This chapter describes the key concepts involved in programming with the HME SDK. Major areas of discussion include the following:
- Application life cycle: Every application follows the basic pattern of initializing, painting the screen and handling events, and shutting down.
- Views: The layout of an application is controlled through a view hierarchy that defines what is shown onscreen. Views are the basic building blocks of HME applications and provide containment, a coordinate system, and transparency. A view can contain one resource. Views can contain other views.
- Resources: Resources are elements that are used to draw on the screen or play media. To draw a resource on the screen, you must assign it to a view. Examples of resources are text, images, sounds, fonts, colors, streams, and animations.
- Events: Events contain information about things that happen on the TiVo box. They are generated by the Receiver and sent to the application (or resources within the application) for handling. Events are generated whenever the user presses a key on the remote control. Other types of events contain information about the HME connection itself, about stream processing, about status changes, and about fonts.
- HME hosting environment: The HME SDK includes a sample hosting environment that uses a local PC as the host for the application. Separating the hosting environment from the application environment allows you to implement custom hosting environments—for example, environments that are server-based rather than hosted locally. Use this sample hosting environment for initial development of your application.
Application Life Cycle
All HME applications subclass the Application class, which is the main entry point for interactions with the SDK. The SDK creates a new instance of the application each time a Receiver creates a new connection. The application is responsible for painting the screen, handling events, and controlling media.
Every application is different, but the SDK will follow the same general pattern when managing the application’s life cycle. The methods called on your application will follow the pattern described here:
Initialize
After the Application is created by the Application Factory, its init() method is called. The init() method takes an IContext object and can throw a generic Exception. This exception allows you to check for required conditions and to close down the application if you detect a reason why it will be unable to run properly. If you override init(), be sure to call init() on the super class as well.
The init() method is where you create the user interface for your application (view hierarchy, associated resources, and event handlers, as described in the following section). Here is the complete code for the HelloWorld sample:
package com.tivo.hme.samples.hello; import java.awt.Color; import com.tivo.hme.interfaces.IContext; import com.tivo.hme.sdk.Application; public class HelloWorld extends Application { /** * Create the app. * @throws Exception */ public void init(IContext context) throws Exception { super.init(context); getRoot().setResource(createText ("default-36-bold.font", Color.white, "Hello, world!")); } }Handle Events
Once the application is constructed, the SDK will send it events from the Receiver. See “Events” for a description of events and to learn how events flow through your application.
All events are initially processed by dispatchEvent(), which sends the event to the appropriate object for handling:
Your application can respond to key events easily by overriding one of the key event handlers (there are handlers for key press, key repeat, and key release for each key).
Unhandled events are sent to the parent and will eventually arrive in Application.handleEvent(). For certain kinds of events, handleEvent() will automatically send the event to a helper method.
Nonfatal errors are sent to your application via Application.handleApplicationError(). It could be an error loading a resource or a warning message from the Receiver. The Application.handleActive() method indicates that the application is either becoming active or deactivating on the client.
While the application is responding to an event, it may issue one or more commands. These commands are buffered and, after the event is processed, the accumulated commands are automatically flushed to the Receiver.
Send Commands from Other Threads
In addition to handling events, your application can choose to send commands to the Receiver at any time from other threads. A common example is creating a separate timer thread that updates the screen periodically. When commands are sent from other threads, don’t forget that you have to manually call flush().
Destroy
When the client disconnects, the hosting environment automatically calls the Application.close() method. (This method is final and cannot be overridden.) The close() method in turn does two thinigs:
You can override the destroy() method to free any held resources and terminate any additional threads started by your application. (At this point, the IContext object is still available to your application, so you can save persistent data, perform logging, and so on.) If you create your own threads, use the isApplicationClosing() method in the threads to determine whether the thread should shut down.
After calling destroy(), the close() method finishes shutting down the application. It sets the context to null and removes the application instance from its factory.
Views
One of the Receiver’s primary responsibilities is to paint HME applications onscreen. Views are the basic building blocks of HME applications and provide containment, a coordinate system, and transparency but are invisible unless they contain resources. Resources include visual elements, such as a color, image, or text, that are drawn inside of views. Sounds and animations are other examples of resources. Each view can contain a single resource. View coordinates are given in pixels.
HmeObject
HmeObject is the superclass for both the View and Resource classes, as shown in Figure 2-1. It contains a reference to the application and the object’s HME ID. Many of the methods in HmeObject call into the application to perform the actual work. Note that since Application is a subclass of Resource, all of the HmeObject helpers are also available inside your application class.
Figure 2-1. HmeObject and immediate subclasses
View Hierarchy
The layout of an application is controlled through a view hierarchy that defines what is shown onscreen. Each application contains a special 640x480 root view that is the top of the view hierarchy. Putting a blue color resource into the root view, for example, will turn the whole screen blue. Applications build up the view hierarchy starting at the root in order to lay out the screen.
View paint order is well defined:
HelloWorld’s object hierarchy looks like this:
View: (0,0,640,480)
Resource: Text “Hello, world.”, 0xff000000
A view is totally invisible unless it contains a resource such as a color, image, or text
View Parameters
Table 2-1 lists the methods and parameters for the View class. For further details, see the Javadoc documentation.
Table 2-1 Methods and Parameters for the View class
Removing Views
To remove a view and all its children from the view hierarchy, call View.remove(). To conserve memory, remove unused views.
Painting Efficiently
Normally all changes to the view hierarchy have an immediate effect onscreen. This can cause undesired effects when a large number of changes need to be made, since some of the intermediate states will be visible onscreen.
There are several ways this can be counteracted. First, when creating a new View hierarchy, you can make the top-most view invisible. Once the view hierarchy is created, you can then make the top-most view visible in a single operation.
The SDK uses this technique automatically when calling Application.init(). The root view of an application is always created with visible set to false. This allows the application to create its initial view hierarchy and populate it with resources inside init() before the root view is made visible. This behavior is built into the SDK and requires no action on your part.
When making lots of changes to a view hierarchy, you can turn off painting of a view. This means that the initial state of the view hierarchy will remain visible while the changes are made. The new changes are queued up and are executed when painting is turned on again.
For example, the following code turns off painting, sets up a one-second cross fade, and then shows the results on the screen:
getRoot().setPainting(false); Resource anim = getResource("*1000"); fg.setTransparency(1.0f); fg.setTransparency(0.0f, anim); bg.setTransparency(0.0f); bg.setTransparency(1.0f, anim); getRoot().setPainting(true);Resources
Resources are elements that are used to draw onscreen or play media. To draw a resource on the screen, it must be assigned to a view. The view’s coordinate system will determine how the resource appears onscreen. Note that a resource can be assigned to more than one view. For example, each row in a list widget could contain the same background image resource.
Some resources generate events. For example, when an audio stream is played, the Receiver sends progress events to the HME application. The application can use these events to display a progress bar or automatically advance to the next track.
General Categories
There are three types of assets accessible to HME applications:
- System resources – fonts and sounds that are built into the Receiver. See “System Fonts and Sounds” for more details.
- Application resources – fonts, sounds, and images that are part of the application. See “Custom Factories” in this chapter and “Finding Assets” in Chapter 3 to learn how to package resources with your application.
- Streaming resources – images and audio streams that the Receiver pulls down based on URIs. See “Streams” for more information.
Two Techniques for Creating Resources
There are two different ways for an application to create resources:
- First, there are a series of methods that are specific to each resource type. For example, HmeObject.createColor(java.awt.Color) creates a new color resource. In some cases, these create- methods return specific subclasses of Resource that provide useful behavior. For example, HmeObject.createSound(String) returns a SoundResource that has a play() method (inherited from HmeObject).
- The second method uses the HmeObject.getResource(String) method. This convenient method parses the supplied string to create the appropriate resource. For example, getResource("0xff0000") will create a color resource (red). See Table 2-4 for details on formatting strings for getResource().
Performance Tip for Creating Resources
There is another important difference between these two mechanisms. Resources created with getResource() are cached by the Receiver for later reuse. Calling this method twice with the same string will return the same resource. Prefer getResource() over create- to avoid accidentally sending resources over the network more than once.
Cleaning Up Resources
Applications that use many resources should call remove() on them when they are no longer needed. If you do not call remove(), you may run out of memory in your Application and on the Receiver (see Chapter 3, “Limits”).
Assigning Resources to Views
Resources that draw onscreen, such as colors, images, and text, as well as streaming sounds, must be assigned to views. Resources are assigned to views using the View.setResource() method. The view can also be assigned a set of resource flags that provide additional control over how that resource is painted within the view. Table 2-2 describes the resource flags. Note that some flags are valid only for specific kinds of resources.
Table 2-2 Resource Flags
System Fonts and Sounds
All receivers have a set of system resources for use by developers. Note that system resources cannot be created with create- since they exist implicitly. They are accessed using getResource(). Table 2-3 lists the system resources.
Table 2-3 System Fonts and Sounds
Inlined vs. Streamed Resources
Remember that the Receiver communicates with the application over a single TCP/IP socket using the HME protocol. Created resources can be sent inline through that socket. For example, if an application creates an image resource that is 512kb, no other HME commands can be read by the Receiver until after the entire image resource has been read. This slight delay might become apparent to the end user when HME is running over a wireless network.
For stream resources, the URI string is the only information that is communicated inline, and a separate HTTP request is made by the Receiver to fetch the data referred to by the URI. The HME command stream is not blocked while the resource is loading. For this reason, prefer createStream() over createImage() if you want to load a large number of images without stalling the application.
Types of Resources
This section lists the various types of resources available in the HME SDK. It includes information on the create- method for each resource type. At the end, Table 2-4 summarizes how to specify the strings for each resource type to the getResource() method.
Resources include the following:
Colors
A color resource fills a view with a specific RGB value.
The syntax for createColor() is
For example:
Fonts
Receivers draw text using TrueType fonts. Each Receiver includes two built-in fonts, default.ttf and system.ttf. Applications can also upload custom fonts to the Receiver. Custom font files are located using the methodology described in Chapter 3, “Finding Assets.” A custom font is uploaded to the device as soon as it is created.
A font resource is the combination of a TrueType resource, style information (plain/bold/italic), and a point size.
The createFont() method has the following forms:
public Resource createFont(java.lang.String family, int style, int size) public Resource createFont(java.lang.String family, int style, int size, int flags)The second form of createFont() also includes font metric measurement flags. See Chapter 4 for more information on font metrics.
For example:
createFont("default.ttf", FONT_BOLD, 12) createFont( "default.ttf", FONT_BOLD, 36, FONT_METRICS_BASIC|FONT_METRICS_GLYPH );Text
Text resources display a text string within a view and consist of a Font resource, a Color resource for the foreground, and the text string itself.
The syntax for createText() is:
For example:
createText("default-12.ttf", Color.red, "Hello, world!") createText("default-12.ttf", "0xff0000", "Hello, world!") createText(font, Color.black, "Hello, world!")Images
Image resources are PNG, JPEG or GIF files that are sent to the Receiver for display. Image files can be in the classpath, or can be located using the methodology described in Chapter 3, “Finding Assets.” Also see Chapter 4, “Rendering Constraints,” for information on hardware limits related to image display.
The createImage() method has the following forms:
public ImageResource createImage(java.lang.String name) // creates an image resource. name should be a PNG or JPG // image file. public ImageResource createImage(java.awt.Image image) // creates an image resource from an AWT image public ImageResource createImage(byte[] buf) // creates an image from an entire byte buffer public ImageResource createImage(byte[] buf, int off, int len) // creates an image from a byte buffer containing a // PNG or JPG imageFor example:
The HME SDK supports the dynamic creation of images at runtime using the AWT image framework. A dynamic image will automatically be PNG encoded and sent over the network. For example:
Image img = new BufferedImage(...); Graphics2D g = img.getGraphics(); g.fillRect(10, 10, 20, 20); getRoot().setResource(img);Sounds
A sound resource is a short audio clip, usually only a few seconds long. In addition to the built-in sounds listed in “System Fonts and Sounds,” applications can upload custom sounds. Custom sounds are located using the methodology described in Chapter 3, “Finding Assets.” The sounds must be in 8,000 Hz signed 16-bit little endian mono PCM format.
The syntax for createSound() is:
For example:
A shortcut method in HmeObject makes it easy to play sounds:
Streams
Stream resources are images or audio streams that are asynchronously streamed from the network to the Receiver. The Receiver sends events to the application to communicate stream properties and progress. At most, there are three parameters used to create stream resources:
The createStream() method has the following forms:
public StreamResource createStream(java.lang.String uri) // creates a new stream with the given URI public StreamResource createStream(java.lang.String uri, java.lang.String contentType, boolean play) // creates a new stream; allows you to specify to pause the // stream at first public StreamResource createStream(java.lang.String uristr, java.util.Map args) // (Advanced) creates a new HME application stream resource. // This method is used to embed one application within // another. The arguments will be appended to the uri.
For example:
// create an image stream createStream("http://.../myPicture.png") // create an mp3 stream createStream("http://.../mySong.mp3") // create a paused stream createStream(".../mySong.mp3", null, false)Streams are controlled as follows:
- Set Position – You can specify a play position, in milliseconds, from the start of the stream.
- Set Speed – Streams that are set to speed zero are paused. Speed one will consume data from the stream at a normal rate.
- Close – Close instructs the Receiver to abort playback of a stream. The stream can no longer be used in any way.
See the Music Playback Tech Note for more information on playing music streams.
Animation
Many of the commands used to manipulate views and resources can be animated instead of taking effect instantly. Animation is a good way to hide network latency. The command will be applied over a period of time as described by an animation resource. For example:
An animation resource consists of a duration in milliseconds and an ease in/out value. A negative ease (ease in) will gradually accelerate before achieving a linear speed. A positive ease (ease out) will move linearly and then decelerate. An ease of zero is entirely linear. Experiment with easing to improve the look of your animations.
Type Value Description Ease in -1..0 Acceleration, then linear speed Linear 0 Linear speed Ease out 0..1 Linear speed, then deceleration
For example, to fade in some text, change the transparency of the view from 1 (entirely transparent) to 0 (not transparent) over a period of 1000 milliseconds with an ease of zero. The effect will be that the view fades in gradually over 1 second.
Smooth scrolling is achieved the same way. Rather than setting the translation of a view to its new value immediately, use an animation parameter to set the translation gradually. The result is a smooth scrolling effect until the new translation is achieved.
The SDK provides the following types of animations:
View Animations:
Bounds
Scale
Translate
Transparency
Visible
Remove
Resource Animations:
Event animation
Animation Examples
Here are some examples of different types of animation:
// set bounds linearly 2 seconds view.setBounds(0, 0, 100, 100, "*2000"); // set bounds over 2 seconds, with some deceleration view.setBounds(0, 0, 100, 100, "*2000,.5"); // set bounds over 2 seconds, with full acceleration view.setBounds(0, 0, 100, 100, "*2000,-1");Animation Chaining with Send Event
Sometimes it is desirable to chain several animated commands together so that they occur sequentially. This can be a complicated task because the HME application that issues the commands is separate from the Receiver that obeys them. One approach is to use sleep. Unfortunately, this is unlikely to look good because the HME application and Receiver aren’t synchronized:
view.setBounds(0, 0, 100, 100, "*1000"); // move over 1 second Thread.sleep(1000); // wait for 1 second view.setBounds(0, 0, 500, 500, "*2000"); // now move againA better approach is to send a custom event to the Receiver with an animation. Just as a View.setBounds() can be animated, a Resource.sendEvent() can be animated as well. If both commands are issued at the same time and specify the same animation, the custom event will be sent to the application roughly when the setBounds() is complete. See the SDK samples for more details.
Syntax for the getResource() Method
Table 2-4 lists the format for strings supplied to the getResource() method.
Flushing Pending Commands
Applications communicate with the Receiver using HME protocol commands. Many of the methods in View, Resource, and Application translate directly to a specific protocol command. For efficiency, these commands are buffered by the SDK before being sent over the network.
Under most circumstances, the SDK will automatically flush the buffered commands to the Receiver. For example, the SDK will flush pending commands after the application is finished handling each key event. If an application uses extra threads, it may be necessary to manually flush pending commands by calling HmeObject.flush().
Events
The Receiver generates events and sends them to the application. There are seven types of events:
Key Event
Key events (event type is EVT_KEY) are sent to the application whenever a key is pressed, released, or held down. Each key event contains three parameters: action, code, and raw code, as shown in Table 2-5. Table 2-6 lists the key codes for standard keys, which are found on all TiVo remote controls. Key codes for standard keys begin with KEY_. Table 2-7 lists the key codes for nonstandard keys, which are found only on select TiVo remote controls and therefore are not guaranteed to be generated by the Receiver. Key codes for nonstandard keys begin with KEY_OPT_.
*Keys reserved for internal TiVo use.Table 2-7 Key Codes for Nonstandard Keys on the Remote Control
*Keys reserved for internal TiVo use.ResourceInfo Event
Streaming resources send events (event type is EVT_RSRC_INFO) as the stream is processed. Each event consists of a status code and a map of key/value pairs that contain additional information about the resource. For example, an audio stream might send a ResourceInfo event with RSRC_STATUS_PLAYING and "pos=10000/60000" to indicate that the Receiver has played 10 seconds of the 60 second stream.
Resource Status Event
When the SDK receives a ResourceInfo event that contains a status change, the system automatically generates a Resource Status event (event type is EVT_RSRC_STATUS).Your application can monitor for a Resource Status event as a shortcut to replace handling all ResourceInfo events and unpacking them to see if they contain a status change.
ApplicationInfo Event
The ApplicationInfo event (EVT_APP_INFO) is used to communicate warnings and changes to the active resource. It contains a map of key/value pairs. An application receives this event when it is set active (active=true) or inactive (active=false).
DeviceInfo Event
The Receiver sends a DeviceInfo event (EVT_DEVICE_INFO) immediately after an HME connection is successfully established. It contains a map of key/value pairs that describe the underlying device on which HME is running, including the device’s version and capabilities. Because this event is sent early in the application life cycle, your application can make configuration decisions based on this event.
FontInfo Event
The FontInfo event class (EVT_FONT_INFO) returns two types of information about the requested font:
See Chapter 4, “Programming Techniques,” for an example of processing a FontInfo event.
Idle Event
An Idle event is sent by the Receiver to the application when the user has been inactive for 15 minutes. After this time, the Receiver times out to live TV. The purpose of this event is to prevent burn-in on expensive screens. If you do not want your application to time out, it should send an acknowledgment within 15 seconds of receiving the Idle event by implementing handleIdle() and calling application.acknowledgeIdle(true).
If your application does not time out to live TV, it is a good idea to run your own screen saver in response to an Idle event. This technique will prevent screen burn in on plasma and other expensive televisions.
Event Flow
The Receiver sends events over the network to the application. The Application superclass is responsible for deciding where to post the events inside dispatchEvent().
An application can ask the SDK to deliver keypress events to a specific View. This is called setting the focus. If the focus isn’t set, keypress events will be sent to the application. For example, an application might set the focus to a View subclass that implements a list widget. The list view can handle the arrow keys itself and propagate other keys to its parent.
The default behavior is:
As events propagate through views and resources, each participant can either handle the event itself or ask its parent to handle the event. For example, a view might handle KEY_RIGHT but allow other keys to pass to its parent. Events that are posted to a resource are automatically propagated to the views that contain the resource.
In addition to sending the event to the containing views, each resource also maintains a separate list of handlers. Events that are posted to a resource will be sent to the handlers if the resource doesn’t handle the event. For example, an application can create an image stream without putting it into a view. The application can wait until a ResourceInfo event arrives indicating that the image has been fully loaded before placing the resource in a view.
Send Event
HME includes a facility for sending custom events to a specific resource. The Resource.sendEvent() method handles only key events and can be called only on applications. See “Animation Chaining with Send Event” for an example of how this is useful.
Processing Streams (ResourceInfo Event)
The Receiver will send ResourceInfo events to keep the application informed as the stream is created and processed. Each ResourceInfo event contains a status code and a map of key/value pairs that contain additional information about the stream:
Image Streams
The width and height of the image will be sent along with the RSRC_STATUS_COMPLETE event.
Audio Streams
The current position of the audio stream will be sent along with each RSRC_STATUS_PLAYING event.
Note that it is not possible to reliably determine the duration of an MP3 stream on the receiving end. To work around this difficultly, HME receivers look for an optional X-TiVo-Accurate-Duration MIME header in the HTTP response. When this header is present, the Receiver can include the duration in the RSRC_STATUS_PLAYING event. The SDK contains a sample music player that shows how to calculate the duration of an MP3 and include it in the HTTP response. See the Music Playback Tech Note for more information on how to change the playback speed of MP3 audio files.
Advanced: Active Resource
In HME terms, an application is considered a stream resource and is handled similarly to an audio stream. The application is usually responsible for handling key events, but this is not always the case. Other stream resources are also capable of handling events. For example, an audio stream can handle KEY_PAUSE and KEY_PLAY itself without any intervention from the application.
One resource is always designated as the active resource within the Receiver, and key events will be sent to this resource. If the resource chooses not to handle a particular key, the event will propagate over the network to the application that contains the resource.
On high latency networks, you can set an audio stream to be the active resource. Since the audio stream handles the pause and play keys, the stream is guaranteed to pause and play instantly when the user presses a key even if the application itself is running far away.
Sample HME Hosting Environment
The SDK sample hosting environment is separate from the HME SDK, as shown in Figure 2-2. You can use this out-of-the-box environment during initial development of your application. If you later choose to implement a custom hosting environment—with a server-based host, for example—you can replace the sample hosting environment with your own implementation.
The sample hosting environment performs the following tasks:
- Supports the hosting interface (provided by the Main class in the sample hosting environment)
- Provides a context for the application to run in (see IContext)
- Manages the application life cycle (starts the application, starts the application’s factories)
- Manages all network connections
- Dispatches application connection events to the Application Factory
- Dispatches HTTP requests for assets to the application’s factory
Main Class
The Main class provides the basis for the sample HME hosting environment. To launch an HME application using the sample environment, you must run Main and then tell it which applications to run (see Chapter 1).
The Main class takes the following options:
Figure 2-2. Separation of HME hosting environment from the SDK application objects
Application Factory
The sample host environment handles the connection between the TiVo box and the Application Factory. Based on the URI sent by the TiVo box, the host environment maps the HTTP request to the appropriate Application Factory. The Application Factory then creates an instance of its corresponding application, as shown in Figure 2-2. (An application can change the URI it listens on, as described in Chapter 3, “Application URI.”)
Context
The hosting environment creates an application context, which implements the IContext interface, and passes this object to the application when it is initialized. The application can use this context for logging and storing persistent data, and for communicating with the HME infrastructure.
The following subsections highlight key methods provided by the IContext interface.
Persistent Data
There are two forms of the setPersistentData() method, which allows you to store small amounts of data for use by your application. The simpler form of setPersistentData() allows you to store a key/value pair associated with a particular Receiver and application. It could be used, for example, to store a personal high score for a specific user and a particular game or to store the last song played by a particular user of an MP3 music application. The syntax is
The second form of setPersistentData() allows you to store global data for an application.
void setPersistentData(java.lang.String key, java.lang.String value, java.lang.String applicationId, boolean applicationGlobal)Examples of using global persistent data would be when data is shared by all users of a particular application—perhaps to publish high scores for all players of a certain game. Another use for persistent data is when multiple applications share the same data so that the user doesn’t have to enter it twice (for example, to store the user’s zipcode for use by a suite of related applications). (In this case applicationGlobal would be false.) The Java documentation provides detailed examples of using this method.
In the sample hosting environment, persistent data is stored in a text file on the local computer, so space is limited by the hard drive capacity. It is recommended that you store only small amounts of data, on the order of 5kb or less, so that performance is not affected.
Logging
The getLogger() method returns an instance of ILogger, which the application can use to write messages to a centralized log. In the sample hosting environment, the logger sends its output to stdout.
Identifying a Specific Receiver
The getReceiverGUID() method returns the ID for a specific Receiver. This method is useful for identifying a specific user of the application.
Obtaining Connection Attributes
The getConnectionAttribute(string key) method returns a specific HTTP header.
The getConnectionAttributes() method returns a map of all headers so that you can iterate over the entire set.
Application URL
The getBaseURI() method returns the URL of the application.
Application Assets
The getAssetURI() method returns the location of the assets for the application, such as a collection of images or music.
Custom Factories
Custom factories are used for several purposes:
- Storing data common to all instances of the application – For example, a music player might have a heavyweight database of tracks stored in the factory. Because the database is in the factory, it can be shared across all instances of the application. See Chapter 4 for a discussion of the pictures and music player sample applications.
- Handling command line arguments – The factory is a convenient place to handle command line arguments.
- Handling HTTP requests for assets– Sometimes it is necessary to override the default behavior for fetching assets via HTTP. For example, a music player wouldn’t be very interesting if it could only play music that’s in the classpath. The music player can use a custom factory to serve music off the disk in response to HTTP requests.
Naming a Factory
You can continue to use the generic Factory’s command line facilities even if your application has a custom factory, as long as you honor a specific naming convention. If an application is named App, then its corresponding factory should be a public inner class named AppFactory. Following this convention makes it possible for HME to automatically find the custom factory class, for example:
package com.foo; public class MP3Player extends Application { public static class MP3PlayerFactory extends Factory { … } }getAppFactory() Method
The static Application.getAppFactory() method can be overridden to return an appropriate factory that doesn’t use the naming pattern described above:
static com.tivo.hme.interfaces.IFactory getAppFactory(java.lang.String appClassName, java.lang.ClassLoader loader, com.tivo.hme.interfaces.IArgumentList args)
Be sure to initialize the custom factory by calling the initFactory() method before returning from the getAppFactory() method.