MovieViewControl.java revision 666ea1b28a76aeba74744148b15099254d918671
1666ea1b28a76aeba74744148b15099254d918671Owen Lin/* 2666ea1b28a76aeba74744148b15099254d918671Owen Lin * Copyright (C) 2009 The Android Open Source Project 3666ea1b28a76aeba74744148b15099254d918671Owen Lin * 4666ea1b28a76aeba74744148b15099254d918671Owen Lin * Licensed under the Apache License, Version 2.0 (the "License"); 5666ea1b28a76aeba74744148b15099254d918671Owen Lin * you may not use this file except in compliance with the License. 6666ea1b28a76aeba74744148b15099254d918671Owen Lin * You may obtain a copy of the License at 7666ea1b28a76aeba74744148b15099254d918671Owen Lin * 8666ea1b28a76aeba74744148b15099254d918671Owen Lin * http://www.apache.org/licenses/LICENSE-2.0 9666ea1b28a76aeba74744148b15099254d918671Owen Lin * 10666ea1b28a76aeba74744148b15099254d918671Owen Lin * Unless required by applicable law or agreed to in writing, software 11666ea1b28a76aeba74744148b15099254d918671Owen Lin * distributed under the License is distributed on an "AS IS" BASIS, 12666ea1b28a76aeba74744148b15099254d918671Owen Lin * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13666ea1b28a76aeba74744148b15099254d918671Owen Lin * See the License for the specific language governing permissions and 14666ea1b28a76aeba74744148b15099254d918671Owen Lin * limitations under the License. 15666ea1b28a76aeba74744148b15099254d918671Owen Lin */ 16666ea1b28a76aeba74744148b15099254d918671Owen Lin 17666ea1b28a76aeba74744148b15099254d918671Owen Linpackage com.android.camera; 18666ea1b28a76aeba74744148b15099254d918671Owen Lin 19666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.app.AlertDialog; 20666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.content.ContentResolver; 21666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.content.ContentValues; 22666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.content.Context; 23666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.content.DialogInterface; 24666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.content.Intent; 25666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.content.DialogInterface.OnCancelListener; 26666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.content.DialogInterface.OnClickListener; 27666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.database.Cursor; 28666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.database.sqlite.SQLiteException; 29666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.media.MediaPlayer; 30666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.net.Uri; 31666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.os.Handler; 32666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.provider.MediaStore; 33666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.provider.MediaStore.Video; 34666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.view.View; 35666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.widget.MediaController; 36666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.widget.VideoView; 37666ea1b28a76aeba74744148b15099254d918671Owen Lin 38666ea1b28a76aeba74744148b15099254d918671Owen Linpublic class MovieViewControl implements MediaPlayer.OnErrorListener, 39666ea1b28a76aeba74744148b15099254d918671Owen Lin MediaPlayer.OnCompletionListener { 40666ea1b28a76aeba74744148b15099254d918671Owen Lin 41666ea1b28a76aeba74744148b15099254d918671Owen Lin @SuppressWarnings("unused") 42666ea1b28a76aeba74744148b15099254d918671Owen Lin private static final String TAG = "MovieViewControl"; 43666ea1b28a76aeba74744148b15099254d918671Owen Lin 44666ea1b28a76aeba74744148b15099254d918671Owen Lin private static final int ONE_MINUTE = 60 * 1000; 45666ea1b28a76aeba74744148b15099254d918671Owen Lin private static final int TWO_MINUTES = 2 * ONE_MINUTE; 46666ea1b28a76aeba74744148b15099254d918671Owen Lin private static final int FIVE_MINUTES = 5 * ONE_MINUTE; 47666ea1b28a76aeba74744148b15099254d918671Owen Lin 48666ea1b28a76aeba74744148b15099254d918671Owen Lin // Copied from MediaPlaybackService in the Music Player app. Should be 49666ea1b28a76aeba74744148b15099254d918671Owen Lin // public, but isn't. 50666ea1b28a76aeba74744148b15099254d918671Owen Lin private static final String SERVICECMD = 51666ea1b28a76aeba74744148b15099254d918671Owen Lin "com.android.music.musicservicecommand"; 52666ea1b28a76aeba74744148b15099254d918671Owen Lin private static final String CMDNAME = "command"; 53666ea1b28a76aeba74744148b15099254d918671Owen Lin private static final String CMDPAUSE = "pause"; 54666ea1b28a76aeba74744148b15099254d918671Owen Lin 55666ea1b28a76aeba74744148b15099254d918671Owen Lin private final VideoView mVideoView; 56666ea1b28a76aeba74744148b15099254d918671Owen Lin private final View mProgressView; 57666ea1b28a76aeba74744148b15099254d918671Owen Lin private final Uri mUri; 58666ea1b28a76aeba74744148b15099254d918671Owen Lin private final ContentResolver mContentResolver; 59666ea1b28a76aeba74744148b15099254d918671Owen Lin 60666ea1b28a76aeba74744148b15099254d918671Owen Lin // State maintained for proper onPause/OnResume behaviour. 61666ea1b28a76aeba74744148b15099254d918671Owen Lin private int mPositionWhenPaused = -1; 62666ea1b28a76aeba74744148b15099254d918671Owen Lin private boolean mWasPlayingWhenPaused = false; 63666ea1b28a76aeba74744148b15099254d918671Owen Lin private MediaController mMediaController; 64666ea1b28a76aeba74744148b15099254d918671Owen Lin 65666ea1b28a76aeba74744148b15099254d918671Owen Lin Handler mHandler = new Handler(); 66666ea1b28a76aeba74744148b15099254d918671Owen Lin 67666ea1b28a76aeba74744148b15099254d918671Owen Lin Runnable mPlayingChecker = new Runnable() { 68666ea1b28a76aeba74744148b15099254d918671Owen Lin public void run() { 69666ea1b28a76aeba74744148b15099254d918671Owen Lin if (mVideoView.isPlaying()) { 70666ea1b28a76aeba74744148b15099254d918671Owen Lin mProgressView.setVisibility(View.GONE); 71666ea1b28a76aeba74744148b15099254d918671Owen Lin } else { 72666ea1b28a76aeba74744148b15099254d918671Owen Lin mHandler.postDelayed(mPlayingChecker, 250); 73666ea1b28a76aeba74744148b15099254d918671Owen Lin } 74666ea1b28a76aeba74744148b15099254d918671Owen Lin } 75666ea1b28a76aeba74744148b15099254d918671Owen Lin }; 76666ea1b28a76aeba74744148b15099254d918671Owen Lin 77666ea1b28a76aeba74744148b15099254d918671Owen Lin public MovieViewControl(View rootView, Context context, Uri videoUri) { 78666ea1b28a76aeba74744148b15099254d918671Owen Lin mContentResolver = context.getContentResolver(); 79666ea1b28a76aeba74744148b15099254d918671Owen Lin mVideoView = (VideoView) rootView.findViewById(R.id.surface_view); 80666ea1b28a76aeba74744148b15099254d918671Owen Lin mProgressView = rootView.findViewById(R.id.progress_indicator); 81666ea1b28a76aeba74744148b15099254d918671Owen Lin 82666ea1b28a76aeba74744148b15099254d918671Owen Lin mUri = videoUri; 83666ea1b28a76aeba74744148b15099254d918671Owen Lin 84666ea1b28a76aeba74744148b15099254d918671Owen Lin // For streams that we expect to be slow to start up, show a 85666ea1b28a76aeba74744148b15099254d918671Owen Lin // progress spinner until playback starts. 86666ea1b28a76aeba74744148b15099254d918671Owen Lin String scheme = mUri.getScheme(); 87666ea1b28a76aeba74744148b15099254d918671Owen Lin if ("http".equalsIgnoreCase(scheme) 88666ea1b28a76aeba74744148b15099254d918671Owen Lin || "rtsp".equalsIgnoreCase(scheme)) { 89666ea1b28a76aeba74744148b15099254d918671Owen Lin mHandler.postDelayed(mPlayingChecker, 250); 90666ea1b28a76aeba74744148b15099254d918671Owen Lin } else { 91666ea1b28a76aeba74744148b15099254d918671Owen Lin mProgressView.setVisibility(View.GONE); 92666ea1b28a76aeba74744148b15099254d918671Owen Lin } 93666ea1b28a76aeba74744148b15099254d918671Owen Lin 94666ea1b28a76aeba74744148b15099254d918671Owen Lin mVideoView.setOnErrorListener(this); 95666ea1b28a76aeba74744148b15099254d918671Owen Lin mVideoView.setOnCompletionListener(this); 96666ea1b28a76aeba74744148b15099254d918671Owen Lin mVideoView.setVideoURI(mUri); 97666ea1b28a76aeba74744148b15099254d918671Owen Lin mMediaController = new MediaController(context); 98666ea1b28a76aeba74744148b15099254d918671Owen Lin mVideoView.setMediaController(mMediaController); 99666ea1b28a76aeba74744148b15099254d918671Owen Lin 100666ea1b28a76aeba74744148b15099254d918671Owen Lin // make the video view handle keys for seeking and pausing 101666ea1b28a76aeba74744148b15099254d918671Owen Lin mVideoView.requestFocus(); 102666ea1b28a76aeba74744148b15099254d918671Owen Lin 103666ea1b28a76aeba74744148b15099254d918671Owen Lin Intent i = new Intent(SERVICECMD); 104666ea1b28a76aeba74744148b15099254d918671Owen Lin i.putExtra(CMDNAME, CMDPAUSE); 105666ea1b28a76aeba74744148b15099254d918671Owen Lin context.sendBroadcast(i); 106666ea1b28a76aeba74744148b15099254d918671Owen Lin 107666ea1b28a76aeba74744148b15099254d918671Owen Lin final Integer bookmark = getBookmark(); 108666ea1b28a76aeba74744148b15099254d918671Owen Lin if (bookmark != null) { 109666ea1b28a76aeba74744148b15099254d918671Owen Lin AlertDialog.Builder builder = new AlertDialog.Builder(context); 110666ea1b28a76aeba74744148b15099254d918671Owen Lin builder.setTitle(R.string.resume_playing_title); 111666ea1b28a76aeba74744148b15099254d918671Owen Lin builder.setMessage(String.format( 112666ea1b28a76aeba74744148b15099254d918671Owen Lin context.getString(R.string.resume_playing_message), 113666ea1b28a76aeba74744148b15099254d918671Owen Lin MenuHelper.formatDuration(context, bookmark))); 114666ea1b28a76aeba74744148b15099254d918671Owen Lin builder.setOnCancelListener(new OnCancelListener() { 115666ea1b28a76aeba74744148b15099254d918671Owen Lin public void onCancel(DialogInterface dialog) { 116666ea1b28a76aeba74744148b15099254d918671Owen Lin onCompletion(); 117666ea1b28a76aeba74744148b15099254d918671Owen Lin }}); 118666ea1b28a76aeba74744148b15099254d918671Owen Lin builder.setPositiveButton(R.string.resume_playing_resume, 119666ea1b28a76aeba74744148b15099254d918671Owen Lin new OnClickListener() { 120666ea1b28a76aeba74744148b15099254d918671Owen Lin public void onClick(DialogInterface dialog, int which) { 121666ea1b28a76aeba74744148b15099254d918671Owen Lin mVideoView.seekTo(bookmark); 122666ea1b28a76aeba74744148b15099254d918671Owen Lin mVideoView.start(); 123666ea1b28a76aeba74744148b15099254d918671Owen Lin }}); 124666ea1b28a76aeba74744148b15099254d918671Owen Lin builder.setNegativeButton(R.string.resume_playing_restart, 125666ea1b28a76aeba74744148b15099254d918671Owen Lin new OnClickListener() { 126666ea1b28a76aeba74744148b15099254d918671Owen Lin public void onClick(DialogInterface dialog, int which) { 127666ea1b28a76aeba74744148b15099254d918671Owen Lin mVideoView.start(); 128666ea1b28a76aeba74744148b15099254d918671Owen Lin }}); 129666ea1b28a76aeba74744148b15099254d918671Owen Lin builder.show(); 130666ea1b28a76aeba74744148b15099254d918671Owen Lin } else { 131666ea1b28a76aeba74744148b15099254d918671Owen Lin mVideoView.start(); 132666ea1b28a76aeba74744148b15099254d918671Owen Lin } 133666ea1b28a76aeba74744148b15099254d918671Owen Lin } 134666ea1b28a76aeba74744148b15099254d918671Owen Lin 135666ea1b28a76aeba74744148b15099254d918671Owen Lin private static boolean uriSupportsBookmarks(Uri uri) { 136666ea1b28a76aeba74744148b15099254d918671Owen Lin String scheme = uri.getScheme(); 137666ea1b28a76aeba74744148b15099254d918671Owen Lin String authority = uri.getAuthority(); 138666ea1b28a76aeba74744148b15099254d918671Owen Lin return ("content".equalsIgnoreCase(scheme) 139666ea1b28a76aeba74744148b15099254d918671Owen Lin && MediaStore.AUTHORITY.equalsIgnoreCase(authority)); 140666ea1b28a76aeba74744148b15099254d918671Owen Lin } 141666ea1b28a76aeba74744148b15099254d918671Owen Lin 142666ea1b28a76aeba74744148b15099254d918671Owen Lin private Integer getBookmark() { 143666ea1b28a76aeba74744148b15099254d918671Owen Lin if (!uriSupportsBookmarks(mUri)) { 144666ea1b28a76aeba74744148b15099254d918671Owen Lin return null; 145666ea1b28a76aeba74744148b15099254d918671Owen Lin } 146666ea1b28a76aeba74744148b15099254d918671Owen Lin 147666ea1b28a76aeba74744148b15099254d918671Owen Lin String[] projection = new String[] { 148666ea1b28a76aeba74744148b15099254d918671Owen Lin Video.VideoColumns.DURATION, 149666ea1b28a76aeba74744148b15099254d918671Owen Lin Video.VideoColumns.BOOKMARK}; 150666ea1b28a76aeba74744148b15099254d918671Owen Lin 151666ea1b28a76aeba74744148b15099254d918671Owen Lin try { 152666ea1b28a76aeba74744148b15099254d918671Owen Lin Cursor cursor = mContentResolver.query( 153666ea1b28a76aeba74744148b15099254d918671Owen Lin mUri, projection, null, null, null); 154666ea1b28a76aeba74744148b15099254d918671Owen Lin if (cursor != null) { 155666ea1b28a76aeba74744148b15099254d918671Owen Lin try { 156666ea1b28a76aeba74744148b15099254d918671Owen Lin if (cursor.moveToFirst()) { 157666ea1b28a76aeba74744148b15099254d918671Owen Lin int duration = getCursorInteger(cursor, 0); 158666ea1b28a76aeba74744148b15099254d918671Owen Lin int bookmark = getCursorInteger(cursor, 1); 159666ea1b28a76aeba74744148b15099254d918671Owen Lin if ((bookmark < TWO_MINUTES) 160666ea1b28a76aeba74744148b15099254d918671Owen Lin || (duration < FIVE_MINUTES) 161666ea1b28a76aeba74744148b15099254d918671Owen Lin || (bookmark > (duration - ONE_MINUTE))) { 162666ea1b28a76aeba74744148b15099254d918671Owen Lin return null; 163666ea1b28a76aeba74744148b15099254d918671Owen Lin } 164666ea1b28a76aeba74744148b15099254d918671Owen Lin return Integer.valueOf(bookmark); 165666ea1b28a76aeba74744148b15099254d918671Owen Lin } 166666ea1b28a76aeba74744148b15099254d918671Owen Lin } finally { 167666ea1b28a76aeba74744148b15099254d918671Owen Lin cursor.close(); 168666ea1b28a76aeba74744148b15099254d918671Owen Lin } 169666ea1b28a76aeba74744148b15099254d918671Owen Lin } 170666ea1b28a76aeba74744148b15099254d918671Owen Lin } catch (SQLiteException e) { 171666ea1b28a76aeba74744148b15099254d918671Owen Lin // ignore 172666ea1b28a76aeba74744148b15099254d918671Owen Lin } 173666ea1b28a76aeba74744148b15099254d918671Owen Lin 174666ea1b28a76aeba74744148b15099254d918671Owen Lin return null; 175666ea1b28a76aeba74744148b15099254d918671Owen Lin } 176666ea1b28a76aeba74744148b15099254d918671Owen Lin 177666ea1b28a76aeba74744148b15099254d918671Owen Lin private static int getCursorInteger(Cursor cursor, int index) { 178666ea1b28a76aeba74744148b15099254d918671Owen Lin try { 179666ea1b28a76aeba74744148b15099254d918671Owen Lin return cursor.getInt(index); 180666ea1b28a76aeba74744148b15099254d918671Owen Lin } catch (SQLiteException e) { 181666ea1b28a76aeba74744148b15099254d918671Owen Lin return 0; 182666ea1b28a76aeba74744148b15099254d918671Owen Lin } catch (NumberFormatException e) { 183666ea1b28a76aeba74744148b15099254d918671Owen Lin return 0; 184666ea1b28a76aeba74744148b15099254d918671Owen Lin } 185666ea1b28a76aeba74744148b15099254d918671Owen Lin 186666ea1b28a76aeba74744148b15099254d918671Owen Lin } 187666ea1b28a76aeba74744148b15099254d918671Owen Lin 188666ea1b28a76aeba74744148b15099254d918671Owen Lin private void setBookmark(int bookmark) { 189666ea1b28a76aeba74744148b15099254d918671Owen Lin if (!uriSupportsBookmarks(mUri)) { 190666ea1b28a76aeba74744148b15099254d918671Owen Lin return; 191666ea1b28a76aeba74744148b15099254d918671Owen Lin } 192666ea1b28a76aeba74744148b15099254d918671Owen Lin 193666ea1b28a76aeba74744148b15099254d918671Owen Lin ContentValues values = new ContentValues(); 194666ea1b28a76aeba74744148b15099254d918671Owen Lin values.put(Video.VideoColumns.BOOKMARK, Integer.toString(bookmark)); 195666ea1b28a76aeba74744148b15099254d918671Owen Lin try { 196666ea1b28a76aeba74744148b15099254d918671Owen Lin mContentResolver.update(mUri, values, null, null); 197666ea1b28a76aeba74744148b15099254d918671Owen Lin } catch (SecurityException ex) { 198666ea1b28a76aeba74744148b15099254d918671Owen Lin // Ignore, can happen if we try to set the bookmark on a read-only 199666ea1b28a76aeba74744148b15099254d918671Owen Lin // resource such as a video attached to GMail. 200666ea1b28a76aeba74744148b15099254d918671Owen Lin } catch (SQLiteException e) { 201666ea1b28a76aeba74744148b15099254d918671Owen Lin // ignore. can happen if the content doesn't support a bookmark 202666ea1b28a76aeba74744148b15099254d918671Owen Lin // column. 203666ea1b28a76aeba74744148b15099254d918671Owen Lin } catch (UnsupportedOperationException e) { 204666ea1b28a76aeba74744148b15099254d918671Owen Lin // ignore. can happen if the external volume is already detached. 205666ea1b28a76aeba74744148b15099254d918671Owen Lin } 206666ea1b28a76aeba74744148b15099254d918671Owen Lin } 207666ea1b28a76aeba74744148b15099254d918671Owen Lin 208666ea1b28a76aeba74744148b15099254d918671Owen Lin public void onPause() { 209666ea1b28a76aeba74744148b15099254d918671Owen Lin mHandler.removeCallbacksAndMessages(null); 210666ea1b28a76aeba74744148b15099254d918671Owen Lin setBookmark(mVideoView.getCurrentPosition()); 211666ea1b28a76aeba74744148b15099254d918671Owen Lin 212666ea1b28a76aeba74744148b15099254d918671Owen Lin mPositionWhenPaused = mVideoView.getCurrentPosition(); 213666ea1b28a76aeba74744148b15099254d918671Owen Lin mWasPlayingWhenPaused = mVideoView.isPlaying(); 214666ea1b28a76aeba74744148b15099254d918671Owen Lin mVideoView.stopPlayback(); 215666ea1b28a76aeba74744148b15099254d918671Owen Lin } 216666ea1b28a76aeba74744148b15099254d918671Owen Lin 217666ea1b28a76aeba74744148b15099254d918671Owen Lin public void onResume() { 218666ea1b28a76aeba74744148b15099254d918671Owen Lin if (mPositionWhenPaused >= 0) { 219666ea1b28a76aeba74744148b15099254d918671Owen Lin mVideoView.setVideoURI(mUri); 220666ea1b28a76aeba74744148b15099254d918671Owen Lin mVideoView.seekTo(mPositionWhenPaused); 221666ea1b28a76aeba74744148b15099254d918671Owen Lin mPositionWhenPaused = -1; 222666ea1b28a76aeba74744148b15099254d918671Owen Lin if (mWasPlayingWhenPaused) { 223666ea1b28a76aeba74744148b15099254d918671Owen Lin mMediaController.show(0); 224666ea1b28a76aeba74744148b15099254d918671Owen Lin } 225666ea1b28a76aeba74744148b15099254d918671Owen Lin } 226666ea1b28a76aeba74744148b15099254d918671Owen Lin } 227666ea1b28a76aeba74744148b15099254d918671Owen Lin 228666ea1b28a76aeba74744148b15099254d918671Owen Lin public boolean onError(MediaPlayer player, int arg1, int arg2) { 229666ea1b28a76aeba74744148b15099254d918671Owen Lin mHandler.removeCallbacksAndMessages(null); 230666ea1b28a76aeba74744148b15099254d918671Owen Lin mProgressView.setVisibility(View.GONE); 231666ea1b28a76aeba74744148b15099254d918671Owen Lin return false; 232666ea1b28a76aeba74744148b15099254d918671Owen Lin } 233666ea1b28a76aeba74744148b15099254d918671Owen Lin 234666ea1b28a76aeba74744148b15099254d918671Owen Lin public void onCompletion(MediaPlayer mp) { 235666ea1b28a76aeba74744148b15099254d918671Owen Lin onCompletion(); 236666ea1b28a76aeba74744148b15099254d918671Owen Lin } 237666ea1b28a76aeba74744148b15099254d918671Owen Lin 238666ea1b28a76aeba74744148b15099254d918671Owen Lin public void onCompletion() { 239666ea1b28a76aeba74744148b15099254d918671Owen Lin } 240666ea1b28a76aeba74744148b15099254d918671Owen Lin} 241