| /* |
| * 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.camera; |
| |
| import com.android.gallery.R; |
| |
| import android.app.AlertDialog; |
| import android.content.ContentResolver; |
| import android.content.ContentValues; |
| import android.content.Context; |
| import android.content.DialogInterface; |
| import android.content.Intent; |
| import android.content.DialogInterface.OnCancelListener; |
| import android.content.DialogInterface.OnClickListener; |
| import android.database.Cursor; |
| import android.database.sqlite.SQLiteException; |
| import android.media.MediaPlayer; |
| import android.net.Uri; |
| import android.os.Handler; |
| import android.provider.MediaStore; |
| import android.provider.MediaStore.Video; |
| import android.view.View; |
| import android.widget.MediaController; |
| import android.widget.VideoView; |
| |
| public class MovieViewControl implements MediaPlayer.OnErrorListener, |
| MediaPlayer.OnCompletionListener { |
| |
| @SuppressWarnings("unused") |
| private static final String TAG = "MovieViewControl"; |
| |
| private static final int ONE_MINUTE = 60 * 1000; |
| private static final int TWO_MINUTES = 2 * ONE_MINUTE; |
| private static final int FIVE_MINUTES = 5 * ONE_MINUTE; |
| |
| // Copied from MediaPlaybackService in the Music Player app. Should be |
| // public, but isn't. |
| private static final String SERVICECMD = |
| "com.android.music.musicservicecommand"; |
| private static final String CMDNAME = "command"; |
| private static final String CMDPAUSE = "pause"; |
| |
| private final VideoView mVideoView; |
| private final View mProgressView; |
| private final Uri mUri; |
| private final ContentResolver mContentResolver; |
| |
| // State maintained for proper onPause/OnResume behaviour. |
| private int mPositionWhenPaused = -1; |
| private boolean mWasPlayingWhenPaused = false; |
| private MediaController mMediaController; |
| |
| Handler mHandler = new Handler(); |
| |
| Runnable mPlayingChecker = new Runnable() { |
| public void run() { |
| if (mVideoView.isPlaying()) { |
| mProgressView.setVisibility(View.GONE); |
| } else { |
| mHandler.postDelayed(mPlayingChecker, 250); |
| } |
| } |
| }; |
| |
| public MovieViewControl(View rootView, Context context, Uri videoUri) { |
| mContentResolver = context.getContentResolver(); |
| mVideoView = (VideoView) rootView.findViewById(R.id.surface_view); |
| mProgressView = rootView.findViewById(R.id.progress_indicator); |
| |
| 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); |
| mMediaController = new MediaController(context); |
| mVideoView.setMediaController(mMediaController); |
| |
| // make the video view handle keys for seeking and pausing |
| mVideoView.requestFocus(); |
| |
| Intent i = new Intent(SERVICECMD); |
| i.putExtra(CMDNAME, CMDPAUSE); |
| context.sendBroadcast(i); |
| |
| final Integer bookmark = getBookmark(); |
| if (bookmark != null) { |
| 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), |
| MenuHelper.formatDuration(context, bookmark))); |
| 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(); |
| } else { |
| mVideoView.start(); |
| } |
| } |
| |
| private static boolean uriSupportsBookmarks(Uri uri) { |
| String scheme = uri.getScheme(); |
| String authority = uri.getAuthority(); |
| return ("content".equalsIgnoreCase(scheme) |
| && MediaStore.AUTHORITY.equalsIgnoreCase(authority)); |
| } |
| |
| private Integer getBookmark() { |
| if (!uriSupportsBookmarks(mUri)) { |
| return null; |
| } |
| |
| String[] projection = new String[] { |
| Video.VideoColumns.DURATION, |
| Video.VideoColumns.BOOKMARK}; |
| |
| try { |
| Cursor cursor = mContentResolver.query( |
| mUri, projection, null, null, null); |
| if (cursor != null) { |
| try { |
| if (cursor.moveToFirst()) { |
| int duration = getCursorInteger(cursor, 0); |
| int bookmark = getCursorInteger(cursor, 1); |
| if ((bookmark < TWO_MINUTES) |
| || (duration < FIVE_MINUTES) |
| || (bookmark > (duration - ONE_MINUTE))) { |
| return null; |
| } |
| return Integer.valueOf(bookmark); |
| } |
| } finally { |
| cursor.close(); |
| } |
| } |
| } catch (SQLiteException e) { |
| // ignore |
| } |
| |
| return null; |
| } |
| |
| private static int getCursorInteger(Cursor cursor, int index) { |
| try { |
| return cursor.getInt(index); |
| } catch (SQLiteException e) { |
| return 0; |
| } catch (NumberFormatException e) { |
| return 0; |
| } |
| |
| } |
| |
| private void setBookmark(int bookmark) { |
| if (!uriSupportsBookmarks(mUri)) { |
| return; |
| } |
| |
| ContentValues values = new ContentValues(); |
| values.put(Video.VideoColumns.BOOKMARK, Integer.toString(bookmark)); |
| try { |
| mContentResolver.update(mUri, values, null, null); |
| } catch (SecurityException ex) { |
| // Ignore, can happen if we try to set the bookmark on a read-only |
| // resource such as a video attached to GMail. |
| } catch (SQLiteException e) { |
| // ignore. can happen if the content doesn't support a bookmark |
| // column. |
| } catch (UnsupportedOperationException e) { |
| // ignore. can happen if the external volume is already detached. |
| } |
| } |
| |
| public void onPause() { |
| mHandler.removeCallbacksAndMessages(null); |
| setBookmark(mVideoView.getCurrentPosition()); |
| |
| mPositionWhenPaused = mVideoView.getCurrentPosition(); |
| mWasPlayingWhenPaused = mVideoView.isPlaying(); |
| mVideoView.stopPlayback(); |
| } |
| |
| public void onResume() { |
| if (mPositionWhenPaused >= 0) { |
| mVideoView.setVideoURI(mUri); |
| mVideoView.seekTo(mPositionWhenPaused); |
| mPositionWhenPaused = -1; |
| if (mWasPlayingWhenPaused) { |
| mMediaController.show(0); |
| } |
| } |
| } |
| |
| 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() { |
| } |
| } |