ClickAider

Sample Blackberry Browser Plugin with XML Scripting

The Blackberry API is powerful but also incompletely documented; I've had to uncover many parts of it by searching multiple sources and through trial and error.

The sample code in this post illustrates several features of the Blackberry API used in the Berry411 application. The BrowserContentProvider interface allows an application like Berry411 to register itself as a handler for a custom mime-type "text/xml-berry411". Berry411 uses the SAX parser interface to parse and interpret scripting commands in the document returned from the server-- in effect this allows Berry411 to define its own custom scripting language allowing web pages to interact with the address book and other features of the Blackberry.

The BrowserContentProvider also allows an application to define its own rendering for pages that take advantage of all of the Blackberry UI widgets, rather than relying upon the browser for rendering.

Finally, the sample code illustrates a "launchOrRaiseApp" method which will ensure that the application with the given module name (e.g. "net_rim_bb_addressbook_app") is running and in the foreground. If the application is already running, it will be foregrounded, otherwise it will be launched.

JAVA:
  1. import net.rim.device.api.xml.parsers.*;
  2. import org.xml.sax.*;
  3. import org.xml.sax.helpers.*;
  4. import net.rim.blackberry.api.browser.*;
  5. import net.rim.device.api.browser.field.*;
  6. import net.rim.device.api.browser.plugin.*;
  7. import net.rim.blackberry.api.invoke.*;
  8. public final class BrowserPlugin extends BrowserContentProvider
  9.      implements BrowserPageContext
  10. {
  11.   private static final String[] ACCEPT = {"text/xml-example"};
  12.   /**
  13.   * Retrieves list of mime types this provider can accept given a set of rendering options.
  14.   * @param context Rendering options in place this provider should consider.
  15.   * @return Array of mime types this provider will accept, given the provided rendering options.
  16.   */
  17.   public String[] getAccept(RenderingOptions context) {
  18.     // Return subset of getSupportedMimeTypes() if accept depends in rendering options.
  19.     // For example HTML can be disabled in the rendering options, and HTMLConverter would remove
  20.     // html MIME types.
  21.     return ACCEPT;
  22.   }
  23.   /**
  24.   * Retrieves all the mime content types supported by this provider.
  25.   * @return Mime types this converter supports.
  26.   */
  27.   public String[] getSupportedMimeTypes() {
  28.     return ACCEPT;
  29.   }
  30.   class BerryHandler extends DefaultHandler
  31.   {
  32.     private String _actionSummary = "";
  33.     private Contact _currentContact = null;
  34.     private BrowserContentBaseImpl _browserContent;
  35.     public BerryHandler(BrowserContentBaseImpl impl)
  36.     {
  37.       _browserContent = impl;
  38.     }
  39.     public void startElement(String uri, String name, String qName, Attributes attrs)
  40.     {
  41.     // SAX Parser implementation omitted
  42.     }
  43.     public String getActionSummary()
  44.     {
  45.       return _actionSummary;
  46.     }
  47.   }
  48.   /**
  49.   * Retrieves a browser content capable of rendering the mime content this provider can handle.
  50.   * @param context Provider context object provided by rendering session.
  51.   * @return Browser content to render specialized content.
  52.   */
  53.   public BrowserContent getBrowserContent( BrowserContentProviderContext context)
  54.        throws RenderingException
  55.   {
  56.     if (context == null) {
  57.       throw new RenderingException("No Context is passed into Provider");
  58.     }
  59.     BrowserContentBaseImpl browserContentBaseImpl = new BrowserContentBaseImpl(context.getHttpConnection().getURL(),
  60.         null, context.getRenderingApplication(),
  61.         context.getRenderingSession().getRenderingOptions(), context.getFlags());
  62.     VerticalFieldManager vfm = new VerticalFieldManager(Manager.VERTICAL_SCROLL);
  63.     vfm.add(new LabelField("Processed Example action"));
  64.     try {
  65.       HttpConnection conn = context.getHttpConnection();
  66.       InputStream in = conn.openInputStream();
  67.       SAXParserFactory factory = SAXParserFactory.newInstance();
  68.       SAXParser parser = factory.newSAXParser();
  69.       parser.setAllowUndefinedNamespaces(true);
  70.       BerryHandler handler = new BerryHandler(browserContentBaseImpl);
  71.       parser.parse(in, handler);
  72.       vfm.add(new LabelField(handler.getActionSummary()));
  73.     }
  74.     catch (IOException e) {
  75.       e.printStackTrace();
  76.     }
  77.     catch (Exception e) {
  78.       vfm.add(new EditField("Error:", e.toString()));
  79.     }
  80.     browserContentBaseImpl.setContent(vfm);
  81.     browserContentBaseImpl.setTitle("Example");
  82.     // Set browser page context. This tells the browser how to display this field.
  83.     browserContentBaseImpl.setBrowserPageContext(this);
  84.     return browserContentBaseImpl;
  85.   }
  86.   /**
  87.   * Retrieves value of specified property as a boolean value.
  88.   * @param id ID of property to query.
  89.   * @param defaultValue Expected default value of property.
  90.   * @return Current value of property.
  91.   */
  92.   public boolean getPropertyWithBooleanValue(int id, boolean defaultValue) {
  93.     return false;
  94.   }
  95.   /**
  96.   * Retrieves value of specified property as an int.
  97.   * @param id ID of property to query.
  98.   * @param defaultValue Expected default value of property.
  99.   * @return Current value of property.
  100.   */
  101.   public int getPropertyWithIntValue(int id, int defaultValue) {
  102.     if (id == BrowserPageContext.DISPLAY_STYLE) {
  103.       // Disable the scroll bar.
  104.       return BrowserPageContext.STYLE_NO_VERTICAL_SCROLLBAR;
  105.     }
  106.     return 0;
  107.   }
  108.   /**
  109.   * Retrieves value of specified property as an object.
  110.   * @param id ID of property to query.
  111.   * @param defaultValue Expected default value of property.
  112.   * @return Current value of property.
  113.   */
  114.   public Object getPropertyWithObjectValue(int id, Object defaultValue) {
  115.     return null;
  116.   }
  117.   /* Retrieves value of specified property as a String value.
  118.   * @param id - ID of property to query.
  119.   * @param defaultValue - Expected default value of property.
  120.   * @return Current value of property.
  121.   */
  122.   public String getPropertyWithStringValue(int id, String defaultValue) {
  123.     return null;
  124.   }
  125.   // -----------------------------------------------------
  126.   // static helper functions for use from BrowserPlugin
  127.   public static boolean raiseApp(String desiredModule)
  128.   {
  129.     ApplicationManager appMgr = ApplicationManager.getApplicationManager();
  130.     ApplicationDescriptor[] apps = appMgr.getVisibleApplications();
  131.     for (int i=0; i <apps.length; i++) {
  132.     ApplicationDescriptor app = apps[i];
  133.     if (app.getModuleName().equals(desiredModule)) {
  134.       try {
  135.         appMgr.runApplication(app, true);
  136.         return true;
  137.       }
  138.       catch(ApplicationManagerException e) {
  139.       }
  140.     }
  141.    }
  142.    return false;
  143.   }
  144.   public static boolean launchOrRaiseApp(String desiredModule)
  145.   {
  146.     if (!raiseApp(desiredModule)) {
  147.     int handle = CodeModuleManager.getModuleHandle(desiredModule);
  148.     if (handle <= 0 ) {
  149.       return false;
  150.     } else {
  151.       ApplicationDescriptor[] appDescriptors = CodeModuleManager.getApplicationDescriptors(handle);
  152.       if (appDescriptors == null ) {
  153.         return false;
  154.       }
  155.       else {
  156.         if ( appDescriptors.length <=0 ) {
  157.           return false;
  158.         } else {
  159.           ApplicationDescriptor descriptor = new ApplicationDescriptor(
  160.               appDescriptors[0],
  161.               desiredModule, null,
  162.               null, -1, null, -1,
  163.               0
  164.             );
  165.           try {
  166.             ApplicationManager.getApplicationManager().runApplication(descriptor);
  167.           }
  168.           catch(ApplicationManagerException e) {
  169.             return false;
  170.           }
  171.         }
  172.       }
  173.     }
  174.   }
  175.   return true;
  176.   }
  177. }