Bananas is released under the Common Public License (CPL).
The HME home page is hosted on sourceforge, http://tivohme.sourceforge.net, and contains news, updates, related downloads and support resources. Please do not call TiVo customer service as they will be unable to help you with HME or Bananas.
Here is a sample screenshot:
> export HME_HOME=~/hme_sdk_ea1 (Linux/Mac OS) > set HME_HOME=c:\hme_sdk_ea1 (Windows) |
> cd sample > runsample.sh (use runsample.bat on Windows) |
README.html - this file
LICENSE-CPL.html - Common Public License
src.zip - Bananas source
bananas.jar - Bananas class files
doc/
bananas-javadoc.zip - zipped javadoc for bananas
sample/
runsample.* - scripts for running the sample
sample.jar - class files for the sample
com/tivo/hme/samples/... - source for the sample
Remember - your feedback will help us revise Bananas.
All Bananas applications begin by subclassing BApplication.Screen Stack
BApplication contains a stack of BScreens (see below), each of which is the same size as the application. You will construct your interface by creating screens and pushing them onto the stack. Whenever a screen is pushed onto the stack you can specify an animated transition effect. For example:
// Push a new screen onto the stack, sliding from right to left. push(new MyScreen(), TRANSITION_LEFT); ... // Pop back to the previous screen. This will reverse the push // transition, sliding from left to right. pop();Planes
BApplication actually contains three planes that are used to organize your interface:
- above - contains views that appear "above" all screens
- normal - contains screens
- below - contains views that appear "below" all screens, such as a background image
It is important to place your screens in
normal. BApplication performs sliding transitions by carefully positioning the screens insidenormal, and then using an animated call tonormal.setTranslationto slide the screens around. If you want your application to have a background that's shared across all screens, put it into below.
Each BScreen is a screenful of information, and an application can contain many such screens.Screen Events
The application contains a stack of screens. The topmost screen on the stack is the only screen that is visible. Whenever an element is pushed onto the stack or the stack is popped, the old screen is hidden and a new screen is shown.
In the world of Bananas we say that the screen being hidden is exited and the screen being shown is entered. BApplication uses callbacks to let your screen know when is is entered or exited. Use these callbacks to reset your screen to its default state, and also to start/stop any helper threads that are associated with the screen. For example:
class MyScreen extends BScreen implements Runnable { Thread thread; ... // start the thread when we are entered public boolean handleEnter(Object arg, boolean isReturn) { thread = new Thread(this); thread.start(); return super.handleEnter(arg, isReturn); } // stop the thread when we are exited public boolean handleExit() { thread.stop(); return super.handleExit(); } }If the user called
pushorpopwith anarg, it will be passed intohandleEnter. Also note that theisReturnparameter can be used to figure out whether your screen was just pushed or whether it's being entered because of a pop. This mechanism can be used to create screens which accept arguments and return results.Above, Normal and Below
Just like BApplication, each individual screen contains three planes that are used to organize your views:
- above - contains views that are "above" widgets
- normal - contains widgets
- below - contains views that appear "below" widgets, such as a background image.
When in doubt, always place views into the
normalplane.Aboveandbeloware primarily used for highlights (see below). Screen backgrounds should go intobelow.
Key events are always routed to the current screen's focused view. This section discusses how the focus moves within each screen.Default Focus
Whenever a screen is pushed, it sets the focus to the
focusDefaultview. For example, if your screen only contains a list widget you probably want to callscreen.setFocusDefault(list)to ensure that the list will have focus when your screen is pushed.When a new screen is pushed on the stack, the old screen's focus is not modified. When the covering screen is popped the old screen will have the same focus as before. This provides continuity for the user.
Changing Focus
It is possible to change the screen's focus at any time using
screen.setFocus(). Whenever the focus changes, events are sent to the views that are losing and gaining focus. These events propagate up the parent hierarchy like other HME events untilhandleFocusreturns true.Focus Movement
The TiVo DVR user interface let's the user navigate within and between screens using the arrow keys on the remote control. Bananas facilitates this behavior.
BScreen contains default behavior for handling
"left","right","up"and"down"actions. When the screen handles these actions it will attempt to automatically move the focus in the desired direction. See Whispering Arrows and Keys and Actions to learn about actions and how they are generated.The exact movement algorithm is somewhat complicated. Imagine that a ray is cast from the center of the focused view. The algorithm will favor the views that are closest to this ray, not views that are closest to the current focus. See
BFocusMgrfor more details.Note that only focusable views are considered during focus movement. Be sure to call
view.setFocusableif you want a view to be eligible for auto focus movement. For example, BButton callssetFocusable(true)in its constructor so that buttons are always candidates for focus. In contrast, BText is not focusable by default. BList itself is not focusable but contains rows that are focusable.
Highlights are the arrows, colored bars, and other visual hints that appear on screen above and below the actual widgets. These cues provide context and help the user to anticipate what will occur when they press keys on the remote. Bananas contains a low-level framework for managing these highlights, and individual widgets sometimes contain helper methods that facilitate their creation.
Some highlights are associated with the focus. For example, in a list widget the arrows and bar indicate that a specific row has focus, and when the focus moves the highlights move too.
Layout
Highlights are drawn either above or below the view being highlighted. They are associated with the underlying view, but are not direct children. This makes it possible to place highlights outside the highlighted view.
Highlights are laid out by assigning them a position. This position is always relative to the view being highlighted, even though the highlight is not a child of the view. For example, a highlight at 0,0 will always draw in the upper left corner of the highlighted view. A highlight at -100,0 will draw to the left of the highlighted view.
There are three different ways to add highlights to a view. In order of complexity:
widget-specific - Some widgets contain helpers for adding highlights. These helpers take care of all the hard work of laying out highlights. For example, see
BList.setBarAndArrows. This is the easiest way to add highlights:
// give the list a bar and some arrows list.setBarAndArrows(BAR_DEFAULT, BAR_DEFAULT, "left", "right");highlight-specific - BHighlights contains helpers for adding some highlights. These helpers take care of some of the work of laying out highlights. For example, see
BHighlights.setWhisperingArrow. This provides ultimate flexibility, but can be much more complicated than using the existing helpers.
// add left arrow to a view. place it in the left/top corner. BHighlights h = view.getHighlights(); h.setWhisperingArrow("left", A_LEFT, A_TOP, "left");custom - To use custom highlights, it is necessary to manually create a BHighlight instance. You will have to handle the grunt work of laying out the highlight. This is both flexible and complicated.
Actions
Whispering arrow highlights are assigned an action. This action will be fired automatically when the highlighted view has focus and the user hits the corresponding key. For example, in the snippet below the "newpage" action will be fired whenever the user hits the right key and the target view has focus:
// fire newpage action when the user hits right BHighlights h = view.getHighlights(); h.setWhisperingArrow("right", 20, 20, "newpage");Actions are used to automatically moving the focus between views. See Focus Movement for more details. To add a highlight arrow that automatically moves the focus, simply specify
"left","right","up"or"down"as the action.See Keys and Actions for more information.
Whispering Arrows
Whispering arrow highlights indicate to the user which arrow keys are available for use. The whispering arrows for each view are only visible when that view has focus. Whispering arrows are always drawn above the view being highlighted.Bars
A bar highlight usually indicates that a view has focus. Bars are always drawn below the view being highlighted. Bars are always the same height, but can be stretched to any width.Page Hints
Page up/down hint highlights are used to indicate whether there is more information on the previous or next screen, and imply that the user can hit channel up/down to scroll the page. The page hints are always drawn above the highlighted view.
Like all HME applications, the user interacts with Bananas applications by pressing keys on the remote control.Events
BApplications sends key events to the focused view on the current screen. From there, the key event will propagate up through the parent hierarchy like other HME events until the handle method returns true.
An action is another kind of event that works in a similar manner. Actions are generated by Bananas or your application, usually in response to a keypress. Actions propagate like other HME events and are handled by overriding
handleAction(). For example:
public boolean handleAction(BView view, Object action) { if (action.equals("myscreen")) { push(new MyScreen()); return true; } return super.handleAction(view, action); }Sounds
Bananas will attempt to play the appropriate sound whenever certain keys are pressed. BApplication follows a simple set of rules after dispatching a key event:
Did someone play a sound? If so, be silent. Note that in order for BApplication to detect that you played a sound, you must call
BApplication.play()directly.Did the focus change or did we change screens? If so, play a sound according to the following table:
Key Sound LEFT updown (focus) / pageup (screen) RIGHT updown (focus) / pagedown (screen) UP/DOWN updown SELECT select THUMBSUP/DOWN thumbsup/down CHANNELUP/DOWN pageup/down - If none of the above occurred, play bonk.
Whispering Arrow Actions
Whispering arrows usually contain an action. When the user presses an arrow key on a view that contains a whispering arrow highlight, that action will be fired automatically. For example:
BHighlights h = view.getHighlights(); // left arrow should fire "pop" action, right arrow should // move focus to the right h.setWhisperingArrow("left", A_LEFT - 10, A_CENTER, "pop"); h.setWhisperingArrow("right", A_RIGHT + 10, A_CENTER, "right");Firing Actions
Actions can be fired manually by calling postEvent, just like any other HME event:
public boolean handleKeyPress(int code, long rawcode) { switch (code) { case KEY_INFO: postEvent(new BEvent.Action(this, "info")); return true; } return super.handleKeyPress(code, rawcode); }
BButton
BButton is a focusable button on screen. It comes with a convenientsetBarAndArrowsmethod for adding whispering arrows and a bar background. Add children to BButton to give it something to display.BList
BList contains a set of rows, each of which is the same size and gets populated in the same manner. OverridecreateRowto populate each row. BList comes with a convenientsetBarAndArrowsmethod for adding whispering arrows and a bar background to each row.BText
BText displays some text, possibly with a shadow.
Bananas comes with some widgets, but advanced users may wish to create their own.Highlight Visibility
Highlight visibility depends on the visibility of the highlighted view. There are three different options:
- H_VIS_FOCUS - the highlight is visible when the view has focus.
- H_VIS_TRUE - the highlight is visible.
- H_VIS_FALSE - the highlight is not visible.
H_VIS_FOCUS is used for whispering arrows, which should always be visible when the highlighted view has focus. H_VIS_TRUE/H_VIS_FALSE are used for page up/down hints, which are toggled on and off depending on the state of the list.
Modifying Highlights
A BHighlight instance is essentially a recipe for drawing a highlight on screen. The highlight must be refreshed at certain times in order to rebuild the highlight based on the state of the underlying view. This is rarely necessary, since most widgets take care of refreshing their own highlights. For example, whenever the focus moves the highlights will automatically be refreshed for both affected views.
Here are some occasions where it may be necessary to manually call refresh on BHighlights:
- when the highlighted view is moved, made (in)visible, or has its transparency changed
- when a parent view is moved, translated, made (in)visible, or has its transparency changed
- when the highlight itself is moved or has a visibility change
Custom Highlights
Bananas comes with all the highlights necessary to create applications that match the TiVo DVR look and feel. You may want to create your own highlights to give your application a different look. To create your own highlights:
- create a new BSkin.Element and give it a size and a rsrc
- create a BHighlight and point it at your new skinnable element
- add the BHighlight to a BHighlights
Animation and IHighlightsLayout
Some highlights are shared between views, which makes it possible to animate the highlights as the focus moves. For example, the row highlights in BList slide between rows when the user hits up and down.
Each BHighlights requires an IHighlightsLayout instance that describes how to position the highlights. The highlights will move to the new position whenever
refresh()is called. If refresh is called with an animation, the highlights will slide instead of moving instantly. See the Bananas sample for an example of animated highlights.
- Bananas applications don't contain any support for scaling.