diff options
Diffstat (limited to 'src/com/android/gallery3d/app/MoviePlayer.java')
-rw-r--r-- | src/com/android/gallery3d/app/MoviePlayer.java | 291 |
1 files changed, 291 insertions, 0 deletions
diff --git a/src/com/android/gallery3d/app/MoviePlayer.java b/src/com/android/gallery3d/app/MoviePlayer.java new file mode 100644 index 000000000..423994485 --- /dev/null +++ b/src/com/android/gallery3d/app/MoviePlayer.java @@ -0,0 +1,291 @@ +/* + * 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 com.android.gallery3d.R; +import com.android.gallery3d.common.BlobCache; +import com.android.gallery3d.util.CacheManager; +import com.android.gallery3d.util.GalleryUtils; + +import android.app.ActionBar; +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.Handler; +import android.view.KeyEvent; +import android.view.View; +import android.widget.MediaController; +import android.widget.VideoView; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; + +public class MoviePlayer implements + MediaPlayer.OnErrorListener, MediaPlayer.OnCompletionListener { + @SuppressWarnings("unused") + private static final String TAG = "MoviePlayer"; + + // 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 Context mContext; + private final VideoView mVideoView; + private final View mProgressView; + private final Bookmarker mBookmarker; + private final Uri mUri; + private final Handler mHandler = new Handler(); + private final AudioBecomingNoisyReceiver mAudioBecomingNoisyReceiver; + private final ActionBar mActionBar; + + private boolean mHasPaused; + + private final Runnable mPlayingChecker = new Runnable() { + public void run() { + if (mVideoView.isPlaying()) { + mProgressView.setVisibility(View.GONE); + } else { + mHandler.postDelayed(mPlayingChecker, 250); + } + } + }; + + public MoviePlayer(View rootView, final MovieActivity movieActivity, Uri videoUri) { + mContext = movieActivity.getApplicationContext(); + mVideoView = (VideoView) rootView.findViewById(R.id.surface_view); + mProgressView = rootView.findViewById(R.id.progress_indicator); + mBookmarker = new Bookmarker(movieActivity); + mActionBar = movieActivity.getActionBar(); + mUri = videoUri; + + // 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)) { + mHandler.postDelayed(mPlayingChecker, 250); + } else { + mProgressView.setVisibility(View.GONE); + } + + mVideoView.setOnErrorListener(this); + mVideoView.setOnCompletionListener(this); + mVideoView.setVideoURI(mUri); + + MediaController mediaController = new MediaController(movieActivity) { + @Override + public void show() { + super.show(); + mActionBar.show(); + } + + @Override + public void hide() { + super.hide(); + mActionBar.hide(); + } + }; + mVideoView.setMediaController(mediaController); + mediaController.setOnKeyListener(new View.OnKeyListener() { + public boolean onKey(View v, int keyCode, KeyEvent event) { + if (keyCode == KeyEvent.KEYCODE_BACK) { + if (event.getAction() == KeyEvent.ACTION_UP) { + movieActivity.onBackPressed(); + } + return true; + } + return false; + } + }); + + mAudioBecomingNoisyReceiver = new AudioBecomingNoisyReceiver(); + mAudioBecomingNoisyReceiver.register(); + + // make the video view handle keys for seeking and pausing + mVideoView.requestFocus(); + + Intent i = new Intent(SERVICECMD); + i.putExtra(CMDNAME, CMDPAUSE); + movieActivity.sendBroadcast(i); + + final Integer bookmark = mBookmarker.getBookmark(mUri); + if (bookmark != null) { + showResumeDialog(movieActivity, bookmark); + } else { + mVideoView.start(); + } + } + + 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() { + public void onCancel(DialogInterface dialog) { + onCompletion(); + } + }); + builder.setPositiveButton( + R.string.resume_playing_resume, new OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + mVideoView.seekTo(bookmark); + mVideoView.start(); + } + }); + builder.setNegativeButton( + R.string.resume_playing_restart, new OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + mVideoView.start(); + } + }); + builder.show(); + } + + public void onPause() { + mHandler.removeCallbacksAndMessages(null); + mBookmarker.setBookmark(mUri, mVideoView.getCurrentPosition(), + mVideoView.getDuration()); + mVideoView.suspend(); + mHasPaused = true; + } + + public void onResume() { + if (mHasPaused) { + Integer bookmark = mBookmarker.getBookmark(mUri); + if (bookmark != null) { + mVideoView.seekTo(bookmark); + } + } + mVideoView.resume(); + } + + public void onDestroy() { + mVideoView.stopPlayback(); + mAudioBecomingNoisyReceiver.unregister(); + } + + public boolean onError(MediaPlayer player, int arg1, int arg2) { + mHandler.removeCallbacksAndMessages(null); + mProgressView.setVisibility(View.GONE); + return false; + } + + public void onCompletion(MediaPlayer mp) { + onCompletion(); + } + + public void onCompletion() { + } + + 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()) { + mVideoView.pause(); + } + } + } +} + +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 = dis.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; + } +} |