Home | History | Annotate | Download | only in camera
      1 /*
      2  * Copyright (C) 2009 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.camera;
     18 
     19 import com.android.gallery.R;
     20 
     21 import android.app.AlertDialog;
     22 import android.content.ContentResolver;
     23 import android.content.ContentValues;
     24 import android.content.Context;
     25 import android.content.DialogInterface;
     26 import android.content.Intent;
     27 import android.content.DialogInterface.OnCancelListener;
     28 import android.content.DialogInterface.OnClickListener;
     29 import android.database.Cursor;
     30 import android.database.sqlite.SQLiteException;
     31 import android.media.MediaPlayer;
     32 import android.net.Uri;
     33 import android.os.Handler;
     34 import android.provider.MediaStore;
     35 import android.provider.MediaStore.Video;
     36 import android.view.View;
     37 import android.widget.MediaController;
     38 import android.widget.VideoView;
     39 
     40 public class MovieViewControl implements MediaPlayer.OnErrorListener,
     41         MediaPlayer.OnCompletionListener {
     42 
     43     @SuppressWarnings("unused")
     44     private static final String TAG = "MovieViewControl";
     45 
     46     private static final int ONE_MINUTE = 60 * 1000;
     47     private static final int TWO_MINUTES = 2 * ONE_MINUTE;
     48     private static final int FIVE_MINUTES = 5 * ONE_MINUTE;
     49 
     50     // Copied from MediaPlaybackService in the Music Player app. Should be
     51     // public, but isn't.
     52     private static final String SERVICECMD =
     53             "com.android.music.musicservicecommand";
     54     private static final String CMDNAME = "command";
     55     private static final String CMDPAUSE = "pause";
     56 
     57     private final VideoView mVideoView;
     58     private final View mProgressView;
     59     private final Uri mUri;
     60     private final ContentResolver mContentResolver;
     61 
     62     // State maintained for proper onPause/OnResume behaviour.
     63     private int mPositionWhenPaused = -1;
     64     private boolean mWasPlayingWhenPaused = false;
     65     private MediaController mMediaController;
     66 
     67     Handler mHandler = new Handler();
     68 
     69     Runnable mPlayingChecker = new Runnable() {
     70         public void run() {
     71             if (mVideoView.isPlaying()) {
     72                 mProgressView.setVisibility(View.GONE);
     73             } else {
     74                 mHandler.postDelayed(mPlayingChecker, 250);
     75             }
     76         }
     77     };
     78 
     79     public MovieViewControl(View rootView, Context context, Uri videoUri) {
     80         mContentResolver = context.getContentResolver();
     81         mVideoView = (VideoView) rootView.findViewById(R.id.surface_view);
     82         mProgressView = rootView.findViewById(R.id.progress_indicator);
     83 
     84         mUri = videoUri;
     85 
     86         // For streams that we expect to be slow to start up, show a
     87         // progress spinner until playback starts.
     88         String scheme = mUri.getScheme();
     89         if ("http".equalsIgnoreCase(scheme)
     90                 || "rtsp".equalsIgnoreCase(scheme)) {
     91             mHandler.postDelayed(mPlayingChecker, 250);
     92         } else {
     93             mProgressView.setVisibility(View.GONE);
     94         }
     95 
     96         mVideoView.setOnErrorListener(this);
     97         mVideoView.setOnCompletionListener(this);
     98         mVideoView.setVideoURI(mUri);
     99         mMediaController = new MediaController(context);
    100         mVideoView.setMediaController(mMediaController);
    101 
    102         // make the video view handle keys for seeking and pausing
    103         mVideoView.requestFocus();
    104 
    105         Intent i = new Intent(SERVICECMD);
    106         i.putExtra(CMDNAME, CMDPAUSE);
    107         context.sendBroadcast(i);
    108 
    109         final Integer bookmark = getBookmark();
    110         if (bookmark != null) {
    111             AlertDialog.Builder builder = new AlertDialog.Builder(context);
    112             builder.setTitle(R.string.resume_playing_title);
    113             builder.setMessage(String.format(
    114                     context.getString(R.string.resume_playing_message),
    115                     MenuHelper.formatDuration(context, bookmark)));
    116             builder.setOnCancelListener(new OnCancelListener() {
    117                 public void onCancel(DialogInterface dialog) {
    118                     onCompletion();
    119                 }});
    120             builder.setPositiveButton(R.string.resume_playing_resume,
    121                     new OnClickListener() {
    122                 public void onClick(DialogInterface dialog, int which) {
    123                     mVideoView.seekTo(bookmark);
    124                     mVideoView.start();
    125                 }});
    126             builder.setNegativeButton(R.string.resume_playing_restart,
    127                     new OnClickListener() {
    128                 public void onClick(DialogInterface dialog, int which) {
    129                     mVideoView.start();
    130                 }});
    131             builder.show();
    132         } else {
    133             mVideoView.start();
    134         }
    135     }
    136 
    137     private static boolean uriSupportsBookmarks(Uri uri) {
    138         String scheme = uri.getScheme();
    139         String authority = uri.getAuthority();
    140         return ("content".equalsIgnoreCase(scheme)
    141                 && MediaStore.AUTHORITY.equalsIgnoreCase(authority));
    142     }
    143 
    144     private Integer getBookmark() {
    145         if (!uriSupportsBookmarks(mUri)) {
    146             return null;
    147         }
    148 
    149         String[] projection = new String[] {
    150                 Video.VideoColumns.DURATION,
    151                 Video.VideoColumns.BOOKMARK};
    152 
    153         try {
    154             Cursor cursor = mContentResolver.query(
    155                     mUri, projection, null, null, null);
    156             if (cursor != null) {
    157                 try {
    158                     if (cursor.moveToFirst()) {
    159                         int duration = getCursorInteger(cursor, 0);
    160                         int bookmark = getCursorInteger(cursor, 1);
    161                         if ((bookmark < TWO_MINUTES)
    162                                 || (duration < FIVE_MINUTES)
    163                                 || (bookmark > (duration - ONE_MINUTE))) {
    164                             return null;
    165                         }
    166                         return Integer.valueOf(bookmark);
    167                     }
    168                 } finally {
    169                     cursor.close();
    170                 }
    171             }
    172         } catch (SQLiteException e) {
    173             // ignore
    174         }
    175 
    176         return null;
    177     }
    178 
    179     private static int getCursorInteger(Cursor cursor, int index) {
    180         try {
    181             return cursor.getInt(index);
    182         } catch (SQLiteException e) {
    183             return 0;
    184         } catch (NumberFormatException e) {
    185             return 0;
    186         }
    187 
    188     }
    189 
    190     private void setBookmark(int bookmark) {
    191         if (!uriSupportsBookmarks(mUri)) {
    192             return;
    193         }
    194 
    195         ContentValues values = new ContentValues();
    196         values.put(Video.VideoColumns.BOOKMARK, Integer.toString(bookmark));
    197         try {
    198             mContentResolver.update(mUri, values, null, null);
    199         } catch (SecurityException ex) {
    200             // Ignore, can happen if we try to set the bookmark on a read-only
    201             // resource such as a video attached to GMail.
    202         } catch (SQLiteException e) {
    203             // ignore. can happen if the content doesn't support a bookmark
    204             // column.
    205         } catch (UnsupportedOperationException e) {
    206             // ignore. can happen if the external volume is already detached.
    207         }
    208     }
    209 
    210     public void onPause() {
    211         mHandler.removeCallbacksAndMessages(null);
    212         setBookmark(mVideoView.getCurrentPosition());
    213 
    214         mPositionWhenPaused = mVideoView.getCurrentPosition();
    215         mWasPlayingWhenPaused = mVideoView.isPlaying();
    216         mVideoView.stopPlayback();
    217     }
    218 
    219     public void onResume() {
    220         if (mPositionWhenPaused >= 0) {
    221             mVideoView.setVideoURI(mUri);
    222             mVideoView.seekTo(mPositionWhenPaused);
    223             mPositionWhenPaused = -1;
    224             if (mWasPlayingWhenPaused) {
    225                 mMediaController.show(0);
    226             }
    227         }
    228     }
    229 
    230     public boolean onError(MediaPlayer player, int arg1, int arg2) {
    231         mHandler.removeCallbacksAndMessages(null);
    232         mProgressView.setVisibility(View.GONE);
    233         return false;
    234     }
    235 
    236     public void onCompletion(MediaPlayer mp) {
    237         onCompletion();
    238     }
    239 
    240     public void onCompletion() {
    241     }
    242 }
    243