/* * Copyright (C) 2012 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.gallery3d.app; import android.app.ActionBar; import android.app.Activity; import android.app.ProgressDialog; import android.content.Context; import android.content.Intent; import android.media.MediaPlayer; import android.net.Uri; import android.os.Bundle; import android.os.Handler; import android.provider.MediaStore; import android.view.View; import android.view.ViewGroup; import android.view.Window; import android.widget.TextView; import android.widget.Toast; import android.widget.VideoView; import com.android.gallery3d.R; import com.android.gallery3d.util.SaveVideoFileInfo; import com.android.gallery3d.util.SaveVideoFileUtils; import java.io.File; import java.io.IOException; public class TrimVideo extends Activity implements MediaPlayer.OnErrorListener, MediaPlayer.OnCompletionListener, ControllerOverlay.Listener { private VideoView mVideoView; private TextView mSaveVideoTextView; private TrimControllerOverlay mController; private Context mContext; private Uri mUri; private final Handler mHandler = new Handler(); public static final String TRIM_ACTION = "com.android.camera.action.TRIM"; public ProgressDialog mProgress; private int mTrimStartTime = 0; private int mTrimEndTime = 0; private int mVideoPosition = 0; public static final String KEY_TRIM_START = "trim_start"; public static final String KEY_TRIM_END = "trim_end"; public static final String KEY_VIDEO_POSITION = "video_pos"; private boolean mHasPaused = false; private String mSrcVideoPath = null; private static final String TIME_STAMP_NAME = "'TRIM'_yyyyMMdd_HHmmss"; private SaveVideoFileInfo mDstFileInfo = null; @Override public void onCreate(Bundle savedInstanceState) { mContext = getApplicationContext(); super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_ACTION_BAR); requestWindowFeature(Window.FEATURE_ACTION_BAR_OVERLAY); ActionBar actionBar = getActionBar(); int displayOptions = ActionBar.DISPLAY_SHOW_HOME; actionBar.setDisplayOptions(0, displayOptions); displayOptions = ActionBar.DISPLAY_SHOW_CUSTOM; actionBar.setDisplayOptions(displayOptions, displayOptions); actionBar.setCustomView(R.layout.trim_menu); mSaveVideoTextView = (TextView) findViewById(R.id.start_trim); mSaveVideoTextView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View arg0) { trimVideo(); } }); mSaveVideoTextView.setEnabled(false); Intent intent = getIntent(); mUri = intent.getData(); mSrcVideoPath = intent.getStringExtra(PhotoPage.KEY_MEDIA_ITEM_PATH); setContentView(R.layout.trim_view); View rootView = findViewById(R.id.trim_view_root); mVideoView = (VideoView) rootView.findViewById(R.id.surface_view); mController = new TrimControllerOverlay(mContext); ((ViewGroup) rootView).addView(mController.getView()); mController.setListener(this); mController.setCanReplay(true); mVideoView.setOnErrorListener(this); mVideoView.setOnCompletionListener(this); mVideoView.setVideoURI(mUri); playVideo(); } @Override public void onResume() { super.onResume(); if (mHasPaused) { mVideoView.seekTo(mVideoPosition); mVideoView.resume(); mHasPaused = false; } mHandler.post(mProgressChecker); } @Override public void onPause() { mHasPaused = true; mHandler.removeCallbacksAndMessages(null); mVideoPosition = mVideoView.getCurrentPosition(); mVideoView.suspend(); super.onPause(); } @Override public void onStop() { if (mProgress != null) { mProgress.dismiss(); mProgress = null; } super.onStop(); } @Override public void onDestroy() { mVideoView.stopPlayback(); super.onDestroy(); } private final Runnable mProgressChecker = new Runnable() { @Override public void run() { int pos = setProgress(); mHandler.postDelayed(mProgressChecker, 200 - (pos % 200)); } }; @Override public void onSaveInstanceState(Bundle savedInstanceState) { savedInstanceState.putInt(KEY_TRIM_START, mTrimStartTime); savedInstanceState.putInt(KEY_TRIM_END, mTrimEndTime); savedInstanceState.putInt(KEY_VIDEO_POSITION, mVideoPosition); super.onSaveInstanceState(savedInstanceState); } @Override public void onRestoreInstanceState(Bundle savedInstanceState) { super.onRestoreInstanceState(savedInstanceState); mTrimStartTime = savedInstanceState.getInt(KEY_TRIM_START, 0); mTrimEndTime = savedInstanceState.getInt(KEY_TRIM_END, 0); mVideoPosition = savedInstanceState.getInt(KEY_VIDEO_POSITION, 0); } // This updates the time bar display (if necessary). It is called by // mProgressChecker and also from places where the time bar needs // to be updated immediately. private int setProgress() { mVideoPosition = mVideoView.getCurrentPosition(); // If the video position is smaller than the starting point of trimming, // correct it. if (mVideoPosition < mTrimStartTime) { mVideoView.seekTo(mTrimStartTime); mVideoPosition = mTrimStartTime; } // If the position is bigger than the end point of trimming, show the // replay button and pause. if (mVideoPosition >= mTrimEndTime && mTrimEndTime > 0) { if (mVideoPosition > mTrimEndTime) { mVideoView.seekTo(mTrimEndTime); mVideoPosition = mTrimEndTime; } mController.showEnded(); mVideoView.pause(); } int duration = mVideoView.getDuration(); if (duration > 0 && mTrimEndTime == 0) { mTrimEndTime = duration; } mController.setTimes(mVideoPosition, duration, mTrimStartTime, mTrimEndTime); return mVideoPosition; } private void playVideo() { mVideoView.start(); mController.showPlaying(); setProgress(); } private void pauseVideo() { mVideoView.pause(); mController.showPaused(); } private boolean isModified() { int delta = mTrimEndTime - mTrimStartTime; // Considering that we only trim at sync frame, we don't want to trim // when the time interval is too short or too close to the origin. if (delta < 100 || Math.abs(mVideoView.getDuration() - delta) < 100) { return false; } else { return true; } } private void trimVideo() { mDstFileInfo = SaveVideoFileUtils.getDstMp4FileInfo(TIME_STAMP_NAME, getContentResolver(), mUri, getString(R.string.folder_download)); final File mSrcFile = new File(mSrcVideoPath); showProgressDialog(); new Thread(new Runnable() { @Override public void run() { try { VideoUtils.startTrim(mSrcFile, mDstFileInfo.mFile, mTrimStartTime, mTrimEndTime); // Update the database for adding a new video file. SaveVideoFileUtils.insertContent(mDstFileInfo, getContentResolver(), mUri); } catch (IOException e) { e.printStackTrace(); } // After trimming is done, trigger the UI changed. mHandler.post(new Runnable() { @Override public void run() { Toast.makeText(getApplicationContext(), getString(R.string.save_into, mDstFileInfo.mFolderName), Toast.LENGTH_SHORT) .show(); // TODO: change trimming into a service to avoid // this progressDialog and add notification properly. if (mProgress != null) { mProgress.dismiss(); mProgress = null; // Show the result only when the activity not stopped. Intent intent = new Intent(android.content.Intent.ACTION_VIEW); intent.setDataAndType(Uri.fromFile(mDstFileInfo.mFile), "video/*"); intent.putExtra(MediaStore.EXTRA_FINISH_ON_COMPLETION, false); startActivity(intent); finish(); } } }); } }).start(); } private void showProgressDialog() { // create a background thread to trim the video. // and show the progress. mProgress = new ProgressDialog(this); mProgress.setTitle(getString(R.string.trimming)); mProgress.setMessage(getString(R.string.please_wait)); // TODO: make this cancelable. mProgress.setCancelable(false); mProgress.setCanceledOnTouchOutside(false); mProgress.show(); } @Override public void onPlayPause() { if (mVideoView.isPlaying()) { pauseVideo(); } else { playVideo(); } } @Override public void onSeekStart() { pauseVideo(); } @Override public void onSeekMove(int time) { mVideoView.seekTo(time); } @Override public void onSeekEnd(int time, int start, int end) { mVideoView.seekTo(time); mTrimStartTime = start; mTrimEndTime = end; setProgress(); // Enable save if there's modifications mSaveVideoTextView.setEnabled(isModified()); } @Override public void onShown() { } @Override public void onHidden() { } @Override public void onReplay() { mVideoView.seekTo(mTrimStartTime); playVideo(); } @Override public void onCompletion(MediaPlayer mp) { mController.showEnded(); } @Override public boolean onError(MediaPlayer mp, int what, int extra) { return false; } }