/*
* CameraDemo.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.camerademo;
import java.util.Vector;
import javax.microedition.amms.control.camera.ZoomControl;
import javax.microedition.media.Manager;
import javax.microedition.media.Player;
import javax.microedition.media.control.GUIControl;
import javax.microedition.media.control.VideoControl;
import net.rim.device.api.amms.control.camera.EnhancedFocusControl;
import net.rim.device.api.amms.control.camera.FeatureControl;
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.system.Application;
import net.rim.device.api.system.EncodedImage;
import net.rim.device.api.ui.Field;
import net.rim.device.api.ui.MenuItem;
import net.rim.device.api.ui.TouchEvent;
import net.rim.device.api.ui.TouchGesture;
import net.rim.device.api.ui.UiApplication;
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.container.MainScreen;
import net.rim.device.api.ui.input.InputSettings;
import net.rim.device.api.ui.input.NavigationDeviceSettings;
import net.rim.device.api.ui.menu.SubMenu;
import net.rim.device.api.util.StringProvider;
import net.rim.device.api.util.StringUtilities;
/**
* A sample application used to demonstrate the VideoControl.getSnapshot()
* method. This application can take snapshots using the BlackBerry device's
* camera. Swiping the trackpad in a north or south direction will zoom the
* viewfinder in and out.
*/
public final class CameraDemo extends UiApplication {
/**
* Entry point for application
*
* @param args
* Command line arguments (not used)
*/
public static void main(final String[] args) {
// Create a new instance of the application and make the currently
// running thread the application's event dispatch thread.
final CameraDemo demo = new CameraDemo();
demo.enterEventDispatcher();
}
/**
* Creates a new CameraDemo object
*/
public CameraDemo() {
UiApplication.getUiApplication().invokeLater(new Runnable() {
public void run() {
Dialog.alert("Click the trackpad or tap the screen to take a picture."
+ "Zoom in or out by swiping the trackpad up or down. You can change"
+ " the image settings by selecting 'Encoding Settings' from the menu.");
}
});
final CameraScreen screen = new CameraScreen();
pushScreen(screen);
}
/**
* Presents a dialog to the user with a given message
*
* @param message
* The text to display
*/
public static void errorDialog(final String message) {
UiApplication.getUiApplication().invokeLater(new Runnable() {
public void run() {
Dialog.alert(message);
}
});
}
}
/**
* A UI screen to display the camera display and buttons
*/
final class CameraScreen extends MainScreen {
private VideoControl _videoControl;
private Field _videoField;
private EncodingProperties[] _encodings;
private EnhancedFocusControl _efc;
private ZoomControl _zoomControl;
private Player _player;
private MenuItem _turnOffAutoFocusMenuItem;
private MenuItem _turnOnAutoFocusMenuItem;
private int _indexOfEncoding = 0;
/**
* Creates a new CameraScreen object
*/
public CameraScreen() {
// Set the title of the screen
setTitle("Camera Demo");
// Initialize the camera object and video field
initializeCamera();
// Initialize the list of possible encodings
initializeEncodingList();
// If the field was constructed successfully, create the UI
if (_videoField != null) {
// Add the video field to the screen
add(_videoField);
// Initialize the camera features menus
buildFocusModeMenuItems();
buildSceneModeMenuItems();
_turnOffAutoFocusMenuItem =
new MenuItem(new StringProvider("Turn Off Auto-Focus"),
0x230020, 0);
_turnOffAutoFocusMenuItem.setCommand(new Command(
new CommandHandler() {
/**
* @see CommandHandler#execute(ReadOnlyCommandMetadata,
* Object)
*/
public void execute(
final ReadOnlyCommandMetadata metadata,
final Object context) {
try {
if (_efc != null) {
_efc.stopAutoFocus();
} else {
CameraDemo
.errorDialog("ERROR: Focus control not initialized.");
}
} catch (final Exception e) {
CameraDemo.errorDialog("ERROR " + e.getClass()
+ ": " + e.getMessage());
}
}
}));
_turnOnAutoFocusMenuItem =
new MenuItem(new StringProvider("Turn on Auto-Focus"),
0x230020, 0);
_turnOnAutoFocusMenuItem.setCommand(new Command(
new CommandHandler() {
/**
* @see CommandHandler#execute(ReadOnlyCommandMetadata,
* Object)
*/
public void execute(
final ReadOnlyCommandMetadata metadata,
final Object context) {
try {
if (_efc != null) {
_efc.startAutoFocus();
} else {
CameraDemo
.errorDialog("ERROR: Focus control not initialized.");
}
} catch (final Exception e) {
CameraDemo.errorDialog("ERROR " + e.getClass()
+ ": " + e.getMessage());
}
}
}));
final MenuItem encodingMenuItem =
new MenuItem(new StringProvider("Encoding Settings"),
0x230010, 0);
encodingMenuItem.setCommand(new Command(new CommandHandler() {
/**
* @see CommandHandler#execute(ReadOnlyCommandMetadata, Object)
*/
public void execute(final ReadOnlyCommandMetadata metadata,
final Object context) {
final EncodingPropertiesScreen encodingPropertiesScreen =
new EncodingPropertiesScreen(_encodings,
CameraScreen.this, _indexOfEncoding);
UiApplication.getUiApplication().pushModalScreen(
encodingPropertiesScreen);
}
}));
addMenuItem(encodingMenuItem);
// Allow the screen to capture trackpad swipes
final InputSettings settings =
NavigationDeviceSettings.createEmptySet();
settings.set(NavigationDeviceSettings.DETECT_SWIPE, 1);
addInputSettings(settings);
}
// If not, display an error message to the user
else {
add(new RichTextField("Error connecting to camera."));
}
}
/**
* @see net.rim.device.api.ui.Screen#makeMenu(Menu, int)
*/
protected void makeMenu(final Menu menu, final int instance) {
super.makeMenu(menu, instance);
if (_efc.isAutoFocusLocked()) {
menu.add(_turnOffAutoFocusMenuItem);
} else {
menu.add(_turnOnAutoFocusMenuItem);
}
}
/**
* @see net.rim.device.api.ui.Field#touchEvent(TouchEvent)
*/
protected boolean touchEvent(final TouchEvent event) {
if (event.getEvent() == TouchEvent.GESTURE) {
final TouchGesture gesture = event.getGesture();
// Handle only trackpad swipe gestures
if (gesture.getEvent() == TouchGesture.NAVIGATION_SWIPE) {
final int direction = gesture.getSwipeDirection();
Application.getApplication().invokeLater(new Runnable() {
public void run() {
// Determine the direction of the swipe
if (direction == TouchGesture.SWIPE_NORTH) {
_zoomControl.setDigitalZoom(ZoomControl.NEXT);
} else if (direction == TouchGesture.SWIPE_SOUTH) {
_zoomControl.setDigitalZoom(ZoomControl.PREVIOUS);
}
}
});
return true;
}
}
return false;
}
/**
* This method allows an array of menu items to be added to the submenu
* which then gets added to the parent menu.
*
* @param items
* The array of menu items that represents the submenu
* @param menuTitle
* The text string of parent menu item that will contain the
* submenu items
* @param ordering
* Ordering of the submenu relative to other items in the parent
* menu
*/
private void addSubMenu(final Vector items, final String menuTitle,
final int ordering) {
final int size = items.size();
if (size > 0) {
final SubMenu subMenu =
new SubMenu(null, menuTitle, ordering, Integer.MAX_VALUE);
for (int i = size - 1; i >= 0; --i) {
final Object obj = items.elementAt(i);
if (obj instanceof MenuItem) {
subMenu.add((MenuItem) obj);
}
}
addMenuItem(subMenu.getMenuItem());
}
}
/**
* Builds the menu items for the various focus modes supported on the
* device.
*/
private void buildFocusModeMenuItems() {
if (_efc != null) {
// Use a Vector to store each of the focus (sub)menu items
final Vector focusMenuItems = new Vector();
// Check for fixed focus mode support
if (_efc.isFocusModeSupported(EnhancedFocusControl.FOCUS_MODE_FIXED)) {
final MenuItem enableFixedFocus =
new MenuItem(new StringProvider(
"Enable Fixed Auto Focus"), 0x230010, 0);
enableFixedFocus.setCommand(new Command(new CommandHandler() {
/**
* @see CommandHandler#execute(ReadOnlyCommandMetadata,
* Object)
*/
public void execute(final ReadOnlyCommandMetadata metadata,
final Object context) {
final EnhancedFocusControl efc =
(EnhancedFocusControl) _player
.getControl("net.rim.device.api.amms.control.camera.EnhancedFocusControl");
efc.setFocusMode(EnhancedFocusControl.FOCUS_MODE_FIXED);
};
}));
focusMenuItems.addElement(enableFixedFocus);
}
// Check for continuous focus mode support
if (_efc.isFocusModeSupported(EnhancedFocusControl.FOCUS_MODE_CONTINUOUS)) {
final MenuItem enableContinuousAutoFocus =
new MenuItem(new StringProvider(
"Enable Continuous Auto Focus"), 0x230020, 0);
enableContinuousAutoFocus.setCommand(new Command(
new CommandHandler() {
/**
* @see CommandHandler#execute(ReadOnlyCommandMetadata,
* Object)
*/
public void execute(
final ReadOnlyCommandMetadata metadata,
final Object context) {
final EnhancedFocusControl efc =
(EnhancedFocusControl) _player
.getControl("net.rim.device.api.amms.control.camera.EnhancedFocusControl");
efc.setFocusMode(EnhancedFocusControl.FOCUS_MODE_CONTINUOUS);
};
}));
focusMenuItems.addElement(enableContinuousAutoFocus);
}
// Check for single shot focus mode support
if (_efc.isFocusModeSupported(EnhancedFocusControl.FOCUS_MODE_SINGLESHOT)) {
final MenuItem enableSingleShotAutoFocus =
new MenuItem(new StringProvider(
"Enable Single Shot Auto Focus"), 0x230030, 0);
enableSingleShotAutoFocus.setCommand(new Command(
new CommandHandler() {
/**
* @see CommandHandler#execute(ReadOnlyCommandMetadata,
* Object)
*/
public void execute(
final ReadOnlyCommandMetadata metadata,
final Object context) {
final EnhancedFocusControl efc =
(EnhancedFocusControl) _player
.getControl("net.rim.device.api.amms.control.camera.EnhancedFocusControl");
efc.setFocusMode(EnhancedFocusControl.FOCUS_MODE_SINGLESHOT);
};
}));
focusMenuItems.addElement(enableSingleShotAutoFocus);
}
addSubMenu(focusMenuItems, "Auto Focus Modes", 0x230030);
}
}
/**
* Builds the menu items for the various scene modes supported on the device
*/
private void buildSceneModeMenuItems() {
// Feature Control allows for accessing the various scene modes
final FeatureControl featureControl =
(FeatureControl) _player
.getControl("net.rim.device.api.amms.control.camera.FeatureControl");
if (featureControl != null) {
// Use a Vector to store each of the scene mode (sub)menu items
final Vector sceneModeMenuItems = new Vector();
// Check for auto scene mode support
if (featureControl
.isSceneModeSupported(FeatureControl.SCENE_MODE_AUTO)) {
final MenuItem enableSceneModeAuto =
new MenuItem(new StringProvider(
"Enable Scene Mode: AUTO"), Integer.MAX_VALUE,
0);
enableSceneModeAuto.setCommand(new Command(
new CommandHandler() {
/**
* @see CommandHandler#execute(ReadOnlyCommandMetadata,
* Object)
*/
public void execute(
final ReadOnlyCommandMetadata metadata,
final Object context) {
featureControl
.setSceneMode(FeatureControl.SCENE_MODE_AUTO);
};
}));
sceneModeMenuItems.addElement(enableSceneModeAuto);
}
// Check for beach scene mode support
if (featureControl
.isSceneModeSupported(FeatureControl.SCENE_MODE_BEACH)) {
final MenuItem enableSceneModeBeach =
new MenuItem(new StringProvider(
"Enable Scene Mode: BEACH"), Integer.MAX_VALUE,
0);
enableSceneModeBeach.setCommand(new Command(
new CommandHandler() {
/**
* @see CommandHandler#execute(ReadOnlyCommandMetadata,
* Object)
*/
public void execute(
final ReadOnlyCommandMetadata metadata,
final Object context) {
featureControl
.setSceneMode(FeatureControl.SCENE_MODE_BEACH);
};
}));
sceneModeMenuItems.addElement(enableSceneModeBeach);
}
// Check for face detection scene mode support
if (featureControl
.isSceneModeSupported(FeatureControl.SCENE_MODE_FACEDETECTION)) {
final MenuItem enableSceneModeFaceDetection =
new MenuItem(new StringProvider(
"Enable Scene Mode: FACE DETECTION"),
Integer.MAX_VALUE, 0);
enableSceneModeFaceDetection.setCommand(new Command(
new CommandHandler() {
/**
* @see CommandHandler#execute(ReadOnlyCommandMetadata,
* Object)
*/
public void execute(
final ReadOnlyCommandMetadata metadata,
final Object context) {
featureControl
.setSceneMode(FeatureControl.SCENE_MODE_FACEDETECTION);
};
}));
sceneModeMenuItems.addElement(enableSceneModeFaceDetection);
}
// Check for landscape scene mode support
if (featureControl
.isSceneModeSupported(FeatureControl.SCENE_MODE_LANDSCAPE)) {
final MenuItem enableSceneModeLandscape =
new MenuItem(new StringProvider(
"Enable Scene Mode: LANDSCAPE"),
Integer.MAX_VALUE, 0);
enableSceneModeLandscape.setCommand(new Command(
new CommandHandler() {
/**
* @see CommandHandler#execute(ReadOnlyCommandMetadata,
* Object)
*/
public void execute(
final ReadOnlyCommandMetadata metadata,
final Object context) {
featureControl
.setSceneMode(FeatureControl.SCENE_MODE_LANDSCAPE);
};
}));
sceneModeMenuItems.addElement(enableSceneModeLandscape);
}
// Check for macro scene mode support
if (featureControl
.isSceneModeSupported(FeatureControl.SCENE_MODE_MACRO)) {
final MenuItem enableSceneModeMacro =
new MenuItem(new StringProvider(
"Enable Scene Mode: MACRO"), Integer.MAX_VALUE,
0);
enableSceneModeMacro.setCommand(new Command(
new CommandHandler() {
/**
* @see CommandHandler#execute(ReadOnlyCommandMetadata,
* Object)
*/
public void execute(
final ReadOnlyCommandMetadata metadata,
final Object context) {
featureControl
.setSceneMode(FeatureControl.SCENE_MODE_MACRO);
};
}));
sceneModeMenuItems.addElement(enableSceneModeMacro);
}
// Check for night scene mode support
if (featureControl
.isSceneModeSupported(FeatureControl.SCENE_MODE_NIGHT)) {
final MenuItem enableSceneModeNight =
new MenuItem(new StringProvider(
"Enable Scene Mode: NIGHT"), Integer.MAX_VALUE,
0);
enableSceneModeNight.setCommand(new Command(
new CommandHandler() {
/**
* @see CommandHandler#execute(ReadOnlyCommandMetadata,
* Object)
*/
public void execute(
final ReadOnlyCommandMetadata metadata,
final Object context) {
featureControl
.setSceneMode(FeatureControl.SCENE_MODE_NIGHT);
};
}));
sceneModeMenuItems.addElement(enableSceneModeNight);
}
// Check for party scene mode support
if (featureControl
.isSceneModeSupported(FeatureControl.SCENE_MODE_PARTY)) {
final MenuItem enableSceneModeParty =
new MenuItem(new StringProvider(
"Enable Scene Mode: PARTY"), Integer.MAX_VALUE,
0);
enableSceneModeParty.setCommand(new Command(
new CommandHandler() {
/**
* @see CommandHandler#execute(ReadOnlyCommandMetadata,
* Object)
*/
public void execute(
final ReadOnlyCommandMetadata metadata,
final Object context) {
featureControl
.setSceneMode(FeatureControl.SCENE_MODE_PARTY);
};
}));
sceneModeMenuItems.addElement(enableSceneModeParty);
}
// Check for portrait scene mode support
if (featureControl
.isSceneModeSupported(FeatureControl.SCENE_MODE_PORTRAIT)) {
final MenuItem enableSceneModePortrait =
new MenuItem(new StringProvider(
"Enable Scene Mode: PORTRAIT"),
Integer.MAX_VALUE, 0);
enableSceneModePortrait.setCommand(new Command(
new CommandHandler() {
/**
* @see CommandHandler#execute(ReadOnlyCommandMetadata,
* Object)
*/
public void execute(
final ReadOnlyCommandMetadata metadata,
final Object context) {
featureControl
.setSceneMode(FeatureControl.SCENE_MODE_PORTRAIT);
};
}));
sceneModeMenuItems.addElement(enableSceneModePortrait);
}
// Check for snow scene mode support
if (featureControl
.isSceneModeSupported(FeatureControl.SCENE_MODE_SNOW)) {
final MenuItem enableSceneModeSnow =
new MenuItem(new StringProvider(
"Enable Scene Mode: SNOW"), Integer.MAX_VALUE,
0);
enableSceneModeSnow.setCommand(new Command(
new CommandHandler() {
/**
* @see CommandHandler#execute(ReadOnlyCommandMetadata,
* Object)
*/
public void execute(
final ReadOnlyCommandMetadata metadata,
final Object context) {
featureControl
.setSceneMode(FeatureControl.SCENE_MODE_SNOW);
};
}));
sceneModeMenuItems.addElement(enableSceneModeSnow);
}
// Check for sport scene mode support
if (featureControl
.isSceneModeSupported(FeatureControl.SCENE_MODE_SPORT)) {
final MenuItem enableSceneModeSport =
new MenuItem(new StringProvider(
"Enable Scene Mode: SPORT"), Integer.MAX_VALUE,
0);
enableSceneModeSport.setCommand(new Command(
new CommandHandler() {
/**
* @see CommandHandler#execute(ReadOnlyCommandMetadata,
* Object)
*/
public void execute(
final ReadOnlyCommandMetadata metadata,
final Object context) {
featureControl
.setSceneMode(FeatureControl.SCENE_MODE_SPORT);
};
}));
sceneModeMenuItems.addElement(enableSceneModeSport);
}
// Check for text scene mode support
if (featureControl
.isSceneModeSupported(FeatureControl.SCENE_MODE_TEXT)) {
final MenuItem enableSceneModeText =
new MenuItem(new StringProvider(
"Enable Scene Mode: TEXT"), Integer.MAX_VALUE,
0);
enableSceneModeText.setCommand(new Command(
new CommandHandler() {
/**
* @see CommandHandler#execute(ReadOnlyCommandMetadata,
* Object)
*/
public void execute(
final ReadOnlyCommandMetadata metadata,
final Object context) {
featureControl
.setSceneMode(FeatureControl.SCENE_MODE_TEXT);
};
}));
sceneModeMenuItems.addElement(enableSceneModeText);
}
addSubMenu(sceneModeMenuItems, "Scene Modes", 0x230040);
}
}
/**
* Takes a picture with the selected encoding settings
*/
private void takePicture() {
try {
// A null encoding indicates that the camera should
// use the default snapshot encoding.
String encoding = null;
if (_encodings != null && _encodings.length > 0) {
// Use the user-selected encoding
encoding = _encodings[_indexOfEncoding].getFullEncoding();
}
// Retrieve the raw image from the VideoControl and
// create a screen to display the image to the user.
createImageScreen(_videoControl.getSnapshot(encoding));
} catch (final Exception e) {
CameraDemo.errorDialog("ERROR " + e.getClass() + ": "
+ e.getMessage());
}
}
/**
* @see net.rim.device.api.ui.container.MainScreen#onSavePrompt()
*/
protected boolean onSavePrompt() {
// Prevent the save dialog from being displayed
return true;
}
/**
* @see net.rim.device.api.ui.Screen#close()
*/
public void close() {
if (_player != null) {
try {
_player.close();
} catch (final Exception e) {
}
}
super.close();
}
/**
* Initializes the Player, VideoControl and VideoField
*/
private void initializeCamera() {
try {
// Create a player for the Blackberry's camera
_player = Manager.createPlayer("capture://video");
// Set the player to the REALIZED state (see Player javadoc)
_player.realize();
// Get the video control
_videoControl = (VideoControl) _player.getControl("VideoControl");
if (_videoControl != null) {
// Create the video field as a GUI primitive (as opposed to a
// direct video, which can only be used on platforms with
// LCDUI support.)
_videoField =
(Field) _videoControl.initDisplayMode(
GUIControl.USE_GUI_PRIMITIVE,
"net.rim.device.api.ui.Field");
_videoControl.setDisplayFullScreen(true);
_videoControl.setVisible(true);
}
// Set the player to the STARTED state (see Player javadoc)
_player.start();
// Enable auto-focus for the camera
_efc =
(EnhancedFocusControl) _player
.getControl("net.rim.device.api.amms.control.camera.EnhancedFocusControl");
// Enable zoom for the camera
_zoomControl =
(ZoomControl) _player
.getControl("javax.microedition.amms.control.camera.ZoomControl");
} catch (final Exception e) {
CameraDemo.errorDialog("ERROR " + e.getClass() + ": "
+ e.getMessage());
}
}
/**
* Initialize the list of encodings
*/
private void initializeEncodingList() {
try {
// Retrieve the list of valid encodings
final String encodingString =
System.getProperty("video.snapshot.encodings");
// Extract the properties as an array of word
final String[] properties =
StringUtilities.stringToKeywords(encodingString);
// The list of encodings
final Vector encodingList = new Vector();
// Strings representing the three properties of an encoding as
// returned by System.getProperty().
final String encoding = "encoding";
final String width = "width";
final String height = "height";
EncodingProperties temp = null;
for (int i = 0; i < properties.length; ++i) {
if (properties[i].equals(encoding)) {
if (temp != null && temp.isComplete()) {
// Add a new encoding to the list if it
// has been properly set.
encodingList.addElement(temp);
}
temp = new EncodingProperties();
// Set the new encoding's format
++i;
temp.setFormat(properties[i]);
} else if (properties[i].equals(width)) {
// Set the new encoding's width
++i;
temp.setWidth(properties[i]);
} else if (properties[i].equals(height)) {
// Set the new encoding's height
++i;
temp.setHeight(properties[i]);
}
}
// If there is a leftover complete encoding, add it
if (temp != null && temp.isComplete()) {
encodingList.addElement(temp);
}
// Convert the Vector to an array for later use
_encodings = new EncodingProperties[encodingList.size()];
encodingList.copyInto(_encodings);
} catch (final Exception e) {
// Something is wrong, indicate that there are no encoding options
_encodings = null;
CameraDemo.errorDialog(e.toString());
}
}
/**
* Create a screen used to display a snapshot
*
* @param raw
* A byte array representing an image
*/
private void createImageScreen(final byte[] raw) {
// Create image to be displayed
final EncodedImage encodedImage =
EncodedImage.createEncodedImage(raw, 0, raw.length);
// Initialize the screen
final ImageScreen imageScreen = new ImageScreen(raw, encodedImage);
// Push screen to display it to the user
UiApplication.getUiApplication().pushScreen(imageScreen);
}
/**
* Sets the index of the encoding in the 'encodingList' Vector
*
* @param index
* The index of the encoding in the 'encodingList' Vector
*/
public void setIndexOfEncoding(final int index) {
_indexOfEncoding = index;
}
/**
* @see net.rim.device.api.ui.Screen#invokeAction(int)
*/
protected boolean invokeAction(final int action) {
final boolean handled = super.invokeAction(action);
if (!handled) {
if (action == ACTION_INVOKE) {
takePicture();
return true;
}
}
return handled;
}
}