• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2012 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.gallery3d.app;
18 
19 import android.app.ActionBar;
20 import android.app.Activity;
21 import android.app.ProgressDialog;
22 import android.content.Context;
23 import android.content.Intent;
24 import android.media.MediaPlayer;
25 import android.net.Uri;
26 import android.os.Bundle;
27 import android.os.Handler;
28 import android.provider.MediaStore;
29 import android.view.View;
30 import android.view.ViewGroup;
31 import android.view.Window;
32 import android.widget.TextView;
33 import android.widget.Toast;
34 import android.widget.VideoView;
35 
36 import com.android.gallery3d.R;
37 import com.android.gallery3d.util.SaveVideoFileInfo;
38 import com.android.gallery3d.util.SaveVideoFileUtils;
39 
40 import java.io.File;
41 import java.io.IOException;
42 
43 public class TrimVideo extends Activity implements
44         MediaPlayer.OnErrorListener,
45         MediaPlayer.OnCompletionListener,
46         ControllerOverlay.Listener {
47 
48     private VideoView mVideoView;
49     private TextView mSaveVideoTextView;
50     private TrimControllerOverlay mController;
51     private Context mContext;
52     private Uri mUri;
53     private final Handler mHandler = new Handler();
54     public static final String TRIM_ACTION = "com.android.camera.action.TRIM";
55 
56     public ProgressDialog mProgress;
57 
58     private int mTrimStartTime = 0;
59     private int mTrimEndTime = 0;
60     private int mVideoPosition = 0;
61     public static final String KEY_TRIM_START = "trim_start";
62     public static final String KEY_TRIM_END = "trim_end";
63     public static final String KEY_VIDEO_POSITION = "video_pos";
64     private boolean mHasPaused = false;
65 
66     private String mSrcVideoPath = null;
67     private static final String TIME_STAMP_NAME = "'TRIM'_yyyyMMdd_HHmmss";
68     private SaveVideoFileInfo mDstFileInfo = null;
69 
70     @Override
onCreate(Bundle savedInstanceState)71     public void onCreate(Bundle savedInstanceState) {
72         mContext = getApplicationContext();
73         super.onCreate(savedInstanceState);
74 
75         requestWindowFeature(Window.FEATURE_ACTION_BAR);
76         requestWindowFeature(Window.FEATURE_ACTION_BAR_OVERLAY);
77 
78         ActionBar actionBar = getActionBar();
79         int displayOptions = ActionBar.DISPLAY_SHOW_HOME;
80         actionBar.setDisplayOptions(0, displayOptions);
81         displayOptions = ActionBar.DISPLAY_SHOW_CUSTOM;
82         actionBar.setDisplayOptions(displayOptions, displayOptions);
83         actionBar.setCustomView(R.layout.trim_menu);
84 
85         mSaveVideoTextView = (TextView) findViewById(R.id.start_trim);
86         mSaveVideoTextView.setOnClickListener(new View.OnClickListener() {
87             @Override
88             public void onClick(View arg0) {
89                 trimVideo();
90             }
91         });
92         mSaveVideoTextView.setEnabled(false);
93 
94         Intent intent = getIntent();
95         mUri = intent.getData();
96         mSrcVideoPath = intent.getStringExtra(PhotoPage.KEY_MEDIA_ITEM_PATH);
97         setContentView(R.layout.trim_view);
98         View rootView = findViewById(R.id.trim_view_root);
99 
100         mVideoView = (VideoView) rootView.findViewById(R.id.surface_view);
101 
102         mController = new TrimControllerOverlay(mContext);
103         ((ViewGroup) rootView).addView(mController.getView());
104         mController.setListener(this);
105         mController.setCanReplay(true);
106 
107         mVideoView.setOnErrorListener(this);
108         mVideoView.setOnCompletionListener(this);
109         mVideoView.setVideoURI(mUri);
110 
111         playVideo();
112     }
113 
114     @Override
onResume()115     public void onResume() {
116         super.onResume();
117         if (mHasPaused) {
118             mVideoView.seekTo(mVideoPosition);
119             mVideoView.resume();
120             mHasPaused = false;
121         }
122         mHandler.post(mProgressChecker);
123     }
124 
125     @Override
onPause()126     public void onPause() {
127         mHasPaused = true;
128         mHandler.removeCallbacksAndMessages(null);
129         mVideoPosition = mVideoView.getCurrentPosition();
130         mVideoView.suspend();
131         super.onPause();
132     }
133 
134     @Override
onStop()135     public void onStop() {
136         if (mProgress != null) {
137             mProgress.dismiss();
138             mProgress = null;
139         }
140         super.onStop();
141     }
142 
143     @Override
onDestroy()144     public void onDestroy() {
145         mVideoView.stopPlayback();
146         super.onDestroy();
147     }
148 
149     private final Runnable mProgressChecker = new Runnable() {
150         @Override
151         public void run() {
152             int pos = setProgress();
153             mHandler.postDelayed(mProgressChecker, 200 - (pos % 200));
154         }
155     };
156 
157     @Override
onSaveInstanceState(Bundle savedInstanceState)158     public void onSaveInstanceState(Bundle savedInstanceState) {
159         savedInstanceState.putInt(KEY_TRIM_START, mTrimStartTime);
160         savedInstanceState.putInt(KEY_TRIM_END, mTrimEndTime);
161         savedInstanceState.putInt(KEY_VIDEO_POSITION, mVideoPosition);
162         super.onSaveInstanceState(savedInstanceState);
163     }
164 
165     @Override
onRestoreInstanceState(Bundle savedInstanceState)166     public void onRestoreInstanceState(Bundle savedInstanceState) {
167         super.onRestoreInstanceState(savedInstanceState);
168         mTrimStartTime = savedInstanceState.getInt(KEY_TRIM_START, 0);
169         mTrimEndTime = savedInstanceState.getInt(KEY_TRIM_END, 0);
170         mVideoPosition = savedInstanceState.getInt(KEY_VIDEO_POSITION, 0);
171     }
172 
173     // This updates the time bar display (if necessary). It is called by
174     // mProgressChecker and also from places where the time bar needs
175     // to be updated immediately.
setProgress()176     private int setProgress() {
177         mVideoPosition = mVideoView.getCurrentPosition();
178         // If the video position is smaller than the starting point of trimming,
179         // correct it.
180         if (mVideoPosition < mTrimStartTime) {
181             mVideoView.seekTo(mTrimStartTime);
182             mVideoPosition = mTrimStartTime;
183         }
184         // If the position is bigger than the end point of trimming, show the
185         // replay button and pause.
186         if (mVideoPosition >= mTrimEndTime && mTrimEndTime > 0) {
187             if (mVideoPosition > mTrimEndTime) {
188                 mVideoView.seekTo(mTrimEndTime);
189                 mVideoPosition = mTrimEndTime;
190             }
191             mController.showEnded();
192             mVideoView.pause();
193         }
194 
195         int duration = mVideoView.getDuration();
196         if (duration > 0 && mTrimEndTime == 0) {
197             mTrimEndTime = duration;
198         }
199         mController.setTimes(mVideoPosition, duration, mTrimStartTime, mTrimEndTime);
200         return mVideoPosition;
201     }
202 
playVideo()203     private void playVideo() {
204         mVideoView.start();
205         mController.showPlaying();
206         setProgress();
207     }
208 
pauseVideo()209     private void pauseVideo() {
210         mVideoView.pause();
211         mController.showPaused();
212     }
213 
214 
isModified()215     private boolean isModified() {
216         int delta = mTrimEndTime - mTrimStartTime;
217 
218         // Considering that we only trim at sync frame, we don't want to trim
219         // when the time interval is too short or too close to the origin.
220         if (delta < 100 || Math.abs(mVideoView.getDuration() - delta) < 100) {
221             return false;
222         } else {
223             return true;
224         }
225     }
226 
trimVideo()227     private void trimVideo() {
228 
229         mDstFileInfo = SaveVideoFileUtils.getDstMp4FileInfo(TIME_STAMP_NAME,
230                 getContentResolver(), mUri, getString(R.string.folder_download));
231         final File mSrcFile = new File(mSrcVideoPath);
232 
233         showProgressDialog();
234 
235         new Thread(new Runnable() {
236             @Override
237             public void run() {
238                 try {
239                     VideoUtils.startTrim(mSrcFile, mDstFileInfo.mFile,
240                             mTrimStartTime, mTrimEndTime);
241                     // Update the database for adding a new video file.
242                     SaveVideoFileUtils.insertContent(mDstFileInfo,
243                             getContentResolver(), mUri);
244                 } catch (IOException e) {
245                     e.printStackTrace();
246                 }
247                 // After trimming is done, trigger the UI changed.
248                 mHandler.post(new Runnable() {
249                     @Override
250                     public void run() {
251                         Toast.makeText(getApplicationContext(),
252                             getString(R.string.save_into, mDstFileInfo.mFolderName),
253                             Toast.LENGTH_SHORT)
254                             .show();
255                         // TODO: change trimming into a service to avoid
256                         // this progressDialog and add notification properly.
257                         if (mProgress != null) {
258                             mProgress.dismiss();
259                             mProgress = null;
260                             // Show the result only when the activity not stopped.
261                             Intent intent = new Intent(android.content.Intent.ACTION_VIEW);
262                             intent.setDataAndType(Uri.fromFile(mDstFileInfo.mFile), "video/*");
263                             intent.putExtra(MediaStore.EXTRA_FINISH_ON_COMPLETION, false);
264                             startActivity(intent);
265                             finish();
266                         }
267                     }
268                 });
269             }
270         }).start();
271     }
272 
showProgressDialog()273     private void showProgressDialog() {
274         // create a background thread to trim the video.
275         // and show the progress.
276         mProgress = new ProgressDialog(this);
277         mProgress.setTitle(getString(R.string.trimming));
278         mProgress.setMessage(getString(R.string.please_wait));
279         // TODO: make this cancelable.
280         mProgress.setCancelable(false);
281         mProgress.setCanceledOnTouchOutside(false);
282         mProgress.show();
283     }
284 
285     @Override
onPlayPause()286     public void onPlayPause() {
287         if (mVideoView.isPlaying()) {
288             pauseVideo();
289         } else {
290             playVideo();
291         }
292     }
293 
294     @Override
onSeekStart()295     public void onSeekStart() {
296         pauseVideo();
297     }
298 
299     @Override
onSeekMove(int time)300     public void onSeekMove(int time) {
301         mVideoView.seekTo(time);
302     }
303 
304     @Override
onSeekEnd(int time, int start, int end)305     public void onSeekEnd(int time, int start, int end) {
306         mVideoView.seekTo(time);
307         mTrimStartTime = start;
308         mTrimEndTime = end;
309         setProgress();
310         // Enable save if there's modifications
311         mSaveVideoTextView.setEnabled(isModified());
312     }
313 
314     @Override
onShown()315     public void onShown() {
316     }
317 
318     @Override
onHidden()319     public void onHidden() {
320     }
321 
322     @Override
onReplay()323     public void onReplay() {
324         mVideoView.seekTo(mTrimStartTime);
325         playVideo();
326     }
327 
328     @Override
onCompletion(MediaPlayer mp)329     public void onCompletion(MediaPlayer mp) {
330         mController.showEnded();
331     }
332 
333     @Override
onError(MediaPlayer mp, int what, int extra)334     public boolean onError(MediaPlayer mp, int what, int extra) {
335         return false;
336     }
337 }
338