summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/com/android/gallery3d/app/MovieControllerOverlayNew.java110
-rwxr-xr-xsrc/com/android/gallery3d/app/MoviePlayer.java4
-rwxr-xr-xsrc/com/android/gallery3d/app/TimeBar.java2
-rw-r--r--src/com/android/gallery3d/app/TrimTimeBar.java39
-rw-r--r--src/com/android/gallery3d/app/TrimVideo.java24
-rw-r--r--src/com/android/gallery3d/filtershow/cache/ImageLoader.java3
-rw-r--r--src/com/android/gallery3d/ui/MenuExecutor.java37
-rwxr-xr-xsrc/com/android/gallery3d/ui/TimeLineTitleMaker.java2
-rw-r--r--src/org/codeaurora/gallery3d/video/CodeauroraVideoView.java8
-rw-r--r--src/org/codeaurora/gallery3d/video/IVideoSnapshotListener.java35
-rw-r--r--src/org/codeaurora/gallery3d/video/VideoSnapshotExt.java220
11 files changed, 445 insertions, 39 deletions
diff --git a/src/com/android/gallery3d/app/MovieControllerOverlayNew.java b/src/com/android/gallery3d/app/MovieControllerOverlayNew.java
index 135591c05..e9e44edb7 100644
--- a/src/com/android/gallery3d/app/MovieControllerOverlayNew.java
+++ b/src/com/android/gallery3d/app/MovieControllerOverlayNew.java
@@ -30,16 +30,21 @@
package com.android.gallery3d.app;
import android.content.Context;
+import android.graphics.Color;
import android.graphics.Rect;
import android.view.MotionEvent;
import android.view.View;
+import android.view.animation.Animation;
+import android.view.animation.AnimationUtils;
import android.widget.ImageView;
+import org.codeaurora.gallery3d.video.IVideoSnapshotListener;
+import org.codeaurora.gallery3d.video.IControllerRewindAndForward;
import com.android.gallery3d.R;
-import org.codeaurora.gallery3d.video.IControllerRewindAndForward;
-
public class MovieControllerOverlayNew extends MovieControllerOverlay {
+ private VideoSnapshotLayout mVideoSnapshotLayout = new VideoSnapshotLayout();
+ private IVideoSnapshotListener mVideoSnapshotListener;
private boolean mIsLive = false;
private ImageView mLiveImage;
@@ -49,6 +54,8 @@ public class MovieControllerOverlayNew extends MovieControllerOverlay {
public MovieControllerOverlayNew(Context context) {
super(context);
+
+ mVideoSnapshotLayout.init(context);
mLiveImage = ((MovieActivity) mContext).getLiveImage();
mStopBtn = mControllerRewindAndForwardExt.getStopBtn();
mLiveMargin = context.getResources().getDimensionPixelSize(
@@ -116,6 +123,13 @@ public class MovieControllerOverlayNew extends MovieControllerOverlay {
}
mTimeBar.layout(mTimeBar.getPreferredHeight(), y - mTimeBar.getPreferredHeight(),
width - mScreenModeExt.getAddedRightPadding(), y);
+
+ mVideoSnapshotLayout.layoutButton(
+ w - pr - mVideoSnapshotLayout.getButtonWidth(),
+ y - mTimeBar.getPreferredHeight() - mVideoSnapshotLayout.getButtonHeight(),
+ w - pr,
+ y - mTimeBar.getPreferredHeight());
+ mVideoSnapshotLayout.layoutAnim(left, top, right, bottom);
}
public void setLive(boolean live) {
@@ -134,4 +148,96 @@ public class MovieControllerOverlayNew extends MovieControllerOverlay {
return false;
}
+ public void setVideoSnapshotListener(IVideoSnapshotListener listener) {
+ mVideoSnapshotListener = listener;
+ }
+
+ public void showVideoSnapshotButton(boolean show) {
+ if (mVideoSnapshotLayout != null) {
+ mVideoSnapshotLayout.showVideoSnapshotButton(show);
+ }
+ }
+
+ class VideoSnapshotLayout implements View.OnClickListener {
+ private ImageView mVideoSnapshotButton;
+ private ImageView mVideoSnapshotAnimView;
+ private Animation mVideoSnapshotAnimation;
+
+ public void init(Context context) {
+ LayoutParams wrapContent =
+ new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
+ mVideoSnapshotButton = new ImageView(context);
+ mVideoSnapshotButton.setImageResource(R.drawable.ic_video_snapshot_padding);
+ mVideoSnapshotButton.setScaleType(ImageView.ScaleType.CENTER);
+ mVideoSnapshotButton.setFocusable(true);
+ mVideoSnapshotButton.setClickable(true);
+ mVideoSnapshotButton.setOnClickListener(this);
+ addView(mVideoSnapshotButton, wrapContent);
+
+ LayoutParams matchParent =
+ new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
+ mVideoSnapshotAnimView = new ImageView(context);
+ addView(mVideoSnapshotAnimView, matchParent);
+
+ mVideoSnapshotAnimation = AnimationUtils.loadAnimation(context, R.anim.player_out);
+ mVideoSnapshotAnimation.setAnimationListener(new Animation.AnimationListener() {
+ @Override
+ public void onAnimationStart(Animation animation) {
+ mVideoSnapshotAnimView.setBackgroundColor(Color.WHITE);
+ mVideoSnapshotButton.setEnabled(false);
+ }
+
+ @Override
+ public void onAnimationEnd(Animation animation) {
+ mVideoSnapshotAnimView.setBackgroundColor(Color.TRANSPARENT);
+ mVideoSnapshotButton.setEnabled(true);
+ }
+
+ @Override
+ public void onAnimationRepeat(Animation animation) {
+ }
+ });
+ }
+
+ public int getButtonWidth() {
+ return mVideoSnapshotButton == null ? 0 : mVideoSnapshotButton.getMeasuredWidth();
+ }
+
+ public int getButtonHeight() {
+ return mVideoSnapshotButton == null ? 0 : mVideoSnapshotButton.getMeasuredHeight();
+ }
+
+ public void layoutButton(int l, int t, int r, int b) {
+ if (mVideoSnapshotButton != null) {
+ mVideoSnapshotButton.layout(l, t, r, b);
+ }
+ }
+
+ public void layoutAnim(int l, int t, int r, int b) {
+ if (mVideoSnapshotAnimView != null) {
+ mVideoSnapshotAnimView.layout(l, t, r, b);
+ }
+ }
+
+ public void showVideoSnapshotButton(boolean show) {
+ if (mVideoSnapshotButton != null) {
+ mVideoSnapshotButton.setVisibility(show ? VISIBLE : GONE);
+ }
+ }
+
+ @Override
+ public void onClick(View v) {
+ maybeStartHiding();
+ if (mVideoSnapshotListener != null && mVideoSnapshotListener.canVideoSnapshot()) {
+ mVideoSnapshotListener.onVideoSnapshot();
+ startAnimation();
+ }
+ }
+
+ private void startAnimation() {
+ if (mVideoSnapshotAnimView != null) {
+ mVideoSnapshotAnimView.startAnimation(mVideoSnapshotAnimation);
+ }
+ }
+ }
}
diff --git a/src/com/android/gallery3d/app/MoviePlayer.java b/src/com/android/gallery3d/app/MoviePlayer.java
index 1f6401ee5..8581f80e8 100755
--- a/src/com/android/gallery3d/app/MoviePlayer.java
+++ b/src/com/android/gallery3d/app/MoviePlayer.java
@@ -62,6 +62,7 @@ import org.codeaurora.gallery3d.video.IControllerRewindAndForward.IRewindAndForw
import org.codeaurora.gallery3d.video.ScreenModeManager;
import org.codeaurora.gallery3d.video.ScreenModeManager.ScreenModeListener;
import org.codeaurora.gallery3d.video.CodeauroraVideoView;
+import org.codeaurora.gallery3d.video.VideoSnapshotExt;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
@@ -161,6 +162,8 @@ public class MoviePlayer implements
private IMovieItem mMovieItem;
private int mVideoLastDuration;//for duration displayed in init state
+ private VideoSnapshotExt mVideoSnapshotExt = new VideoSnapshotExt();
+
private enum TState {
PLAYING,
PAUSED,
@@ -364,6 +367,7 @@ public class MoviePlayer implements
}
}
mScreenModeExt.setScreenMode();
+ mVideoSnapshotExt.init(mController, mVideoView, isLocalFile());
}
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
diff --git a/src/com/android/gallery3d/app/TimeBar.java b/src/com/android/gallery3d/app/TimeBar.java
index aed8eeccc..f66dfdfcd 100755
--- a/src/com/android/gallery3d/app/TimeBar.java
+++ b/src/com/android/gallery3d/app/TimeBar.java
@@ -91,7 +91,7 @@ public class TimeBar extends View {
private ITimeBarSecondaryProgressExt mSecondaryProgressExt = new TimeBarSecondaryProgressExtImpl();
private ITimeBarInfoExt mInfoExt = new TimeBarInfoExtImpl();
- private ITimeBarLayoutExt mLayoutExt = new TimeBarLayoutExtImpl();
+ protected ITimeBarLayoutExt mLayoutExt = new TimeBarLayoutExtImpl();
public TimeBar(Context context, Listener listener) {
super(context);
diff --git a/src/com/android/gallery3d/app/TrimTimeBar.java b/src/com/android/gallery3d/app/TrimTimeBar.java
index 7e26b2860..8dad597a1 100644
--- a/src/com/android/gallery3d/app/TrimTimeBar.java
+++ b/src/com/android/gallery3d/app/TrimTimeBar.java
@@ -49,6 +49,9 @@ public class TrimTimeBar extends TimeBar {
private int mTrimStartTime;
private int mTrimEndTime;
+ private int mTimeBarMargin;
+ private int mTimeBarTimeMargin;
+
private final Bitmap mTrimStartScrubber;
private final Bitmap mTrimEndScrubber;
public TrimTimeBar(Context context, Listener listener) {
@@ -69,6 +72,9 @@ public class TrimTimeBar extends TimeBar {
// touch padding since we have 3 scrubbers now.
mScrubberPadding = 0;
mVPaddingInPx = mVPaddingInPx * 3 / 2;
+ mTimeBarMargin = context.getResources().getDimensionPixelSize(R.dimen.timebar_margin);
+ mTimeBarTimeMargin = context.getResources().
+ getDimensionPixelSize(R.dimen.timebar_time_margin);
}
private int getBarPosFromTime(int time) {
@@ -174,14 +180,14 @@ public class TrimTimeBar extends TimeBar {
if (mShowTimes) {
margin += mTimeBounds.width();
}
- int progressY = h / 4;
- int scrubberY = progressY - mScrubber.getHeight() / 2 + 1;
- mScrubberTop = scrubberY;
+ margin = mLayoutExt.getProgressMargin(margin);
+ int progressY = (h + mScrubberPadding) / 2;
mTrimStartScrubberTop = progressY;
mTrimEndScrubberTop = progressY;
+ mScrubberTop = progressY - mScrubber.getHeight() / 2 + 1;
mProgressBar.set(
- getPaddingLeft() + margin, progressY,
- w - getPaddingRight() - margin, progressY + 6);
+ mTimeBarMargin + margin, progressY,
+ w - mTimeBarMargin - margin, progressY + 6);
}
update();
}
@@ -191,18 +197,19 @@ public class TrimTimeBar extends TimeBar {
// draw progress bars
canvas.drawRect(mProgressBar, mProgressPaint);
canvas.drawRect(mPlayedBar, mPlayedPaint);
-
if (mShowTimes) {
- canvas.drawText(
- stringForTime(mTrimStartTime),
- mTimeBounds.width() / 2 + getPaddingLeft(),
- mTimeBounds.height() / 2 + mTrimStartScrubberTop,
- mTimeTextPaint);
- canvas.drawText(
- stringForTime(mTrimEndTime),
- getWidth() - getPaddingRight() - mTimeBounds.width() / 2,
- mTimeBounds.height() / 2 + mTrimStartScrubberTop,
- mTimeTextPaint);
+ canvas.drawText(
+ stringForTime(mCurrentTime),
+ mTimeBarTimeMargin,
+ mTimeBounds.height() + mVPaddingInPx / 2 + mScrubberPadding -
+ mLayoutExt.getProgressOffset(mTimeBounds),
+ mTimeTextPaint);
+ canvas.drawText(
+ stringForTime(mTotalTime),
+ getWidth() - mTimeBarTimeMargin,
+ mTimeBounds.height() + mVPaddingInPx / 2 + mScrubberPadding -
+ mLayoutExt.getProgressOffset(mTimeBounds),
+ mTimeTextPaint);
}
// draw extra scrubbers
diff --git a/src/com/android/gallery3d/app/TrimVideo.java b/src/com/android/gallery3d/app/TrimVideo.java
index 37da98a4e..6905e62d5 100644
--- a/src/com/android/gallery3d/app/TrimVideo.java
+++ b/src/com/android/gallery3d/app/TrimVideo.java
@@ -18,8 +18,10 @@ package com.android.gallery3d.app;
import android.app.ActionBar;
import android.app.Activity;
+import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.content.Context;
+import android.content.DialogInterface;
import android.content.Intent;
import android.media.MediaPlayer;
import android.net.Uri;
@@ -50,6 +52,7 @@ public class TrimVideo extends Activity implements
private TextView mSaveVideoTextView;
private ImageView mExitImageView;
private TrimControllerOverlay mController;
+ private AlertDialog mExitDialog;
private Context mContext;
private Uri mUri;
private final Handler mHandler = new Handler();
@@ -89,7 +92,26 @@ public class TrimVideo extends Activity implements
mExitImageView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
- finish();
+ mExitDialog = new AlertDialog.Builder(TrimVideo.this,
+ AlertDialog.THEME_DEVICE_DEFAULT_LIGHT).
+ setTitle(R.string.trim_video_exit_title).
+ setMessage(R.string.trim_video_exit_msg).
+ setPositiveButton(R.string.trim_video_exit_discard,
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ finish();
+ }
+ }).
+ setNegativeButton(R.string.review_cancel,
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ dialog.dismiss();
+ }
+ }).
+ create();
+ mExitDialog.show();
}
});
diff --git a/src/com/android/gallery3d/filtershow/cache/ImageLoader.java b/src/com/android/gallery3d/filtershow/cache/ImageLoader.java
index ea559e569..d8560312c 100644
--- a/src/com/android/gallery3d/filtershow/cache/ImageLoader.java
+++ b/src/com/android/gallery3d/filtershow/cache/ImageLoader.java
@@ -88,8 +88,7 @@ public final class ImageLoader {
return null;
}
int index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
- cursor.moveToFirst();
- return cursor.getString(index);
+ return cursor.moveToFirst() ? cursor.getString(index) : null;
}
/**
diff --git a/src/com/android/gallery3d/ui/MenuExecutor.java b/src/com/android/gallery3d/ui/MenuExecutor.java
index c4636cb38..e65649bcf 100644
--- a/src/com/android/gallery3d/ui/MenuExecutor.java
+++ b/src/com/android/gallery3d/ui/MenuExecutor.java
@@ -216,13 +216,16 @@ public class MenuExecutor {
private Path getSingleSelectedPath() {
ArrayList<Path> ids = mSelectionManager.getSelected(true);
- Utils.assertTrue(ids.size() == 1);
- return ids.get(0);
+ if (ids.size() != 1)
+ return null;
+ return ids.get(0);
}
private Intent getIntentBySingleSelectedPath(String action) {
DataManager manager = mActivity.getDataManager();
Path path = getSingleSelectedPath();
+ if (path == null)
+ return null;
String mimeType = getMimeType(manager.getMediaType(path));
return new Intent(action).setDataAndType(manager.getContentUri(path), mimeType);
}
@@ -248,26 +251,30 @@ public class MenuExecutor {
return;
}*/
case R.id.action_edit: {
- Intent intent = getIntentBySingleSelectedPath(Intent.ACTION_EDIT)
- .setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
- ((Activity) mActivity).startActivity(Intent.createChooser(intent, null));
+ Intent intent = getIntentBySingleSelectedPath(Intent.ACTION_EDIT);
+ if (intent != null) {
+ intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
+ ((Activity) mActivity).startActivity(Intent.createChooser(intent, null));
+ }
return;
}
case R.id.action_setas: {
- Intent intent = getIntentBySingleSelectedPath(Intent.ACTION_ATTACH_DATA)
- .addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
- intent.putExtra("mimeType", intent.getType());
-
- // DRM files can be set as wallpaper only. Don't show other options
- // to set as.
- Uri uri = intent.getData();
+ Intent intent = getIntentBySingleSelectedPath(Intent.ACTION_ATTACH_DATA);
+ if (intent != null) {
+ intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
+ intent.putExtra("mimeType", intent.getType());
+
+ // DRM files can be set as wallpaper only. Don't show other options
+ // to set as.
+ Uri uri = intent.getData();
// if (DrmHelper.isDrmFile(DrmHelper.getFilePath(mActivity, uri))) {
// intent.setPackage("com.android.gallery3d");
// }
- Activity activity = mActivity;
- activity.startActivity(Intent.createChooser(
- intent, activity.getString(R.string.set_as)));
+ Activity activity = mActivity;
+ activity.startActivity(Intent.createChooser(
+ intent, activity.getString(R.string.set_as)));
+ }
return;
}
case R.id.action_delete:
diff --git a/src/com/android/gallery3d/ui/TimeLineTitleMaker.java b/src/com/android/gallery3d/ui/TimeLineTitleMaker.java
index c154f369d..2b368753a 100755
--- a/src/com/android/gallery3d/ui/TimeLineTitleMaker.java
+++ b/src/com/android/gallery3d/ui/TimeLineTitleMaker.java
@@ -78,8 +78,6 @@ public class TimeLineTitleMaker {
static void drawText(Canvas canvas,
int x, int y, String text, int lengthLimit, TextPaint p) {
- text = TextUtils.ellipsize(
- text, p, lengthLimit, TextUtils.TruncateAt.END).toString();
canvas.drawText(text, x, y - p.getFontMetricsInt().ascent, p);
}
diff --git a/src/org/codeaurora/gallery3d/video/CodeauroraVideoView.java b/src/org/codeaurora/gallery3d/video/CodeauroraVideoView.java
index aae691d55..00ca80122 100644
--- a/src/org/codeaurora/gallery3d/video/CodeauroraVideoView.java
+++ b/src/org/codeaurora/gallery3d/video/CodeauroraVideoView.java
@@ -1102,4 +1102,12 @@ public class CodeauroraVideoView extends SurfaceView implements MediaPlayerContr
Log.v(TAG, "setOnBufferingUpdateListener(" + l + ")");
}
}
+
+ public MediaPlayer getMediaPlayer() {
+ return mMediaPlayer;
+ }
+
+ public Uri getUri() {
+ return mUri;
+ }
}
diff --git a/src/org/codeaurora/gallery3d/video/IVideoSnapshotListener.java b/src/org/codeaurora/gallery3d/video/IVideoSnapshotListener.java
new file mode 100644
index 000000000..b8675ce29
--- /dev/null
+++ b/src/org/codeaurora/gallery3d/video/IVideoSnapshotListener.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.codeaurora.gallery3d.video;
+
+public interface IVideoSnapshotListener {
+ void onVideoSnapshot();
+ boolean canVideoSnapshot();
+}
diff --git a/src/org/codeaurora/gallery3d/video/VideoSnapshotExt.java b/src/org/codeaurora/gallery3d/video/VideoSnapshotExt.java
new file mode 100644
index 000000000..7788e79d5
--- /dev/null
+++ b/src/org/codeaurora/gallery3d/video/VideoSnapshotExt.java
@@ -0,0 +1,220 @@
+/*
+ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.codeaurora.gallery3d.video;
+
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.media.MediaMetadataRetriever;
+import android.net.Uri;
+import android.os.AsyncTask;
+import android.os.Environment;
+import android.provider.MediaStore.Images;
+import android.provider.MediaStore.Images.ImageColumns;
+import android.util.Log;
+import com.android.gallery3d.R;
+import com.android.gallery3d.app.MovieControllerOverlay;
+import com.android.gallery3d.app.MovieControllerOverlayNew;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Locale;
+
+public class VideoSnapshotExt implements IVideoSnapshotListener {
+ private static String TAG = "VideoSnapshotExt";
+ private static final boolean DEBUG = false;
+
+ private static final String FOLDER = Environment.getExternalStorageDirectory() +
+ File.separator + "Pictures" + File.separator + "VideoSnapshots";
+ private static final String FILE_PREFIX = "VideoSnapshot_";
+ private static final String FILE_EXT = ".jpg";
+ private static final String TIME_STAMP_NAME = "yyyyMMdd_HHmmss";
+ private static final int CONTENT_VALUES_SIZE = 9;
+
+ private CodeauroraVideoView mVideoView;
+ private Context mContext;
+ private ContentResolver mContentResolver;
+
+ @Override
+ public void onVideoSnapshot() {
+ if (canVideoSnap()) {
+ int currentPosition = mVideoView.getMediaPlayer().getCurrentPosition();
+ doVideoSnap(mVideoView.getUri(), currentPosition);
+ }
+ }
+
+ @Override
+ public boolean canVideoSnapshot() {
+ return canVideoSnap();
+ }
+
+ public void init(MovieControllerOverlay controller, CodeauroraVideoView videoView,
+ boolean isLocalFile) {
+ mContext = videoView.getContext();
+ mContentResolver = mContext.getContentResolver();
+
+ mVideoView = videoView;
+ if (controller instanceof MovieControllerOverlayNew) {
+ ((MovieControllerOverlayNew) controller).showVideoSnapshotButton(isLocalFile);
+ ((MovieControllerOverlayNew) controller).setVideoSnapshotListener(this);
+ }
+ }
+
+ private boolean canVideoSnap() {
+ if (mVideoView.getMediaPlayer() == null) {
+ Log.w(TAG, "can't videoSnapshot because mMediaPlayer is null !");
+ return false;
+ }
+ return true;
+ }
+
+ private void doVideoSnap(Uri uri, int snapPosition) {
+ VideoSnapParameters parameters = new VideoSnapParameters(uri, snapPosition);
+ new VideoSnapTask().execute(parameters);
+ }
+
+ private class VideoSnapParameters {
+ private int mSnapPosition;
+ private Uri mUri;
+
+ /**
+ * @param snapPosition milliseconds
+ */
+ public VideoSnapParameters(Uri uri, int snapPosition) {
+ mUri = uri;
+ mSnapPosition = snapPosition;
+ }
+
+ public int getSnapPosition() {
+ return mSnapPosition;
+ }
+
+ public Uri getUri() {
+ return mUri;
+ }
+ }
+
+ private class VideoSnapTask extends AsyncTask<VideoSnapParameters, Void, Bitmap> {
+ SimpleDateFormat mDateFormat = new SimpleDateFormat(TIME_STAMP_NAME, Locale.getDefault());
+ @Override
+ protected Bitmap doInBackground(VideoSnapParameters... params) {
+ VideoSnapParameters parameters = params[0];
+ return doVideoSnap(parameters.getUri(), parameters.getSnapPosition());
+ }
+
+ @Override
+ protected void onPostExecute(Bitmap result) {
+ if (result != null) {
+ saveVideoSnap(mContentResolver, result);
+ }
+ }
+
+ private boolean isPositionValid(int currentPosition, long duration) {
+ return (currentPosition <= duration) && (currentPosition >= 0);
+ }
+
+ private Bitmap doVideoSnap(Uri videoUri, int snapPosition) {
+ MediaMetadataRetriever retriever = new MediaMetadataRetriever();
+ retriever.setDataSource(mContext, videoUri);
+ String durationString =
+ retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION);
+ long duration =
+ (durationString == null) ? 0 : Long.parseLong(durationString); // milliseconds
+ if (DEBUG) {
+ Log.d(TAG, "doVideoSnap at " + snapPosition + "/" + duration);
+ }
+ if (isPositionValid(snapPosition, duration)) {
+ // convert ms to us.
+ Bitmap bitmap = retriever.getFrameAtTime(snapPosition * 1000,
+ MediaMetadataRetriever.OPTION_CLOSEST);
+ if (bitmap == null) {
+ Log.w(TAG, "frame cannot be retrieved. ");
+ } else {
+ retriever.release();
+ if (DEBUG) {
+ Log.d(TAG, "retriever get frame resolution : " +
+ bitmap.getHeight() + "x" + bitmap.getWidth());
+ }
+ return bitmap;
+ }
+ }
+ retriever.release();
+ return null;
+ }
+
+ private void saveVideoSnap(ContentResolver resolver, Bitmap videoSnap) {
+ File folder = new File(FOLDER);
+ if (!folder.exists()) {
+ folder.mkdirs();
+ }
+
+ long dateTaken = System.currentTimeMillis();
+ String fileName = mDateFormat.format(new Date(dateTaken));
+ String fileTitle = FILE_PREFIX + fileName;
+ File file = new File(folder, fileTitle + FILE_EXT);
+
+ try {
+ FileOutputStream fos = new FileOutputStream(file);
+ videoSnap.compress(Bitmap.CompressFormat.JPEG, 85, fos);
+ fos.close();
+
+ addImage(resolver, file.getPath(), fileTitle, dateTaken, file.length(), 0,
+ videoSnap.getWidth(), videoSnap.getHeight());
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ private static void addImage(ContentResolver resolver, String path, String title, long date,
+ long size, int orientation, int width, int height) {
+ // Insert into MediaStore.
+ ContentValues values = new ContentValues(CONTENT_VALUES_SIZE);
+ values.put(ImageColumns.TITLE, title);
+ values.put(ImageColumns.DISPLAY_NAME, title + ".jpg");
+ values.put(ImageColumns.DATE_TAKEN, date);
+ values.put(ImageColumns.MIME_TYPE, "image/jpeg");
+ values.put(ImageColumns.ORIENTATION, orientation);
+ values.put(ImageColumns.DATA, path);
+ values.put(ImageColumns.SIZE, size);
+ values.put(ImageColumns.WIDTH, width);
+ values.put(ImageColumns.HEIGHT, height);
+
+ try {
+ resolver.insert(Images.Media.EXTERNAL_CONTENT_URI, values);
+ } catch (Throwable th) {
+ Log.w(TAG, "Failed to write MediaStore" + th);
+ }
+ }
+}