Bananas Release Notes
20050207

© 2004-2005 TiVo Inc.

Welcome to Bananas

Bananas is a TiVo-style user interface toolkit built on top of the HME SDK. Bananas makes it easy to create great looking applications that match the TiVo DVR look and feel. You should be familiar with HME before attempting to build applications using Bananas.

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:

screenshot

Getting Started

First, on your PC:
  1. Set the HME_HOME environment variable to point at the HME SDK. For example:

    > export HME_HOME=~/hme_sdk_ea1   (Linux/Mac OS)
    > set HME_HOME=c:\hme_sdk_ea1     (Windows)

  2. Run the Bananas sample:

    > cd sample
    > runsample.sh   (use runsample.bat on Windows)

On your TiVo DVR:
  1. Turn on HME. Navigate to System Information and press the following four keys in order : CLEAR CLEAR 0 0. Ignore the sounds.
  2. Return to TiVo Central. Note that Music and Photos changed to Music, Photos and More.
  3. Enter Music, Photos and More. The sample should be listed.

Packing List

Bananas includes the following files:

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

Backward Compatibility

Bananas is considered experimental and the API will be subject to revision. Backward compatibility is not yet a priority and we may make significant API changes in future releases.

Remember - your feedback will help us revise Bananas.


Tutorial

The following brief tutorial will help you get started with Bananas.

1. BApplication

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:

It is important to place your screens in normal. BApplication performs sliding transitions by carefully positioning the screens inside normal, and then using an animated call to normal.setTranslation to slide the screens around. If you want your application to have a background that's shared across all screens, put it into below.

2. BScreen

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 push or pop with an arg, it will be passed into handleEnter. Also note that the isReturn parameter 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:

When in doubt, always place views into the normal plane. Above and below are primarily used for highlights (see below). Screen backgrounds should go into below.

3. Focus

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 focusDefault view. For example, if your screen only contains a list widget you probably want to call screen.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 until handleFocus returns 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 BFocusMgr for more details.

Note that only focusable views are considered during focus movement. Be sure to call view.setFocusable if you want a view to be eligible for auto focus movement. For example, BButton calls setFocusable(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.

4. Highlights

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:

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.

5. Keys and Actions

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:

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);
  }

6. Widgets

BButton

BButton is a focusable button on screen. It comes with a convenient setBarAndArrows method 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. Override createRow to populate each row. BList comes with a convenient setBarAndArrows method for adding whispering arrows and a bar background to each row.

BText

BText displays some text, possibly with a shadow.

7. Creating Custom Widgets (Advanced)

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 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:

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:
  1. create a new BSkin.Element and give it a size and a rsrc
  2. create a BHighlight and point it at your new skinnable element
  3. 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.

8. Tips