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