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