/*******************************************************************************
* Copyright (c) 2011-2012 Nokia Corporation
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Comarch team - initial API and implementation
*******************************************************************************/
package org.ned.client.view;
import com.sun.lwuit.*;
import com.sun.lwuit.events.ActionEvent;
import com.sun.lwuit.events.ActionListener;
import com.sun.lwuit.events.DataChangedListener;
import com.sun.lwuit.layouts.BorderLayout;
import com.sun.lwuit.layouts.BoxLayout;
import java.io.*;
import java.util.Timer;
import java.util.TimerTask;
import javax.microedition.io.Connector;
import javax.microedition.io.HttpConnection;
import javax.microedition.media.*;
import javax.microedition.media.control.FramePositioningControl;
import javax.microedition.media.control.VolumeControl;
import org.ned.client.IContent;
import org.ned.client.NedMidlet;
import org.ned.client.NedResources;
import org.ned.client.command.BackVideoCommand;
public class VideoPlayerView extends NedFormBase implements PlayerListener, ActionListener, Runnable {
private static final int INIT_VOLUME_LEVEL = 100;
private static final Image playIcon = NedMidlet.getRes().getImage( "Play" );
private static final Image pauseIcon = NedMidlet.getRes().getImage( "Pause" );
private static final Image ffIcon = NedMidlet.getRes().getImage( "FF" );
private static final Image rewIcon = NedMidlet.getRes().getImage( "Rew" );
private static final Image fullIcon = NedMidlet.getRes().getImage( "Fullscreen" );
private static final Image exitIcon = NedMidlet.getRes().getImage( "BackIcon" );
private static int currentVolume = -1;
private VolumeControl volume = null;
private MediaComponent mediaComponent;
private Player player;
private FramePositioningControl frame = null;
private String videoFile;
private KeyListetener mKeyListener;
private Container controlUI = null;
private Slider progress = null;
private boolean ignoreEvent = false;
private boolean isPortrait;
private Button rewindButton;
private Button playButton;
private Button fastForwardButton;
private Button fullScreenButton;
private Button backButton;
private UpdateProgessbarTimerTask updateProgressBar;
private static Command playCommand = new Command( "Play" );
private static Command fastForwardCommand = new Command( "FF" );
private static Command rewindCommanf = new Command( "Rew" );
private static Command fullScreenCommand = new Command( "Full" );
private static Command exitPlayerCommand = new Command( "Exit" );
private IContent mContent;
public VideoPlayerView( IContent content ) {
mContent = content;
videoFile = mContent.getMediaFile();
setLayout( new BorderLayout() );
setNedTitle( mContent.getText() );
isPortrait = Display.getInstance().isPortrait();
mKeyListener = new KeyListetener();
addGameKeyListener( Display.GAME_UP, mKeyListener );
addGameKeyListener( Display.GAME_DOWN, mKeyListener );
addGameKeyListener( Display.GAME_FIRE, mKeyListener );
addCommandListener( this );
addPointerReleasedListener( new ActionListener() {
public void actionPerformed( ActionEvent evt ) {
if ( player != null && mediaComponent != null && mediaComponent.
isFullScreen() ) {
showControlPanel();
}
}
} );
initControlUI();
updateProgressBar = new UpdateProgessbarTimerTask();
}
public void prepareToPlay() {
start();
}
private void showControlPanel() {
if ( controlUI != null && contains( controlUI ) ) {
removeComponent( controlUI );
controlUI = null;
}
initControlUI();
mediaComponent.setFullScreen( false );
addComponent( BorderLayout.SOUTH, controlUI );
removeGameKeyListener( Display.GAME_FIRE, mKeyListener );
controlUI.requestFocus();
repaint();
updateProgressBar();
updateProgressBar.startTimer();
}
private synchronized void updateProgressBar() {
if ( player != null ) {
long time = player.getMediaTime();
long duration = player.getDuration();
if ( time != Player.TIME_UNKNOWN && duration != Player.TIME_UNKNOWN
&& duration > 0 ) {
progress.setProgress( (int)(100 * time / duration) );
int seconds = (int)((time / 1000000) % 60);
int minutes = (int)((time / 60000000) % 60);
String secondsStr = (seconds < 10 ? "0" : "") + seconds;
String minutesStr = (minutes < 10 ? "0" : "") + minutes;
progress.setText( minutesStr + ":" + secondsStr );
}
}
}
/**
* Reads the content from the specified HTTP URL and returns InputStream
* where the contents are read.
*
* @return InputStream
* @throws IOException
*/
private InputStream urlToStream( String url ) throws IOException {
// Open connection to the http url...
HttpConnection connection = null;
DataInputStream dataIn = null;
ByteArrayOutputStream byteout = null;
try {
connection = (HttpConnection)Connector.open( url );
dataIn = connection.openDataInputStream();
byte[] buffer = new byte[1000];
int read = -1;
// Read the content from url.
byteout = new ByteArrayOutputStream();
while ( (read = dataIn.read( buffer )) >= 0 ) {
byteout.write( buffer, 0, read );
}
} catch ( IOException ex ) {
if ( dataIn != null ) {
dataIn.close();
}
if ( connection != null ) {
connection.close();
}
throw ex;
}
// Fill InputStream to return with content read from the URL.
ByteArrayInputStream byteIn = new ByteArrayInputStream( byteout.
toByteArray() );
return byteIn;
}
public synchronized void actionPerformed( ActionEvent evt ) {
Object source = evt.getSource();
if ( source == BackVideoCommand.getInstance().getCommand() ) {
BackVideoCommand.getInstance().execute( mContent.getParentId() );
} else if ( source == fastForwardCommand || source == rewindCommanf ) {
if ( frame != null ) {
frame.skip( 25 * (source == fastForwardCommand ? 1 : -1) );//fast forward or rew
updateProgressBar();
} else {
NotSupportedMediaContolAction();
}
} else if ( source == playCommand ) {
pause();
} else if ( source == fullScreenCommand ) {
evt.consume();
removeComponent( controlUI );
ignoreEvent = true;
addGameKeyListener( Display.GAME_FIRE, mKeyListener );
mediaComponent.setFullScreen( true );
repaint();
updateProgressBar.cancelTimer();
} else if ( source == exitPlayerCommand ) {
updateProgressBar.cancelTimer();
BackVideoCommand.getInstance().execute( mContent.getParentId() );
}
}
public void pause() {
if ( player != null ) {
if ( player.getState() == Player.STARTED ) {
try {
long mt = player.getMediaTime();
player.stop();
player.setMediaTime( mt );
} catch ( MediaException ex ) {
ex.printStackTrace();
} catch ( IllegalStateException ex ) {
ex.printStackTrace();
}
} else if ( player.getState() == Player.PREFETCHED ) {
try {
player.start();
} catch ( MediaException ex ) {
start();
} catch ( IllegalStateException isex ) {
start();
}
}
}
}
public void stopPlayer() {
try {
if ( player != null && player.getState() != Player.CLOSED ) {
if ( player.getState() == Player.STARTED ) {
player.stop();
}
if ( player.getState() == Player.PREFETCHED ) {
player.deallocate();
}
if ( player.getState() == Player.REALIZED
|| player.getState() == Player.UNREALIZED ) {
player.close();
}
player = null;
}
} catch ( Exception ex ) {
ex.printStackTrace();
}
}
public void start() {
Thread t = new Thread( this );
t.setPriority( Thread.MIN_PRIORITY );
t.start();
}
public void playerUpdate( final Player p, final String event,
final Object eventData ) {
// queue a call to updateEvent in the user interface event queue
Display display = Display.getInstance();
display.callSerially( new Runnable() {
public void run() {
playerUpdate2( p, event, eventData );
}
} );
}
public synchronized void playerUpdate2( Player p, String event,
Object eventData ) {
if ( p.getState() == Player.CLOSED ) {
return;
}
if ( event.equals( PlayerListener.END_OF_MEDIA ) ) {
playButton.setIcon( playIcon );
playButton.repaint();
showControlPanel();
} else if ( event.equals( PlayerListener.STARTED ) ) {
addGameKeyListener( Display.GAME_FIRE, mKeyListener );
playButton.setIcon( pauseIcon );
playButton.repaint();
} else if ( event.equals( PlayerListener.STOPPED ) ) {
playButton.setIcon( playIcon );
playButton.repaint();
showControlPanel();
}
}
public void run() {
init();
}
void init() {
try {
if ( mediaComponent != null ) {
mediaComponent.setVisible( false );
removeComponent( mediaComponent );
}
boolean fromHttp = videoFile.startsWith( "http://" );
if ( fromHttp ) {
InputStream is = urlToStream( videoFile );
player = Manager.createPlayer( is, "video/3gpp" );
} else {
player = Manager.createPlayer( videoFile );
}
player.realize();
player.prefetch();
mediaComponent = new MediaComponent( player );
mediaComponent.setPreferredH( getContentPane().getHeight() - 3
* Font.getDefaultFont().getHeight() );
mediaComponent.getStyle().setMargin( 0, 0, 0, 0 );
mediaComponent.setFullScreen( true );
mediaComponent.setVisible( true );
addComponent( BorderLayout.CENTER, mediaComponent );
player.addPlayerListener( this );
Control[] cs = player.getControls();
for ( int i = 0; i < cs.length; i++ ) {
if ( cs[i] instanceof VolumeControl ) {
volume = (VolumeControl)cs[i];
volume.setLevel( currentVolume == -1 ? INIT_VOLUME_LEVEL
: currentVolume );
} else if ( cs[i] instanceof FramePositioningControl ) {
frame = (FramePositioningControl)cs[i];
}
}
player.start();
repaint();
progress.setProgress( 0 );
} catch ( IOException ex ) {
ex.printStackTrace();
} catch ( MediaException ex ) {
GeneralAlert.show( NedResources.UNSUPPORTED_MEDIA_FORMAT, GeneralAlert.WARNING );
}
}
private void initControlUI() {
if ( controlUI == null ) {
controlUI = new Container( new BoxLayout( (BoxLayout.Y_AXIS) ) );
Container controlUIButton = new Container( new BoxLayout( (BoxLayout.X_AXIS) ) );
int prefH = Font.getDefaultFont().getHeight();
rewindButton = new Button( rewindCommanf );
rewindButton.setIcon( rewIcon );
rewindButton.setText( "" );
int prefW = (Display.getInstance().getDisplayWidth() - 10
* rewindButton.getStyle().getMargin( Component.LEFT )) / 5;
rewindButton.setPreferredW( prefW );
rewindButton.setPreferredH( 2 * prefH );
playButton = new Button( playCommand );
playButton.setIcon( (player != null && player.getState()
== Player.STARTED) ? pauseIcon : playIcon );
playButton.setText( "" );
playButton.setPreferredW( prefW );
playButton.setPreferredH( 2 * prefH );
fastForwardButton = new Button( fastForwardCommand );
fastForwardButton.setIcon( ffIcon );
fastForwardButton.setText( "" );
fastForwardButton.setPreferredW( prefW );
fastForwardButton.setPreferredH( 2 * prefH );
fullScreenButton = new Button( fullScreenCommand );
fullScreenButton.setIcon( fullIcon );
fullScreenButton.setText( "" );
fullScreenButton.setPreferredW( prefW );
fullScreenButton.setPreferredH( 2 * prefH );
backButton = new Button( exitPlayerCommand );
backButton.setIcon( exitIcon );
backButton.setText( "" );
backButton.setPreferredW( prefW );
backButton.setPreferredH( 2 * prefH );
progress = new Slider();
progress.setThumbImage( pauseIcon.subImage( 7, 0, 8, pauseIcon.
getHeight(), false ) );
progress.setMinValue( 0 );
progress.setMaxValue( 100 );
progress.setFocusable( true );
progress.setIncrements( 1 );
progress.setEditable( true );
progress.setPreferredH( Font.getDefaultFont().getHeight() );
progress.addDataChangedListener( new RewFFVideo() );
controlUIButton.addComponent( rewindButton );
controlUIButton.addComponent( playButton );
controlUIButton.addComponent( fastForwardButton );
controlUIButton.addComponent( fullScreenButton );
controlUIButton.addComponent( backButton );
controlUI.addComponent( progress );
controlUI.addComponent( controlUIButton );
controlUI.setPreferredH( 3 * prefH );
}
}
protected void sizeChanged( int w, int h ) {
boolean isPortraitNow = Display.getInstance().isPortrait();
if ( isPortrait != isPortraitNow ) {
if ( contains( controlUI ) ) {
removeComponent( controlUI );
}
controlUI = null;
initControlUI();
isPortrait = isPortraitNow;
if ( mediaComponent != null ) {
removeComponent( mediaComponent );
if ( isPortraitNow ) {
mediaComponent.setPreferredH( getContentPane().getHeight() - 3
* Font.getDefaultFont().getHeight() );
} else {
mediaComponent.setPreferredH( 100 );
}
addComponent( BorderLayout.CENTER, mediaComponent );
}
addComponent( BorderLayout.SOUTH, controlUI );
controlUI.requestFocus();
repaint();
}
}
private class UpdateProgessbarTimerTask {
private static final long SEC = 1000;
private Timer timer;
private TimerTask task;
public void startTimer() {
cancelTimer();
timer = new Timer();
task = new TimerTask() {
public void run() {
try {
updateProgressBar();
} catch ( Exception ex ) {
}
}
};
timer.schedule( task, SEC, SEC );
}
public void cancelTimer() {
if ( task != null ) {
task.cancel();
task = null;
}
if ( timer != null ) {
timer.cancel();
timer = null;
}
}
protected void finalize() throws Throwable {
cancelTimer();
}
}
private class KeyListetener implements ActionListener {
public void actionPerformed( ActionEvent evt ) {
int keyCode = evt.getKeyEvent();
switch ( keyCode ) {
case Display.GAME_FIRE:
if ( mediaComponent.isFullScreen() && !ignoreEvent ) {
showControlPanel();
} else {
ignoreEvent = false;
}
break;
case Display.GAME_UP:
if ( volume != null ) {
currentVolume = volume.getLevel() + 5;
volume.setLevel( currentVolume );
}
break;
case Display.GAME_DOWN:
if ( volume != null ) {
currentVolume = volume.getLevel() - 5;
volume.setLevel( currentVolume );
}
break;
default:
break;
}
}
}
private void NotSupportedMediaContolAction() {
progress.setRenderPercentageOnTop( false );
progress.setText( NedResources.NOT_SUPPORTED );
Timer timer = new Timer();
timer.schedule( new FadingNotSupportedLabelTask( timer ), 1000 );
}
private class RewFFVideo implements DataChangedListener {
public RewFFVideo() {
}
public synchronized void dataChanged( int i, int i1 ) {
if ( player != null ) {
try {
player.setMediaTime( i1 * player.getDuration() / 100 );
} catch ( MediaException ex ) {
NotSupportedMediaContolAction();
}
updateProgressBar();
} else {
NotSupportedMediaContolAction();
}
}
}
private class FadingNotSupportedLabelTask extends TimerTask {
private Timer mTimer;
public FadingNotSupportedLabelTask( Timer aTimer ) {
mTimer = aTimer;
}
public void run() {
progress.setRenderPercentageOnTop( true );
mTimer.cancel();
}
}
}