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