/** * HomeScreenDemo.java * * Copyright � 1998-2011 Research In Motion Limited * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Note: For the sake of simplicity, this sample application may not leverage * resource bundles and resource strings. However, it is STRONGLY recommended * that application developers make use of the localization features available * within the BlackBerry development platform to ensure a seamless application * experience across a variety of languages and geographies. For more information * on localizing your application, please refer to the BlackBerry Java Development * Environment Development Guide associated with this release. */ package com.rim.samples.device.homescreendemo; import java.io.IOException; import java.util.Enumeration; import java.util.Vector; import javax.microedition.io.Connector; import javax.microedition.io.file.FileConnection; import javax.microedition.io.file.FileSystemRegistry; import net.rim.blackberry.api.homescreen.HomeScreen; import net.rim.blackberry.api.invoke.CameraArguments; import net.rim.blackberry.api.invoke.Invoke; import net.rim.device.api.command.Command; import net.rim.device.api.command.CommandHandler; import net.rim.device.api.command.ReadOnlyCommandMetadata; import net.rim.device.api.io.file.FileSystemJournal; import net.rim.device.api.io.file.FileSystemJournalEntry; import net.rim.device.api.io.file.FileSystemJournalListener; import net.rim.device.api.system.Bitmap; import net.rim.device.api.system.Characters; import net.rim.device.api.system.DeviceInfo; import net.rim.device.api.system.EventInjector; import net.rim.device.api.system.PersistentObject; import net.rim.device.api.system.PersistentStore; import net.rim.device.api.ui.Field; import net.rim.device.api.ui.Manager; import net.rim.device.api.ui.MenuItem; import net.rim.device.api.ui.UiApplication; import net.rim.device.api.ui.component.ButtonField; import net.rim.device.api.ui.component.Dialog; import net.rim.device.api.ui.component.Menu; import net.rim.device.api.ui.component.RichTextField; import net.rim.device.api.ui.component.table.SimpleList; import net.rim.device.api.ui.container.MainScreen; import net.rim.device.api.ui.container.VerticalFieldManager; import net.rim.device.api.util.StringProvider; /** * Using the File Connection API, this application searches the root file * systems on the BlackBerry Smartphone device for "pictures" folder(s) and then * displays a list of the directories found. Clicking on a list item will * display a list of the pictures within that directory. Invoking the * "Set as Home Screen Image" menu item for a picture will set the selected * picture as the background image for the home screen. * * This demo also allows the user to invoke the camera application to take a * picture, which can then be set as the background image for the home screen. * * The application also allows for the creation of a shortcut on the home screen * leading directly to the picture selection screen * (HomeScreenDemoSecondaryScreen). This is done by specifying an alternate * entry point, defined in the HomeScreenAlternateEntryPoint project. */ class HomeScreenDemo extends UiApplication { // com.rim.samples.device.homescreendemo.HomeScreenDemo = // 0x23d84fce8b031333L static final long HOMESCREEN_DEMO_ID = 0x23d84fce8b031333L; // Contains the URLs of the "pictures" folders private Vector _pictureDirectoryURLs; // Contains the names of the pictures within a specific "pictures" folders private Vector _pictureFileNames; private static PersistentObject _store; /** * Entry point for application * * @param args * Command line arguments (not used) */ public static void main(final String[] args) { _store = PersistentStore.getPersistentObject(HOMESCREEN_DEMO_ID); synchronized (_store) { // If the PersistentObject is empty, initialize it if (_store.getContents() == null) { _store.setContents(""); PersistentObject.commit(_store); } } boolean shortcut = false; // Check if the application was launched from the shortcut for (int i = 0; i < args.length; i++) { if (args[i].equals("shortcut")) { shortcut = true; } } // Create a new instance of the application and make the currently // running thread the application's event dispatch thread. new HomeScreenDemo(shortcut).enterEventDispatcher(); } /** * Create a new HomeScreenDemo object * * @param shortcut * True if the application was launched from the shortcut, false * otherwise */ private HomeScreenDemo(final boolean shortcut) { if (shortcut) { // If the application was launched from the shortcut, go directly to // list screen displayDirectoryPictures((String) _store.getContents()); } else { final HSDemoScreen screen = new HSDemoScreen(); pushScreen(screen); addFileSystemJournalListener(screen); // To detect when a camera // image is added to a file // system } } /** * When called by initPictureDirectories(), this method will look for * "pictures" folder(s) in <code>root</code> and save URL(s) in * _pictureDirectoryURLs vector. When called by displayDirectoryPicstures(), * the method will update the _pictureFileNames vector with the names of the * pictures within a "pictures" folder (passed as the String * <code>root</code>). * * @param root * Directory to be searched for the pictures * @param pictureSearch * If false, search for "pictures" folder, if true then search * for pictures within folder. */ private void readDirectory(final String root, final boolean isPictureFolder) { FileConnection fc = null; try { fc = (FileConnection) Connector.open("file:///" + root, Connector.READ); if (fc.isDirectory()) { final Enumeration e = fc.list(); while (e.hasMoreElements()) { final String inner = (String) e.nextElement(); if (isPictureFolder) { _pictureFileNames.addElement(inner); } else if (inner.indexOf("pictures") != -1) { final String URL = root + inner; _pictureDirectoryURLs.addElement(URL); return; } else { // Couldn't find "pictures" folder in root directory, // go one level deeper. final String URL = root + inner; readDirectory(URL, false); } } } } catch (final IOException ioe) { invokeLater(new Runnable() { /** * @see Runnable#run() */ public void run() { Dialog.alert("Connector.open() threw " + ioe.toString()); } }); } } /** * Launch a screen where the user can select from a list of pictures in a * given directory. * * @param picDirectoryURL * The directory to display */ private void displayDirectoryPictures(final String pictureDirectoryURL) { // (Re)populate the vector of images in the directory if (_pictureFileNames == null) { _pictureFileNames = new Vector(); } else { _pictureFileNames.removeAllElements(); } // Search the directory for pictures. This updates the _pictureFileURLs // vector. readDirectory(pictureDirectoryURL, true); if (_pictureFileNames.size() > 0) { // Launch the picture selection screen pushScreen(new HomeScreenDemoSecondaryScreen(pictureDirectoryURL, _pictureFileNames)); } else { Dialog.alert("No pictures found"); } } /** * Main screen for the application */ class HSDemoScreen extends MainScreen implements FileSystemJournalListener { private final SimpleList _list; private ButtonField _invokeButtonField; private long _lastUSN; private boolean _displayDialog; /** * Create a new HSDemoScreen object */ public HSDemoScreen() { super(Manager.NO_VERTICAL_SCROLL); setTitle("Home Screen Demo"); _pictureDirectoryURLs = new Vector(); _pictureFileNames = new Vector(); // Populate _picDirectoryURLs with a list of directories // that store pictures. initPictureDirectories(); add(new RichTextField( "Click on a pictures directory to display a list of the pictures it contains.\n", Field.NON_FOCUSABLE)); final DemoVerticalFieldManager vfm = new DemoVerticalFieldManager(Manager.NO_VERTICAL_SCROLL); add(vfm); _list = new SimpleList(vfm); for (int i = 0; i < _pictureDirectoryURLs.size(); i++) { _list.add((String) _pictureDirectoryURLs.elementAt(i)); } // Set the list to display when a list item is activated _list.setCommand(new Command(new CommandHandler() { /** * @see CommandHandler#execute(ReadOnlyCommandMetadata, Object) */ public void execute(final ReadOnlyCommandMetadata metadata, final Object context) { displayDirectoryPictures(_list.get(_list.getFocusRow())); } })); if (DeviceInfo.hasCamera()) { add(new RichTextField("\n...or invoke the camera application", Field.NON_FOCUSABLE)); _invokeButtonField = new ButtonField("Invoke Camera App", ButtonField.CONSUME_CLICK | Field.FIELD_HCENTER) { /** * @see net.rim.device.api.ui.component.ButtonField#fieldChangeNotify(int) */ protected void fieldChangeNotify(final int context) { Invoke.invokeApplication( Invoke.APP_TYPE_CAMERA, new CameraArguments()); super.fieldChangeNotify(context); } }; add(_invokeButtonField); } } /** * Looks for all folders containing the substring 'pictures' */ private void initPictureDirectories() { final Enumeration rootEnum = FileSystemRegistry.listRoots(); while (rootEnum.hasMoreElements()) { final String root = (String) rootEnum.nextElement(); readDirectory(root, false); } } /** * Invoked when a picture is taken by the Camera app * * @see net.rim.device.api.io.file.FileSystemJournalListener#fileJournalChanged() */ public void fileJournalChanged() { final long nextUSN = FileSystemJournal.getNextUSN(); String cameraImagePath = null; for (long lookUSN = nextUSN - 1; lookUSN >= _lastUSN && cameraImagePath == null; lookUSN--) { final FileSystemJournalEntry entry = FileSystemJournal.getEntry(lookUSN); if (entry == null) { // We didn't find an entry break; } if (entry.getEvent() == FileSystemJournalEntry.FILE_ADDED) { cameraImagePath = entry.getPath(); if (cameraImagePath != null && (cameraImagePath.endsWith("png") || cameraImagePath.endsWith("jpg") || cameraImagePath.endsWith("bmp") || cameraImagePath .endsWith("gif"))) { _displayDialog = true; break; } } } // _lastUSN must be updated before pushing a modal screen onto the // display stack _lastUSN = nextUSN; if (_displayDialog) { // Close the Camera application to return to Home Screen Demo final EventInjector.KeyEvent event = new EventInjector.KeyEvent( EventInjector.KeyEvent.KEY_DOWN, Characters.ESCAPE, 0); event.post(); event.post(); _displayDialog = false; final int choice = Dialog.ask(Dialog.D_YES_NO, "Set as Background?", Dialog.YES); if (choice == Dialog.YES) { HomeScreen.setBackgroundImage(cameraImagePath); } } } /** * @see net.rim.device.api.ui.container.MainScreen#makeMenu(Menu,int) */ protected void makeMenu(final Menu menu, final int instance) { if (HomeScreen.supportsIcons()) { final MenuItem setIconItem = new MenuItem( new StringProvider("Set Home Screen Icon"), 0x230010, 0); setIconItem.setCommand(new Command(new CommandHandler() { /** * @see net.rim.device.api.command.CommandHandler#execute(ReadOnlyCommandMetadata, * Object) */ public void execute(final ReadOnlyCommandMetadata metadata, final Object context) { final Bitmap bitmap = Bitmap.getBitmapResource("img/logo_blue.jpg"); HomeScreen.updateIcon(bitmap); } })); menu.add(setIconItem); final MenuItem setRolloverItem = new MenuItem(new StringProvider("Set Rollover Icon"), 0x230020, 1); setRolloverItem.setCommand(new Command(new CommandHandler() { /** * @see net.rim.device.api.command.CommandHandler#execute(ReadOnlyCommandMetadata, * Object) */ public void execute(final ReadOnlyCommandMetadata metadata, final Object context) { final Bitmap bitmap = Bitmap.getBitmapResource("img/logo_black.jpg"); HomeScreen.setRolloverIcon(bitmap); } })); menu.add(setRolloverItem); } super.makeMenu(menu, instance); } /** * @see net.rim.device.api.ui.container.MainScreen#onSavePrompt() */ public boolean onSavePrompt() { // Supress the save dialog return true; } /** * A VerticalFieldManager which performs an action on an Enter key press */ private final class DemoVerticalFieldManager extends VerticalFieldManager { /** * Creates a new DemoVerticalFieldManager object * * @param style * Style bit for this manager */ DemoVerticalFieldManager(final long style) { super(style); } /** * @see net.rim.device.api.ui.Manager#keyChar(char, int, int) */ protected boolean keyChar(final char c, final int status, final int time) { if (c == Characters.ENTER) { displayDirectoryPictures(_list.get(_list.getFocusRow())); return true; } return super.keyChar(c, status, time); } } } }