summaryrefslogtreecommitdiffstats
path: root/src/com/android/gallery3d/app/MoviePlayer.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/com/android/gallery3d/app/MoviePlayer.java')
-rw-r--r--src/com/android/gallery3d/app/MoviePlayer.java525
1 files changed, 0 insertions, 525 deletions
diff --git a/src/com/android/gallery3d/app/MoviePlayer.java b/src/com/android/gallery3d/app/MoviePlayer.java
deleted file mode 100644
index ce9183483..000000000
--- a/src/com/android/gallery3d/app/MoviePlayer.java
+++ /dev/null
@@ -1,525 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * 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.
- */
-
-package com.android.gallery3d.app;
-
-import android.annotation.TargetApi;
-import android.app.AlertDialog;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.DialogInterface.OnCancelListener;
-import android.content.DialogInterface.OnClickListener;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.media.AudioManager;
-import android.media.MediaPlayer;
-import android.net.Uri;
-import android.os.Build;
-import android.os.Bundle;
-import android.os.Handler;
-import android.view.KeyEvent;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.VideoView;
-
-import com.android.gallery3d.R;
-import com.android.gallery3d.common.ApiHelper;
-import com.android.gallery3d.common.BlobCache;
-import com.android.gallery3d.util.CacheManager;
-import com.android.gallery3d.util.GalleryUtils;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.DataInputStream;
-import java.io.DataOutputStream;
-
-public class MoviePlayer implements
- MediaPlayer.OnErrorListener, MediaPlayer.OnCompletionListener,
- ControllerOverlay.Listener {
- @SuppressWarnings("unused")
- private static final String TAG = "MoviePlayer";
-
- private static final String KEY_VIDEO_POSITION = "video-position";
- private static final String KEY_RESUMEABLE_TIME = "resumeable-timeout";
-
- // These are constants in KeyEvent, appearing on API level 11.
- private static final int KEYCODE_MEDIA_PLAY = 126;
- private static final int KEYCODE_MEDIA_PAUSE = 127;
-
- // Copied from MediaPlaybackService in the Music Player app.
- private static final String SERVICECMD = "com.android.music.musicservicecommand";
- private static final String CMDNAME = "command";
- private static final String CMDPAUSE = "pause";
-
- private static final long BLACK_TIMEOUT = 500;
-
- // If we resume the acitivty with in RESUMEABLE_TIMEOUT, we will keep playing.
- // Otherwise, we pause the player.
- private static final long RESUMEABLE_TIMEOUT = 3 * 60 * 1000; // 3 mins
-
- private Context mContext;
- private final VideoView mVideoView;
- private final View mRootView;
- private final Bookmarker mBookmarker;
- private final Uri mUri;
- private final Handler mHandler = new Handler();
- private final AudioBecomingNoisyReceiver mAudioBecomingNoisyReceiver;
- private final MovieControllerOverlay mController;
-
- private long mResumeableTime = Long.MAX_VALUE;
- private int mVideoPosition = 0;
- private boolean mHasPaused = false;
- private int mLastSystemUiVis = 0;
-
- // If the time bar is being dragged.
- private boolean mDragging;
-
- // If the time bar is visible.
- private boolean mShowing;
-
- private final Runnable mPlayingChecker = new Runnable() {
- @Override
- public void run() {
- if (mVideoView.isPlaying()) {
- mController.showPlaying();
- } else {
- mHandler.postDelayed(mPlayingChecker, 250);
- }
- }
- };
-
- private final Runnable mProgressChecker = new Runnable() {
- @Override
- public void run() {
- int pos = setProgress();
- mHandler.postDelayed(mProgressChecker, 1000 - (pos % 1000));
- }
- };
-
- public MoviePlayer(View rootView, final MovieActivity movieActivity,
- Uri videoUri, Bundle savedInstance, boolean canReplay) {
- mContext = movieActivity.getApplicationContext();
- mRootView = rootView;
- mVideoView = (VideoView) rootView.findViewById(R.id.surface_view);
- mBookmarker = new Bookmarker(movieActivity);
- mUri = videoUri;
-
- mController = new MovieControllerOverlay(mContext);
- ((ViewGroup)rootView).addView(mController.getView());
- mController.setListener(this);
- mController.setCanReplay(canReplay);
-
- mVideoView.setOnErrorListener(this);
- mVideoView.setOnCompletionListener(this);
- mVideoView.setVideoURI(mUri);
- mVideoView.setOnTouchListener(new View.OnTouchListener() {
- @Override
- public boolean onTouch(View v, MotionEvent event) {
- mController.show();
- return true;
- }
- });
- mVideoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
- @Override
- public void onPrepared(MediaPlayer player) {
- if (!mVideoView.canSeekForward() || !mVideoView.canSeekBackward()) {
- mController.setSeekable(false);
- } else {
- mController.setSeekable(true);
- }
- setProgress();
- }
- });
-
- // The SurfaceView is transparent before drawing the first frame.
- // This makes the UI flashing when open a video. (black -> old screen
- // -> video) However, we have no way to know the timing of the first
- // frame. So, we hide the VideoView for a while to make sure the
- // video has been drawn on it.
- mVideoView.postDelayed(new Runnable() {
- @Override
- public void run() {
- mVideoView.setVisibility(View.VISIBLE);
- }
- }, BLACK_TIMEOUT);
-
- setOnSystemUiVisibilityChangeListener();
- // Hide system UI by default
- showSystemUi(false);
-
- mAudioBecomingNoisyReceiver = new AudioBecomingNoisyReceiver();
- mAudioBecomingNoisyReceiver.register();
-
- Intent i = new Intent(SERVICECMD);
- i.putExtra(CMDNAME, CMDPAUSE);
- movieActivity.sendBroadcast(i);
-
- if (savedInstance != null) { // this is a resumed activity
- mVideoPosition = savedInstance.getInt(KEY_VIDEO_POSITION, 0);
- mResumeableTime = savedInstance.getLong(KEY_RESUMEABLE_TIME, Long.MAX_VALUE);
- mVideoView.start();
- mVideoView.suspend();
- mHasPaused = true;
- } else {
- final Integer bookmark = mBookmarker.getBookmark(mUri);
- if (bookmark != null) {
- showResumeDialog(movieActivity, bookmark);
- } else {
- startVideo();
- }
- }
- }
-
- @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
- private void setOnSystemUiVisibilityChangeListener() {
- if (!ApiHelper.HAS_VIEW_SYSTEM_UI_FLAG_HIDE_NAVIGATION) return;
-
- // When the user touches the screen or uses some hard key, the framework
- // will change system ui visibility from invisible to visible. We show
- // the media control and enable system UI (e.g. ActionBar) to be visible at this point
- mVideoView.setOnSystemUiVisibilityChangeListener(
- new View.OnSystemUiVisibilityChangeListener() {
- @Override
- public void onSystemUiVisibilityChange(int visibility) {
- int diff = mLastSystemUiVis ^ visibility;
- mLastSystemUiVis = visibility;
- if ((diff & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) != 0
- && (visibility & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0) {
- mController.show();
- }
- }
- });
- }
-
- @SuppressWarnings("deprecation")
- @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
- private void showSystemUi(boolean visible) {
- if (!ApiHelper.HAS_VIEW_SYSTEM_UI_FLAG_LAYOUT_STABLE) return;
-
- int flag = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
- | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
- | View.SYSTEM_UI_FLAG_LAYOUT_STABLE;
- if (!visible) {
- // We used the deprecated "STATUS_BAR_HIDDEN" for unbundling
- flag |= View.STATUS_BAR_HIDDEN | View.SYSTEM_UI_FLAG_FULLSCREEN
- | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
- }
- mVideoView.setSystemUiVisibility(flag);
- }
-
- public void onSaveInstanceState(Bundle outState) {
- outState.putInt(KEY_VIDEO_POSITION, mVideoPosition);
- outState.putLong(KEY_RESUMEABLE_TIME, mResumeableTime);
- }
-
- private void showResumeDialog(Context context, final int bookmark) {
- AlertDialog.Builder builder = new AlertDialog.Builder(context);
- builder.setTitle(R.string.resume_playing_title);
- builder.setMessage(String.format(
- context.getString(R.string.resume_playing_message),
- GalleryUtils.formatDuration(context, bookmark / 1000)));
- builder.setOnCancelListener(new OnCancelListener() {
- @Override
- public void onCancel(DialogInterface dialog) {
- onCompletion();
- }
- });
- builder.setPositiveButton(
- R.string.resume_playing_resume, new OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- mVideoView.seekTo(bookmark);
- startVideo();
- }
- });
- builder.setNegativeButton(
- R.string.resume_playing_restart, new OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- startVideo();
- }
- });
- builder.show();
- }
-
- public void onPause() {
- mHasPaused = true;
- mHandler.removeCallbacksAndMessages(null);
- mVideoPosition = mVideoView.getCurrentPosition();
- mBookmarker.setBookmark(mUri, mVideoPosition, mVideoView.getDuration());
- mVideoView.suspend();
- mResumeableTime = System.currentTimeMillis() + RESUMEABLE_TIMEOUT;
- }
-
- public void onResume() {
- if (mHasPaused) {
- mVideoView.seekTo(mVideoPosition);
- mVideoView.resume();
-
- // If we have slept for too long, pause the play
- if (System.currentTimeMillis() > mResumeableTime) {
- pauseVideo();
- }
- }
- mHandler.post(mProgressChecker);
- }
-
- public void onDestroy() {
- mVideoView.stopPlayback();
- mAudioBecomingNoisyReceiver.unregister();
- }
-
- // This updates the time bar display (if necessary). It is called every
- // second by mProgressChecker and also from places where the time bar needs
- // to be updated immediately.
- private int setProgress() {
- if (mDragging || !mShowing) {
- return 0;
- }
- int position = mVideoView.getCurrentPosition();
- int duration = mVideoView.getDuration();
- mController.setTimes(position, duration, 0, 0);
- return position;
- }
-
- private void startVideo() {
- // For streams that we expect to be slow to start up, show a
- // progress spinner until playback starts.
- String scheme = mUri.getScheme();
- if ("http".equalsIgnoreCase(scheme) || "rtsp".equalsIgnoreCase(scheme)) {
- mController.showLoading();
- mHandler.removeCallbacks(mPlayingChecker);
- mHandler.postDelayed(mPlayingChecker, 250);
- } else {
- mController.showPlaying();
- mController.hide();
- }
-
- mVideoView.start();
- setProgress();
- }
-
- private void playVideo() {
- mVideoView.start();
- mController.showPlaying();
- setProgress();
- }
-
- private void pauseVideo() {
- mVideoView.pause();
- mController.showPaused();
- }
-
- // Below are notifications from VideoView
- @Override
- public boolean onError(MediaPlayer player, int arg1, int arg2) {
- mHandler.removeCallbacksAndMessages(null);
- // VideoView will show an error dialog if we return false, so no need
- // to show more message.
- mController.showErrorMessage("");
- return false;
- }
-
- @Override
- public void onCompletion(MediaPlayer mp) {
- mController.showEnded();
- onCompletion();
- }
-
- public void onCompletion() {
- }
-
- // Below are notifications from ControllerOverlay
- @Override
- public void onPlayPause() {
- if (mVideoView.isPlaying()) {
- pauseVideo();
- } else {
- playVideo();
- }
- }
-
- @Override
- public void onSeekStart() {
- mDragging = true;
- }
-
- @Override
- public void onSeekMove(int time) {
- mVideoView.seekTo(time);
- }
-
- @Override
- public void onSeekEnd(int time, int start, int end) {
- mDragging = false;
- mVideoView.seekTo(time);
- setProgress();
- }
-
- @Override
- public void onShown() {
- mShowing = true;
- setProgress();
- showSystemUi(true);
- }
-
- @Override
- public void onHidden() {
- mShowing = false;
- showSystemUi(false);
- }
-
- @Override
- public void onReplay() {
- startVideo();
- }
-
- // Below are key events passed from MovieActivity.
- public boolean onKeyDown(int keyCode, KeyEvent event) {
-
- // Some headsets will fire off 7-10 events on a single click
- if (event.getRepeatCount() > 0) {
- return isMediaKey(keyCode);
- }
-
- switch (keyCode) {
- case KeyEvent.KEYCODE_HEADSETHOOK:
- case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
- if (mVideoView.isPlaying()) {
- pauseVideo();
- } else {
- playVideo();
- }
- return true;
- case KEYCODE_MEDIA_PAUSE:
- if (mVideoView.isPlaying()) {
- pauseVideo();
- }
- return true;
- case KEYCODE_MEDIA_PLAY:
- if (!mVideoView.isPlaying()) {
- playVideo();
- }
- return true;
- case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
- case KeyEvent.KEYCODE_MEDIA_NEXT:
- // TODO: Handle next / previous accordingly, for now we're
- // just consuming the events.
- return true;
- }
- return false;
- }
-
- public boolean onKeyUp(int keyCode, KeyEvent event) {
- return isMediaKey(keyCode);
- }
-
- private static boolean isMediaKey(int keyCode) {
- return keyCode == KeyEvent.KEYCODE_HEADSETHOOK
- || keyCode == KeyEvent.KEYCODE_MEDIA_PREVIOUS
- || keyCode == KeyEvent.KEYCODE_MEDIA_NEXT
- || keyCode == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE
- || keyCode == KeyEvent.KEYCODE_MEDIA_PLAY
- || keyCode == KeyEvent.KEYCODE_MEDIA_PAUSE;
- }
-
- // We want to pause when the headset is unplugged.
- private class AudioBecomingNoisyReceiver extends BroadcastReceiver {
-
- public void register() {
- mContext.registerReceiver(this,
- new IntentFilter(AudioManager.ACTION_AUDIO_BECOMING_NOISY));
- }
-
- public void unregister() {
- mContext.unregisterReceiver(this);
- }
-
- @Override
- public void onReceive(Context context, Intent intent) {
- if (mVideoView.isPlaying()) pauseVideo();
- }
- }
-}
-
-class Bookmarker {
- private static final String TAG = "Bookmarker";
-
- private static final String BOOKMARK_CACHE_FILE = "bookmark";
- private static final int BOOKMARK_CACHE_MAX_ENTRIES = 100;
- private static final int BOOKMARK_CACHE_MAX_BYTES = 10 * 1024;
- private static final int BOOKMARK_CACHE_VERSION = 1;
-
- private static final int HALF_MINUTE = 30 * 1000;
- private static final int TWO_MINUTES = 4 * HALF_MINUTE;
-
- private final Context mContext;
-
- public Bookmarker(Context context) {
- mContext = context;
- }
-
- public void setBookmark(Uri uri, int bookmark, int duration) {
- try {
- BlobCache cache = CacheManager.getCache(mContext,
- BOOKMARK_CACHE_FILE, BOOKMARK_CACHE_MAX_ENTRIES,
- BOOKMARK_CACHE_MAX_BYTES, BOOKMARK_CACHE_VERSION);
-
- ByteArrayOutputStream bos = new ByteArrayOutputStream();
- DataOutputStream dos = new DataOutputStream(bos);
- dos.writeUTF(uri.toString());
- dos.writeInt(bookmark);
- dos.writeInt(duration);
- dos.flush();
- cache.insert(uri.hashCode(), bos.toByteArray());
- } catch (Throwable t) {
- Log.w(TAG, "setBookmark failed", t);
- }
- }
-
- public Integer getBookmark(Uri uri) {
- try {
- BlobCache cache = CacheManager.getCache(mContext,
- BOOKMARK_CACHE_FILE, BOOKMARK_CACHE_MAX_ENTRIES,
- BOOKMARK_CACHE_MAX_BYTES, BOOKMARK_CACHE_VERSION);
-
- byte[] data = cache.lookup(uri.hashCode());
- if (data == null) return null;
-
- DataInputStream dis = new DataInputStream(
- new ByteArrayInputStream(data));
-
- String uriString = DataInputStream.readUTF(dis);
- int bookmark = dis.readInt();
- int duration = dis.readInt();
-
- if (!uriString.equals(uri.toString())) {
- return null;
- }
-
- if ((bookmark < HALF_MINUTE) || (duration < TWO_MINUTES)
- || (bookmark > (duration - HALF_MINUTE))) {
- return null;
- }
- return Integer.valueOf(bookmark);
- } catch (Throwable t) {
- Log.w(TAG, "getBookmark failed", t);
- }
- return null;
- }
-}