/* * EmbeddedMediaDemo.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.embeddedmediademo; import java.io.IOException; import java.io.InputStream; import javax.microedition.media.MediaException; import javax.microedition.media.Player; import javax.microedition.media.PlayerListener; import javax.microedition.media.control.GUIControl; import javax.microedition.media.control.VideoControl; import javax.microedition.media.control.VolumeControl; import net.rim.device.api.media.control.StreamingBufferControl; import net.rim.device.api.system.Characters; import net.rim.device.api.ui.Field; import net.rim.device.api.ui.FieldChangeListener; 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.LabelField; import net.rim.device.api.ui.component.RichTextField; import net.rim.device.api.ui.container.HorizontalFieldManager; import net.rim.device.api.ui.container.MainScreen; /** * A simple showcase of the javax.microedition.media API's. We are embedding a * media player within a standard UI field and allowing the user to start and * pause the media player and adjust the audio volume. Label fields at the * bottom of the screen indicate current volume level, total playing time of the * media, and elapsed time when media is paused. */ public class EmbeddedMediaDemo 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. new EmbeddedMediaDemo().enterEventDispatcher(); } /** * Creates a new EmbeddedMediaDemo object */ public EmbeddedMediaDemo() { final EmbeddedMediaScreen screen = new EmbeddedMediaScreen(); 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 a media player */ final class EmbeddedMediaScreen extends MainScreen implements FieldChangeListener, PlayerListener { private Player _player; private VolumeControl _volumeControl; private final RichTextField _statusField; private ButtonField _controlButton; private Field _videoField; private HorizontalFieldManager _hfm1; private HorizontalFieldManager _hfm2; private LabelField _currentTime; private LabelField _duration; private LabelField _volumeDisplay; private TimerUpdateThread _timerUpdateThread; /** * Creates a new EmbeddedMediaScreen object */ EmbeddedMediaScreen() { setTitle("Embedded Media Demo"); _statusField = new RichTextField("Loading media, please wait..."); add(_statusField); UiApplication.getUiApplication().invokeLater(new Runnable() { public void run() { initializeMedia(); // If initialization was successful... if (_videoField != null) { createUI(); updateVideoSize(); } else { _statusField.setText("Error: Could not load media"); } } }); } /** * @see net.rim.device.api.ui.FieldChangeListener#fieldChanged(Field, int) */ public void fieldChanged(final Field field, final int context) { final int playerState = _player.getState(); if (playerState == Player.PREFETCHED || playerState == Player.REALIZED) { try { // Start/resume the media player _player.start(); _timerUpdateThread = new TimerUpdateThread(); _timerUpdateThread.start(); } catch (final MediaException pe) { EmbeddedMediaDemo.errorDialog("Player#start() threw " + pe.toString()); } } else if (playerState == Player.STARTED) { try { // Stop/pause the media player _player.stop(); _timerUpdateThread.stop(); } catch (final MediaException pe) { EmbeddedMediaDemo.errorDialog("Player#stop() threw " + pe.toString()); } } } /** * @see net.rim.device.api.ui.Manager#sublayout(int,int) */ protected void sublayout(final int width, final int height) { super.sublayout(width, height); updateVideoSize(); } /** * Initializes UI Components and adds them to the screen */ private void createUI() { delete(_statusField); _hfm1 = new HorizontalFieldManager(Field.FIELD_HCENTER); _controlButton = new ButtonField("Start", ButtonField.NEVER_DIRTY | ButtonField.CONSUME_CLICK); _controlButton.setChangeListener(this); _hfm1.add(_controlButton); _hfm2 = new HorizontalFieldManager(Field.FIELD_HCENTER); _currentTime = new LabelField("-"); _duration = new LabelField("- s"); _volumeDisplay = new LabelField("Volume : " + _volumeControl.getLevel()); _hfm2.add(_currentTime); _hfm2.add(new LabelField(" / ")); _hfm2.add(_duration); _hfm2.add(new LabelField("\t\t")); _hfm2.add(_volumeDisplay); add(_videoField); add(_hfm1); add(_hfm2); } /** * Creates a Player based on a specified URL and provides a VolumeControl * object. */ private void initializeMedia() { try { // For the purpose of this sample we are supplying a URL to a media // file // that is included in the project itself. See the // javax.microedition.media.Manager javadoc for more information on // handling data residing on a server. final InputStream is = getClass().getResourceAsStream("/media/BlackBerry.mp4"); _player = javax.microedition.media.Manager.createPlayer(is, "video/mp4"); _player.addPlayerListener(this); _player.realize(); // Cause playback to begin as soon as possible once start() // is called on the Player. final StreamingBufferControl sbc = (StreamingBufferControl) _player .getControl("net.rim.device.api.media.control.StreamingBufferControl"); sbc.setBufferTime(0); final VideoControl vc = (VideoControl) _player.getControl("VideoControl"); if (vc != null) { _videoField = (Field) vc.initDisplayMode( GUIControl.USE_GUI_PRIMITIVE, "net.rim.device.api.ui.Field"); vc.setVisible(true); } _volumeControl = (VolumeControl) _player.getControl("VolumeControl"); } catch (final MediaException pe) { EmbeddedMediaDemo.errorDialog(pe.toString()); } catch (final IOException ioe) { EmbeddedMediaDemo.errorDialog("Manager.createPlayer() threw " + ioe.toString()); } } /** * Updates the video size according to the current screen dimensions * * @param screenWidth * The screen's width. * @param screenHeight * The screen's height. */ private void updateVideoSize() { if (_player != null) { try { final VideoControl vc = (VideoControl) _player.getControl("VideoControl"); if (vc != null) { final net.rim.device.api.ui.Manager manager = getMainManager(); final int videoHeight = manager.getHeight() - _hfm1.getHeight() - _hfm2.getHeight(); final int videoWidth = manager.getWidth(); vc.setDisplaySize(videoWidth, videoHeight); } } catch (final Exception e) { EmbeddedMediaDemo .errorDialog("VideoControl#setDisplayDize() threw " + e.toString()); } } } /** * @see net.rim.device.api.ui.Screen#keyControl(char,int,int) */ protected boolean keyControl(final char c, final int status, final int time) { // Capture volume control key press and adjust volume accordingly switch (c) { case Characters.CONTROL_VOLUME_DOWN: _volumeControl.setLevel(_volumeControl.getLevel() - 10); return true; case Characters.CONTROL_VOLUME_UP: _volumeControl.setLevel(_volumeControl.getLevel() + 10); return true; } return super.keyControl(c, status, time); } /** * @see javax.microedition.media.PlayerListener#playerUpdate(Player,String,Object) */ public void playerUpdate(final Player player, final String event, final Object eventData) { UiApplication.getUiApplication().invokeLater(new Runnable() { public void run() { if (event.equals(VOLUME_CHANGED)) { _volumeDisplay.setText("Volume : " + _volumeControl.getLevel()); } else if (event.equals(STARTED)) { _currentTime.setText(" "); _controlButton.setLabel("Pause"); } else if (event.equals(STOPPED)) { _controlButton.setLabel("Start"); } else if (event.equals(DURATION_UPDATED)) { _duration.setText(_player.getDuration() / 1000000 + " s"); } else if (event.equals(END_OF_MEDIA)) { _controlButton.setLabel("Start"); _timerUpdateThread.stop(); } } }); } /** * @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) { // Suppress the menu return true; } } return handled; } /** * A thread which acts as a timer to update the screen */ private class TimerUpdateThread extends Thread { private boolean _threadCanRun; /** * @see java.lang.Runnable#run() */ public void run() { _threadCanRun = true; while (_threadCanRun) { UiApplication.getUiApplication().invokeLater(new Runnable() { public void run() { _currentTime.setText(String.valueOf(_player .getMediaTime() / 1000000)); } }); try { Thread.sleep(500L); } catch (final InterruptedException e) { } } } /** * Sets an internal flag such that {@link #run()} will stop as soon as * possible */ public void stop() { _threadCanRun = false; } } }