summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/com/android/gallery3d/app/AbstractGalleryActivity.java8
-rw-r--r--src/com/android/gallery3d/app/ActivityState.java37
-rw-r--r--src/com/android/gallery3d/app/AlbumPage.java18
-rw-r--r--src/com/android/gallery3d/app/AlbumSetPage.java14
-rw-r--r--src/com/android/gallery3d/app/CommonControllerOverlay.java2
-rw-r--r--src/com/android/gallery3d/app/CropImage.java12
-rw-r--r--src/com/android/gallery3d/app/FilmstripPage.java21
-rw-r--r--src/com/android/gallery3d/app/Gallery.java11
-rw-r--r--src/com/android/gallery3d/app/GalleryActionBar.java16
-rw-r--r--src/com/android/gallery3d/app/MovieActivity.java22
-rw-r--r--src/com/android/gallery3d/app/MoviePlayer.java3
-rw-r--r--src/com/android/gallery3d/app/MuteVideo.java104
-rw-r--r--src/com/android/gallery3d/app/PhotoPage.java28
-rw-r--r--src/com/android/gallery3d/app/PickerActivity.java10
-rw-r--r--src/com/android/gallery3d/app/SinglePhotoDataAdapter.java1
-rw-r--r--src/com/android/gallery3d/app/SinglePhotoPage.java21
-rw-r--r--src/com/android/gallery3d/app/StateManager.java4
-rw-r--r--src/com/android/gallery3d/app/TrimControllerOverlay.java51
-rw-r--r--src/com/android/gallery3d/app/TrimVideo.java150
-rw-r--r--src/com/android/gallery3d/app/VideoUtils.java (renamed from src/com/android/gallery3d/app/TrimVideoUtils.java)58
-rw-r--r--src/com/android/gallery3d/data/Exif.java161
-rw-r--r--src/com/android/gallery3d/data/LocalAlbum.java4
-rw-r--r--src/com/android/gallery3d/data/LocalMergeAlbum.java5
-rw-r--r--src/com/android/gallery3d/data/LocalVideo.java2
-rw-r--r--src/com/android/gallery3d/data/MediaDetails.java60
-rw-r--r--src/com/android/gallery3d/data/MediaObject.java1
-rw-r--r--src/com/android/gallery3d/filtershow/FilterShowActivity.java9
-rw-r--r--src/com/android/gallery3d/filtershow/cache/ImageLoader.java25
-rw-r--r--src/com/android/gallery3d/filtershow/imageshow/ImageShow.java3
-rw-r--r--src/com/android/gallery3d/ui/ActionModeHandler.java25
-rw-r--r--src/com/android/gallery3d/ui/MenuExecutor.java7
-rw-r--r--src/com/android/gallery3d/ui/PopupList.java2
-rw-r--r--src/com/android/gallery3d/ui/PositionController.java8
-rw-r--r--src/com/android/gallery3d/util/AccessibilityUtils.java54
-rw-r--r--src/com/android/gallery3d/util/SaveVideoFileInfo.java29
-rw-r--r--src/com/android/gallery3d/util/SaveVideoFileUtils.java141
36 files changed, 702 insertions, 425 deletions
diff --git a/src/com/android/gallery3d/app/AbstractGalleryActivity.java b/src/com/android/gallery3d/app/AbstractGalleryActivity.java
index 88ac028e1..8f824cfd2 100644
--- a/src/com/android/gallery3d/app/AbstractGalleryActivity.java
+++ b/src/com/android/gallery3d/app/AbstractGalleryActivity.java
@@ -17,7 +17,6 @@
package com.android.gallery3d.app;
import android.annotation.TargetApi;
-import android.app.Activity;
import android.app.AlertDialog;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -28,11 +27,12 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.content.res.Configuration;
import android.os.Bundle;
-import android.view.Menu;
-import android.view.MenuItem;
import android.view.Window;
import android.view.WindowManager;
+import com.actionbarsherlock.app.SherlockActivity;
+import com.actionbarsherlock.view.Menu;
+import com.actionbarsherlock.view.MenuItem;
import com.android.gallery3d.R;
import com.android.gallery3d.common.ApiHelper;
import com.android.gallery3d.data.BitmapPool;
@@ -43,7 +43,7 @@ import com.android.gallery3d.ui.GLRootView;
import com.android.gallery3d.util.ThreadPool;
import com.android.gallery3d.util.LightCycleHelper.PanoramaViewHelper;
-public class AbstractGalleryActivity extends Activity implements GalleryContext {
+public class AbstractGalleryActivity extends SherlockActivity implements GalleryContext {
@SuppressWarnings("unused")
private static final String TAG = "AbstractGalleryActivity";
private GLRootView mGLRootView;
diff --git a/src/com/android/gallery3d/app/ActivityState.java b/src/com/android/gallery3d/app/ActivityState.java
index cdd91ff4d..b2e39b1cb 100644
--- a/src/com/android/gallery3d/app/ActivityState.java
+++ b/src/com/android/gallery3d/app/ActivityState.java
@@ -16,24 +16,23 @@
package com.android.gallery3d.app;
-import android.app.ActionBar;
import android.app.Activity;
import android.content.BroadcastReceiver;
-import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.res.Configuration;
import android.os.BatteryManager;
import android.os.Bundle;
-import android.provider.Settings;
-import android.provider.Settings.SettingNotFoundException;
-import android.view.Menu;
-import android.view.MenuInflater;
-import android.view.MenuItem;
+import android.view.HapticFeedbackConstants;
import android.view.Window;
import android.view.WindowManager;
+import com.actionbarsherlock.app.ActionBar;
+import com.actionbarsherlock.app.SherlockActivity;
+import com.actionbarsherlock.view.Menu;
+import com.actionbarsherlock.view.MenuInflater;
+import com.actionbarsherlock.view.MenuItem;
import com.android.gallery3d.R;
import com.android.gallery3d.anim.StateTransitionAnimation;
import com.android.gallery3d.ui.GLView;
@@ -62,9 +61,6 @@ abstract public class ActivityState {
public Intent resultData;
}
- protected boolean mHapticsEnabled;
- private ContentResolver mContentResolver;
-
private boolean mDestroyed = false;
private boolean mPlugged = false;
boolean mIsFinishing = false;
@@ -92,7 +88,6 @@ abstract public class ActivityState {
void initialize(AbstractGalleryActivity activity, Bundle data) {
mActivity = activity;
mData = data;
- mContentResolver = activity.getAndroidContext().getContentResolver();
}
public Bundle getData() {
@@ -175,15 +170,20 @@ abstract public class ActivityState {
protected void transitionOnNextPause(Class<? extends ActivityState> outgoing,
Class<? extends ActivityState> incoming, StateTransitionAnimation.Transition hint) {
- if (outgoing == PhotoPage.class && incoming == AlbumPage.class) {
+ if (outgoing == SinglePhotoPage.class && incoming == AlbumPage.class) {
mNextTransition = StateTransitionAnimation.Transition.Outgoing;
- } else if (outgoing == AlbumPage.class && incoming == PhotoPage.class) {
+ } else if (outgoing == AlbumPage.class && incoming == SinglePhotoPage.class) {
mNextTransition = StateTransitionAnimation.Transition.PhotoIncoming;
} else {
mNextTransition = hint;
}
}
+ protected void performHapticFeedback(int feedbackConstant) {
+ mActivity.getWindow().getDecorView().performHapticFeedback(feedbackConstant,
+ HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING);
+ }
+
protected void onPause() {
if (0 != (mFlags & FLAG_SCREEN_ON_WHEN_PLUGGED)) {
((Activity) mActivity).unregisterReceiver(mPowerIntentReceiver);
@@ -198,7 +198,7 @@ abstract public class ActivityState {
// should only be called by StateManager
void resume() {
AbstractGalleryActivity activity = mActivity;
- ActionBar actionBar = activity.getActionBar();
+ ActionBar actionBar = ((SherlockActivity) activity).getSupportActionBar();
if (actionBar != null) {
if ((mFlags & FLAG_HIDE_ACTION_BAR) != 0) {
actionBar.hide();
@@ -231,13 +231,6 @@ abstract public class ActivityState {
activity.registerReceiver(mPowerIntentReceiver, filter);
}
- try {
- mHapticsEnabled = Settings.System.getInt(mContentResolver,
- Settings.System.HAPTIC_FEEDBACK_ENABLED) != 0;
- } catch (SettingNotFoundException e) {
- mHapticsEnabled = false;
- }
-
onResume();
// the transition store should be cleared after resume;
@@ -279,6 +272,6 @@ abstract public class ActivityState {
}
protected MenuInflater getSupportMenuInflater() {
- return mActivity.getMenuInflater();
+ return ((SherlockActivity) mActivity).getSupportMenuInflater();
}
}
diff --git a/src/com/android/gallery3d/app/AlbumPage.java b/src/com/android/gallery3d/app/AlbumPage.java
index ee7a107fd..e1c061318 100644
--- a/src/com/android/gallery3d/app/AlbumPage.java
+++ b/src/com/android/gallery3d/app/AlbumPage.java
@@ -24,13 +24,13 @@ import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
-import android.os.Vibrator;
import android.provider.MediaStore;
-import android.view.Menu;
-import android.view.MenuInflater;
-import android.view.MenuItem;
+import android.view.HapticFeedbackConstants;
import android.widget.Toast;
+import com.actionbarsherlock.view.Menu;
+import com.actionbarsherlock.view.MenuInflater;
+import com.actionbarsherlock.view.MenuItem;
import com.android.gallery3d.R;
import com.android.gallery3d.common.Utils;
import com.android.gallery3d.data.DataManager;
@@ -89,7 +89,6 @@ public class AlbumPage extends ActivityState implements GalleryActionBar.Cluster
private AlbumDataLoader mAlbumDataAdapter;
protected SelectionManager mSelectionManager;
- private Vibrator mVibrator;
private boolean mGetContent;
private boolean mShowClusterMenu;
@@ -304,10 +303,10 @@ public class AlbumPage extends ActivityState implements GalleryActionBar.Cluster
startInFilmstrip);
data.putBoolean(PhotoPage.KEY_IN_CAMERA_ROLL, mMediaSet.isCameraRoll());
if (startInFilmstrip) {
- mActivity.getStateManager().switchState(this, PhotoPage.class, data);
+ mActivity.getStateManager().switchState(this, FilmstripPage.class, data);
} else {
mActivity.getStateManager().startStateForResult(
- PhotoPage.class, REQUEST_PHOTO, data);
+ SinglePhotoPage.class, REQUEST_PHOTO, data);
}
}
}
@@ -371,7 +370,6 @@ public class AlbumPage extends ActivityState implements GalleryActionBar.Cluster
mShowClusterMenu = data.getBoolean(KEY_SHOW_CLUSTER_MENU, false);
mDetailsSource = new MyDetailsSource();
Context context = mActivity.getAndroidContext();
- mVibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
// Enable auto-select-all for mtp album
if (data.getBoolean(KEY_AUTO_SELECT_ALL)) {
@@ -379,7 +377,7 @@ public class AlbumPage extends ActivityState implements GalleryActionBar.Cluster
}
mLaunchedFromPhotoPage =
- mActivity.getStateManager().hasStateClass(PhotoPage.class);
+ mActivity.getStateManager().hasStateClass(FilmstripPage.class);
mInCameraApp = data.getBoolean(PhotoPage.KEY_APP_BRIDGE, false);
mHandler = new SynchronizedHandler(mActivity.getGLRoot()) {
@@ -662,7 +660,7 @@ public class AlbumPage extends ActivityState implements GalleryActionBar.Cluster
switch (mode) {
case SelectionManager.ENTER_SELECTION_MODE: {
mActionModeHandler.startActionMode();
- if (mHapticsEnabled) mVibrator.vibrate(100);
+ performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
break;
}
case SelectionManager.LEAVE_SELECTION_MODE: {
diff --git a/src/com/android/gallery3d/app/AlbumSetPage.java b/src/com/android/gallery3d/app/AlbumSetPage.java
index cae606be1..ed06f46ae 100644
--- a/src/com/android/gallery3d/app/AlbumSetPage.java
+++ b/src/com/android/gallery3d/app/AlbumSetPage.java
@@ -23,16 +23,16 @@ import android.graphics.Rect;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
-import android.os.Vibrator;
-import android.view.Menu;
-import android.view.MenuInflater;
-import android.view.MenuItem;
+import android.view.HapticFeedbackConstants;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.RelativeLayout;
import android.widget.Toast;
+import com.actionbarsherlock.view.Menu;
+import com.actionbarsherlock.view.MenuInflater;
+import com.actionbarsherlock.view.MenuItem;
import com.android.gallery3d.R;
import com.android.gallery3d.common.Utils;
import com.android.gallery3d.data.DataManager;
@@ -92,7 +92,6 @@ public class AlbumSetPage extends ActivityState implements
private boolean mShowClusterMenu;
private GalleryActionBar mActionBar;
private int mSelectedAction;
- private Vibrator mVibrator;
protected SelectionManager mSelectionManager;
private AlbumSetDataLoader mAlbumSetDataAdapter;
@@ -275,7 +274,7 @@ public class AlbumSetPage extends ActivityState implements
data.putBoolean(PhotoPage.KEY_START_IN_FILMSTRIP, true);
data.putBoolean(PhotoPage.KEY_IN_CAMERA_ROLL, targetSet.isCameraRoll());
mActivity.getStateManager().startStateForResult(
- PhotoPage.class, AlbumPage.REQUEST_PHOTO, data);
+ FilmstripPage.class, AlbumPage.REQUEST_PHOTO, data);
return;
}
data.putString(AlbumPage.KEY_MEDIA_PATH, mediaPath);
@@ -332,7 +331,6 @@ public class AlbumSetPage extends ActivityState implements
mSubtitle = data.getString(AlbumSetPage.KEY_SET_SUBTITLE);
mEyePosition = new EyePosition(context, this);
mDetailsSource = new MyDetailsSource();
- mVibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
mActionBar = mActivity.getGalleryActionBar();
mSelectedAction = data.getInt(AlbumSetPage.KEY_SELECTED_CLUSTER_TYPE,
FilterUtils.CLUSTER_BY_ALBUM);
@@ -655,7 +653,7 @@ public class AlbumSetPage extends ActivityState implements
case SelectionManager.ENTER_SELECTION_MODE: {
mActionBar.disableClusterMenu(true);
mActionModeHandler.startActionMode();
- if (mHapticsEnabled) mVibrator.vibrate(100);
+ performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
break;
}
case SelectionManager.LEAVE_SELECTION_MODE: {
diff --git a/src/com/android/gallery3d/app/CommonControllerOverlay.java b/src/com/android/gallery3d/app/CommonControllerOverlay.java
index ab43dada5..089872fa5 100644
--- a/src/com/android/gallery3d/app/CommonControllerOverlay.java
+++ b/src/com/android/gallery3d/app/CommonControllerOverlay.java
@@ -154,7 +154,7 @@ public abstract class CommonControllerOverlay extends FrameLayout implements
@Override
public void showEnded() {
mState = State.ENDED;
- showMainView(mPlayPauseReplayView);
+ if (mCanReplay) showMainView(mPlayPauseReplayView);
}
@Override
diff --git a/src/com/android/gallery3d/app/CropImage.java b/src/com/android/gallery3d/app/CropImage.java
index 89ca63d44..e7e95fdaa 100644
--- a/src/com/android/gallery3d/app/CropImage.java
+++ b/src/com/android/gallery3d/app/CropImage.java
@@ -17,7 +17,6 @@
package com.android.gallery3d.app;
import android.annotation.TargetApi;
-import android.app.ActionBar;
import android.app.ProgressDialog;
import android.app.WallpaperManager;
import android.content.ContentValues;
@@ -40,12 +39,13 @@ import android.os.Message;
import android.provider.MediaStore;
import android.provider.MediaStore.Images;
import android.util.FloatMath;
-import android.view.Menu;
-import android.view.MenuItem;
-import android.view.Window;
import android.view.WindowManager;
import android.widget.Toast;
+import com.actionbarsherlock.app.ActionBar;
+import com.actionbarsherlock.view.Menu;
+import com.actionbarsherlock.view.MenuItem;
+import com.actionbarsherlock.view.Window;
import com.android.camera.Util;
import com.android.gallery3d.R;
import com.android.gallery3d.common.ApiHelper;
@@ -172,7 +172,7 @@ public class CropImage extends AbstractGalleryActivity {
mCropView = new CropView(this);
getGLRoot().setContentPane(mCropView);
- ActionBar actionBar = getActionBar();
+ ActionBar actionBar = getSupportActionBar();
int displayOptions = ActionBar.DISPLAY_HOME_AS_UP
| ActionBar.DISPLAY_SHOW_TITLE;
actionBar.setDisplayOptions(displayOptions, displayOptions);
@@ -235,7 +235,7 @@ public class CropImage extends AbstractGalleryActivity {
@Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
- getMenuInflater().inflate(R.menu.crop, menu);
+ getSupportMenuInflater().inflate(R.menu.crop, menu);
return true;
}
diff --git a/src/com/android/gallery3d/app/FilmstripPage.java b/src/com/android/gallery3d/app/FilmstripPage.java
new file mode 100644
index 000000000..a9726cdc9
--- /dev/null
+++ b/src/com/android/gallery3d/app/FilmstripPage.java
@@ -0,0 +1,21 @@
+/*
+ * 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;
+
+public class FilmstripPage extends PhotoPage {
+
+}
diff --git a/src/com/android/gallery3d/app/Gallery.java b/src/com/android/gallery3d/app/Gallery.java
index e28404fac..354e325d4 100644
--- a/src/com/android/gallery3d/app/Gallery.java
+++ b/src/com/android/gallery3d/app/Gallery.java
@@ -26,10 +26,9 @@ import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.provider.OpenableColumns;
-import android.view.Window;
-import android.view.WindowManager;
import android.widget.Toast;
+import com.actionbarsherlock.view.Window;
import com.android.gallery3d.R;
import com.android.gallery3d.common.Utils;
import com.android.gallery3d.data.DataManager;
@@ -49,7 +48,6 @@ public final class Gallery extends AbstractGalleryActivity implements OnCancelLi
public static final String KEY_GET_ALBUM = "get-album";
public static final String KEY_TYPE_BITS = "type-bits";
public static final String KEY_MEDIA_TYPES = "mediaTypes";
- public static final String KEY_DISMISS_KEYGUARD = "dismiss-keyguard";
private static final String TAG = "Gallery";
private Dialog mVersionCheckDialog;
@@ -60,11 +58,6 @@ public final class Gallery extends AbstractGalleryActivity implements OnCancelLi
requestWindowFeature(Window.FEATURE_ACTION_BAR);
requestWindowFeature(Window.FEATURE_ACTION_BAR_OVERLAY);
- if (getIntent().getBooleanExtra(KEY_DISMISS_KEYGUARD, false)) {
- getWindow().addFlags(
- WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);
- }
-
setContentView(R.layout.main);
if (savedInstanceState != null) {
@@ -222,7 +215,7 @@ public final class Gallery extends AbstractGalleryActivity implements OnCancelLi
}
}
- getStateManager().startState(PhotoPage.class, data);
+ getStateManager().startState(SinglePhotoPage.class, data);
}
}
}
diff --git a/src/com/android/gallery3d/app/GalleryActionBar.java b/src/com/android/gallery3d/app/GalleryActionBar.java
index 0fb5e51b4..49f4186e8 100644
--- a/src/com/android/gallery3d/app/GalleryActionBar.java
+++ b/src/com/android/gallery3d/app/GalleryActionBar.java
@@ -17,9 +17,6 @@
package com.android.gallery3d.app;
import android.annotation.TargetApi;
-import android.app.ActionBar;
-import android.app.ActionBar.OnMenuVisibilityListener;
-import android.app.ActionBar.OnNavigationListener;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
@@ -27,15 +24,18 @@ import android.content.DialogInterface;
import android.content.Intent;
import android.content.res.Resources;
import android.view.LayoutInflater;
-import android.view.Menu;
-import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
-import android.widget.ShareActionProvider;
import android.widget.TextView;
import android.widget.TwoLineListItem;
+import com.actionbarsherlock.app.ActionBar;
+import com.actionbarsherlock.app.ActionBar.OnMenuVisibilityListener;
+import com.actionbarsherlock.app.ActionBar.OnNavigationListener;
+import com.actionbarsherlock.view.Menu;
+import com.actionbarsherlock.view.MenuItem;
+import com.actionbarsherlock.widget.ShareActionProvider;
import com.android.gallery3d.R;
import com.android.gallery3d.common.ApiHelper;
@@ -186,7 +186,7 @@ public class GalleryActionBar implements OnNavigationListener {
}
public GalleryActionBar(AbstractGalleryActivity activity) {
- mActionBar = activity.getActionBar();
+ mActionBar = activity.getSupportActionBar();
mContext = activity.getAndroidContext();
mActivity = activity;
mInflater = ((Activity) mActivity).getLayoutInflater();
@@ -396,7 +396,7 @@ public class GalleryActionBar implements OnNavigationListener {
private Intent mShareIntent;
public void createActionBarMenu(int menuRes, Menu menu) {
- mActivity.getMenuInflater().inflate(menuRes, menu);
+ mActivity.getSupportMenuInflater().inflate(menuRes, menu);
mActionBarMenu = menu;
MenuItem item = menu.findItem(R.id.action_share_panorama);
diff --git a/src/com/android/gallery3d/app/MovieActivity.java b/src/com/android/gallery3d/app/MovieActivity.java
index 3123644c7..d725e6d12 100644
--- a/src/com/android/gallery3d/app/MovieActivity.java
+++ b/src/com/android/gallery3d/app/MovieActivity.java
@@ -17,8 +17,6 @@
package com.android.gallery3d.app;
import android.annotation.TargetApi;
-import android.app.ActionBar;
-import android.app.Activity;
import android.content.AsyncQueryHandler;
import android.content.ContentResolver;
import android.content.Intent;
@@ -33,13 +31,15 @@ import android.os.Bundle;
import android.provider.MediaStore;
import android.provider.OpenableColumns;
import android.view.KeyEvent;
-import android.view.Menu;
-import android.view.MenuItem;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
-import android.widget.ShareActionProvider;
+import com.actionbarsherlock.app.ActionBar;
+import com.actionbarsherlock.app.SherlockActivity;
+import com.actionbarsherlock.view.Menu;
+import com.actionbarsherlock.view.MenuItem;
+import com.actionbarsherlock.widget.ShareActionProvider;
import com.android.gallery3d.R;
import com.android.gallery3d.common.ApiHelper;
import com.android.gallery3d.common.Utils;
@@ -51,7 +51,7 @@ import com.android.gallery3d.common.Utils;
* to set the action bar logo so the playback process looks more seamlessly integrated with
* the original activity.
*/
-public class MovieActivity extends Activity {
+public class MovieActivity extends SherlockActivity {
@SuppressWarnings("unused")
private static final String TAG = "MovieActivity";
public static final String KEY_LOGO_BITMAP = "logo-bitmap";
@@ -75,8 +75,8 @@ public class MovieActivity extends Activity {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- requestWindowFeature(Window.FEATURE_ACTION_BAR);
- requestWindowFeature(Window.FEATURE_ACTION_BAR_OVERLAY);
+ getSherlock().requestFeature(Window.FEATURE_ACTION_BAR);
+ getSherlock().requestFeature(Window.FEATURE_ACTION_BAR_OVERLAY);
setContentView(R.layout.movie_view);
View rootView = findViewById(R.id.movie_view_root);
@@ -119,14 +119,14 @@ public class MovieActivity extends Activity {
private void setActionBarLogoFromIntent(Intent intent) {
Bitmap logo = intent.getParcelableExtra(KEY_LOGO_BITMAP);
if (logo != null) {
- getActionBar().setLogo(
+ getSupportActionBar().setLogo(
new BitmapDrawable(getResources(), logo));
}
}
private void initializeActionBar(Intent intent) {
mUri = intent.getData();
- final ActionBar actionBar = getActionBar();
+ final ActionBar actionBar = getSupportActionBar();
setActionBarLogoFromIntent(intent);
actionBar.setDisplayOptions(
ActionBar.DISPLAY_HOME_AS_UP,
@@ -166,7 +166,7 @@ public class MovieActivity extends Activity {
@Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
- getMenuInflater().inflate(R.menu.movie, menu);
+ getSupportMenuInflater().inflate(R.menu.movie, menu);
// Document says EXTRA_STREAM should be a content: Uri
// So, we only share the video if it's "content:".
diff --git a/src/com/android/gallery3d/app/MoviePlayer.java b/src/com/android/gallery3d/app/MoviePlayer.java
index 85dc4427e..00e4cd63b 100644
--- a/src/com/android/gallery3d/app/MoviePlayer.java
+++ b/src/com/android/gallery3d/app/MoviePlayer.java
@@ -74,8 +74,8 @@ public class MoviePlayer implements
private static final long RESUMEABLE_TIMEOUT = 3 * 60 * 1000; // 3 mins
private Context mContext;
- private final View mRootView;
private final VideoView mVideoView;
+ private final View mRootView;
private final Bookmarker mBookmarker;
private final Uri mUri;
private final Handler mHandler = new Handler();
@@ -191,7 +191,6 @@ public class MoviePlayer implements
if ((diff & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) != 0
&& (visibility & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0) {
mController.show();
- mRootView.setBackgroundColor(Color.BLACK);
}
}
});
diff --git a/src/com/android/gallery3d/app/MuteVideo.java b/src/com/android/gallery3d/app/MuteVideo.java
new file mode 100644
index 000000000..012b682ef
--- /dev/null
+++ b/src/com/android/gallery3d/app/MuteVideo.java
@@ -0,0 +1,104 @@
+/*
+ * 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.Activity;
+import android.app.ProgressDialog;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Handler;
+import android.provider.MediaStore;
+import android.widget.Toast;
+
+import com.android.gallery3d.R;
+import com.android.gallery3d.data.MediaItem;
+import com.android.gallery3d.util.SaveVideoFileInfo;
+import com.android.gallery3d.util.SaveVideoFileUtils;
+
+import java.io.IOException;
+
+public class MuteVideo {
+
+ private ProgressDialog mMuteProgress;
+
+ private MediaItem mCurrentItem = null;
+ private Uri mUri = null;
+ private SaveVideoFileInfo mDstFileInfo = null;
+ private Activity mActivity = null;
+ private final Handler mHandler = new Handler();
+
+ final String TIME_STAMP_NAME = "'MUTE'_yyyyMMdd_HHmmss";
+
+ public MuteVideo(MediaItem current, Uri uri, Activity activity) {
+ mUri = uri;
+ mCurrentItem = current;
+ mActivity = activity;
+ }
+
+ public void muteInBackground() {
+ mDstFileInfo = SaveVideoFileUtils.getDstMp4FileInfo(TIME_STAMP_NAME,
+ mActivity.getContentResolver(), mUri,
+ mActivity.getString(R.string.folder_download));
+
+ showProgressDialog();
+ new Thread(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ VideoUtils.startMute(mCurrentItem.getFilePath(), mDstFileInfo);
+ SaveVideoFileUtils.insertContent(
+ mDstFileInfo, mActivity.getContentResolver(), mUri);
+ } catch (IOException e) {
+ Toast.makeText(mActivity, mActivity.getString(R.string.video_mute_err),
+ Toast.LENGTH_SHORT).show();
+ }
+ // After muting is done, trigger the UI changed.
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ Toast.makeText(mActivity.getApplicationContext(),
+ mActivity.getString(R.string.save_into,
+ mDstFileInfo.mFolderName),
+ Toast.LENGTH_SHORT)
+ .show();
+
+ if (mMuteProgress != null) {
+ mMuteProgress.dismiss();
+ mMuteProgress = 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);
+ mActivity.startActivity(intent);
+ }
+ }
+ });
+ }
+ }).start();
+ }
+
+ private void showProgressDialog() {
+ mMuteProgress = new ProgressDialog(mActivity);
+ mMuteProgress.setTitle(mActivity.getString(R.string.muting));
+ mMuteProgress.setMessage(mActivity.getString(R.string.please_wait));
+ mMuteProgress.setCancelable(false);
+ mMuteProgress.setCanceledOnTouchOutside(false);
+ mMuteProgress.show();
+ }
+}
diff --git a/src/com/android/gallery3d/app/PhotoPage.java b/src/com/android/gallery3d/app/PhotoPage.java
index b43cf2a70..76e050a75 100644
--- a/src/com/android/gallery3d/app/PhotoPage.java
+++ b/src/com/android/gallery3d/app/PhotoPage.java
@@ -17,7 +17,6 @@
package com.android.gallery3d.app;
import android.annotation.TargetApi;
-import android.app.ActionBar.OnMenuVisibilityListener;
import android.app.Activity;
import android.content.ActivityNotFoundException;
import android.content.Context;
@@ -32,13 +31,15 @@ import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.SystemClock;
-import android.view.Menu;
-import android.view.MenuItem;
import android.widget.RelativeLayout;
import android.widget.Toast;
import com.android.camera.CameraActivity;
import com.android.camera.ProxyLauncher;
+
+import com.actionbarsherlock.app.ActionBar.OnMenuVisibilityListener;
+import com.actionbarsherlock.view.Menu;
+import com.actionbarsherlock.view.MenuItem;
import com.android.gallery3d.R;
import com.android.gallery3d.common.ApiHelper;
import com.android.gallery3d.data.ComboAlbum;
@@ -71,7 +72,7 @@ import com.android.gallery3d.ui.SelectionManager;
import com.android.gallery3d.ui.SynchronizedHandler;
import com.android.gallery3d.util.GalleryUtils;
-public class PhotoPage extends ActivityState implements
+public abstract class PhotoPage extends ActivityState implements
PhotoView.Listener, AppBridge.Server,
PhotoPageBottomControls.Delegate, GalleryActionBar.OnAlbumModeSelectedListener {
private static final String TAG = "PhotoPage";
@@ -1017,11 +1018,16 @@ public class PhotoPage extends ActivityState implements
refreshHidingMessage();
MediaItem current = mModel.getMediaItem(0);
+ // This is a shield for monkey when it clicks the action bar
+ // menu when transitioning from filmstrip to camera
+ if (current instanceof SnailItem) return true;
+ // TODO: We should check the current photo against the MediaItem
+ // that the menu was initially created for. We need to fix this
+ // after PhotoPage being refactored.
if (current == null) {
// item is not ready, ignore
return true;
}
-
int currentIndex = mModel.getCurrentIndex();
Path path = current.getPath();
@@ -1062,6 +1068,12 @@ public class PhotoPage extends ActivityState implements
mActivity.startActivityForResult(intent, REQUEST_TRIM);
return true;
}
+ case R.id.action_mute: {
+ MuteVideo muteVideo = new MuteVideo(current,
+ manager.getContentUri(path), mActivity);
+ muteVideo.muteInBackground();
+ return true;
+ }
case R.id.action_edit: {
launchPhotoEditor();
return true;
@@ -1154,9 +1166,7 @@ public class PhotoPage extends ActivityState implements
} else if (goBack) {
onBackPressed();
} else if (unlock) {
- Intent intent = new Intent(mActivity, Gallery.class);
- intent.putExtra(Gallery.KEY_DISMISS_KEYGUARD, true);
- mActivity.startActivity(intent);
+ mActivity.getStateManager().finishState(this);
} else if (launchCamera) {
launchCamera();
} else {
@@ -1240,7 +1250,7 @@ public class PhotoPage extends ActivityState implements
Bundle data = new Bundle(getData());
data.putString(KEY_MEDIA_SET_PATH, albumPath.toString());
data.putString(PhotoPage.KEY_MEDIA_ITEM_PATH, path.toString());
- mActivity.getStateManager().startState(PhotoPage.class, data);
+ mActivity.getStateManager().startState(SinglePhotoPage.class, data);
return;
}
mModel.setCurrentPhoto(path, mCurrentIndex);
diff --git a/src/com/android/gallery3d/app/PickerActivity.java b/src/com/android/gallery3d/app/PickerActivity.java
index d5bb218ea..1eb95d0c6 100644
--- a/src/com/android/gallery3d/app/PickerActivity.java
+++ b/src/com/android/gallery3d/app/PickerActivity.java
@@ -17,13 +17,13 @@
package com.android.gallery3d.app;
import android.os.Bundle;
-import android.view.Menu;
-import android.view.MenuInflater;
-import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
-import android.view.Window;
+import com.actionbarsherlock.view.Menu;
+import com.actionbarsherlock.view.MenuInflater;
+import com.actionbarsherlock.view.MenuItem;
+import com.actionbarsherlock.view.Window;
import com.android.gallery3d.R;
import com.android.gallery3d.ui.GLRootView;
@@ -62,7 +62,7 @@ public class PickerActivity extends AbstractGalleryActivity
@Override
public boolean onCreateOptionsMenu(Menu menu) {
- MenuInflater inflater = getMenuInflater();
+ MenuInflater inflater = getSupportMenuInflater();
inflater.inflate(R.menu.pickup, menu);
return true;
}
diff --git a/src/com/android/gallery3d/app/SinglePhotoDataAdapter.java b/src/com/android/gallery3d/app/SinglePhotoDataAdapter.java
index 00f2fe78f..f0848ad22 100644
--- a/src/com/android/gallery3d/app/SinglePhotoDataAdapter.java
+++ b/src/com/android/gallery3d/app/SinglePhotoDataAdapter.java
@@ -34,6 +34,7 @@ import com.android.gallery3d.ui.SynchronizedHandler;
import com.android.gallery3d.ui.TileImageViewAdapter;
import com.android.gallery3d.util.Future;
import com.android.gallery3d.util.FutureListener;
+import com.android.gallery3d.util.LightCycleHelper;
import com.android.gallery3d.util.ThreadPool;
public class SinglePhotoDataAdapter extends TileImageViewAdapter
diff --git a/src/com/android/gallery3d/app/SinglePhotoPage.java b/src/com/android/gallery3d/app/SinglePhotoPage.java
new file mode 100644
index 000000000..beb87d358
--- /dev/null
+++ b/src/com/android/gallery3d/app/SinglePhotoPage.java
@@ -0,0 +1,21 @@
+/*
+ * 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;
+
+public class SinglePhotoPage extends PhotoPage {
+
+}
diff --git a/src/com/android/gallery3d/app/StateManager.java b/src/com/android/gallery3d/app/StateManager.java
index d77279f78..64daa6afe 100644
--- a/src/com/android/gallery3d/app/StateManager.java
+++ b/src/com/android/gallery3d/app/StateManager.java
@@ -21,10 +21,10 @@ import android.content.Intent;
import android.content.res.Configuration;
import android.os.Bundle;
import android.os.Parcelable;
-import android.view.Menu;
-import android.view.MenuItem;
import com.android.gallery3d.anim.StateTransitionAnimation;
+import com.actionbarsherlock.view.Menu;
+import com.actionbarsherlock.view.MenuItem;
import com.android.gallery3d.common.Utils;
import java.util.Stack;
diff --git a/src/com/android/gallery3d/app/TrimControllerOverlay.java b/src/com/android/gallery3d/app/TrimControllerOverlay.java
index 9127ad159..cae016626 100644
--- a/src/com/android/gallery3d/app/TrimControllerOverlay.java
+++ b/src/com/android/gallery3d/app/TrimControllerOverlay.java
@@ -23,6 +23,8 @@ import android.content.Context;
import android.view.MotionEvent;
import android.view.View;
+import com.android.gallery3d.common.ApiHelper;
+
/**
* The controller for the Trimming Video.
*/
@@ -41,36 +43,41 @@ public class TrimControllerOverlay extends CommonControllerOverlay {
if (mState == State.PLAYING) {
mPlayPauseReplayView.setVisibility(View.INVISIBLE);
}
- mPlayPauseReplayView.setAlpha(1f);
+ if (ApiHelper.HAS_OBJECT_ANIMATION) {
+ mPlayPauseReplayView.setAlpha(1f);
+ }
}
@Override
public void showPlaying() {
super.showPlaying();
+ if (ApiHelper.HAS_OBJECT_ANIMATION) {
+ // Add animation to hide the play button while playing.
+ ObjectAnimator anim = ObjectAnimator.ofFloat(mPlayPauseReplayView, "alpha", 1f, 0f);
+ anim.setDuration(200);
+ anim.start();
+ anim.addListener(new AnimatorListener() {
+ @Override
+ public void onAnimationStart(Animator animation) {
+ }
- // Add animation to hide the play button while playing.
- ObjectAnimator anim = ObjectAnimator.ofFloat(mPlayPauseReplayView, "alpha", 1f, 0f);
- anim.setDuration(200);
- anim.start();
- anim.addListener(new AnimatorListener() {
- @Override
- public void onAnimationStart(Animator animation) {
- }
-
- @Override
- public void onAnimationEnd(Animator animation) {
- hidePlayButtonIfPlaying();
- }
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ hidePlayButtonIfPlaying();
+ }
- @Override
- public void onAnimationCancel(Animator animation) {
- hidePlayButtonIfPlaying();
- }
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ hidePlayButtonIfPlaying();
+ }
- @Override
- public void onAnimationRepeat(Animator animation) {
- }
- });
+ @Override
+ public void onAnimationRepeat(Animator animation) {
+ }
+ });
+ } else {
+ hidePlayButtonIfPlaying();
+ }
}
@Override
diff --git a/src/com/android/gallery3d/app/TrimVideo.java b/src/com/android/gallery3d/app/TrimVideo.java
index 38b403b10..7a76be5dc 100644
--- a/src/com/android/gallery3d/app/TrimVideo.java
+++ b/src/com/android/gallery3d/app/TrimVideo.java
@@ -16,8 +16,6 @@
package com.android.gallery3d.app;
-import android.app.ActionBar;
-import android.app.Activity;
import android.app.ProgressDialog;
import android.content.ContentResolver;
import android.content.ContentValues;
@@ -39,20 +37,25 @@ import android.widget.TextView;
import android.widget.Toast;
import android.widget.VideoView;
+import com.actionbarsherlock.app.ActionBar;
+import com.actionbarsherlock.app.SherlockActivity;
import com.android.gallery3d.R;
import com.android.gallery3d.util.BucketNames;
+import com.android.gallery3d.util.SaveVideoFileInfo;
+import com.android.gallery3d.util.SaveVideoFileUtils;
import java.io.File;
import java.io.IOException;
import java.sql.Date;
import java.text.SimpleDateFormat;
-public class TrimVideo extends Activity implements
+public class TrimVideo extends SherlockActivity implements
MediaPlayer.OnErrorListener,
MediaPlayer.OnCompletionListener,
ControllerOverlay.Listener {
private VideoView mVideoView;
+ private TextView mSaveVideoTextView;
private TrimControllerOverlay mController;
private Context mContext;
private Uri mUri;
@@ -70,13 +73,8 @@ public class TrimVideo extends Activity implements
private boolean mHasPaused = false;
private String mSrcVideoPath = null;
- private String mSaveFileName = null;
private static final String TIME_STAMP_NAME = "'TRIM'_yyyyMMdd_HHmmss";
- private File mSrcFile = null;
- private File mDstFile = null;
- private File mSaveDirectory = null;
- // For showing the result.
- private String saveFolderName = null;
+ private SaveVideoFileInfo mDstFileInfo = null;
@Override
public void onCreate(Bundle savedInstanceState) {
@@ -86,20 +84,21 @@ public class TrimVideo extends Activity implements
requestWindowFeature(Window.FEATURE_ACTION_BAR);
requestWindowFeature(Window.FEATURE_ACTION_BAR_OVERLAY);
- ActionBar actionBar = getActionBar();
+ ActionBar actionBar = getSupportActionBar();
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);
- TextView mSaveVideoTextView = (TextView) findViewById(R.id.start_trim);
+ 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();
@@ -221,72 +220,24 @@ public class TrimVideo extends Activity implements
mController.showPaused();
}
- // Copy from SaveCopyTask.java in terms of how to handle the destination
- // path and filename : querySource() and getSaveDirectory().
- private interface ContentResolverQueryCallback {
- void onCursorResult(Cursor cursor);
- }
-
- private void querySource(String[] projection, ContentResolverQueryCallback callback) {
- ContentResolver contentResolver = getContentResolver();
- Cursor cursor = null;
- try {
- cursor = contentResolver.query(mUri, projection, null, null, null);
- if ((cursor != null) && cursor.moveToNext()) {
- callback.onCursorResult(cursor);
- }
- } catch (Exception e) {
- // Ignore error for lacking the data column from the source.
- } finally {
- if (cursor != null) {
- cursor.close();
- }
- }
- }
-
- private File getSaveDirectory() {
- final File[] dir = new File[1];
- querySource(new String[] {
- VideoColumns.DATA }, new ContentResolverQueryCallback() {
- @Override
- public void onCursorResult(Cursor cursor) {
- dir[0] = new File(cursor.getString(0)).getParentFile();
- }
- });
- return dir[0];
- }
-
- private void trimVideo() {
+ 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 ) {
- Toast.makeText(getApplicationContext(),
- getString(R.string.trim_too_short),
- Toast.LENGTH_SHORT).show();
- return;
- }
- if (Math.abs(mVideoView.getDuration() - delta) < 100) {
- // If no change has been made, go back
- onBackPressed();
- return;
- }
- // Use the default save directory if the source directory cannot be
- // saved.
- mSaveDirectory = getSaveDirectory();
- if ((mSaveDirectory == null) || !mSaveDirectory.canWrite()) {
- mSaveDirectory = new File(Environment.getExternalStorageDirectory(),
- BucketNames.DOWNLOAD);
- saveFolderName = getString(R.string.folder_download);
+ if (delta < 100 || Math.abs(mVideoView.getDuration() - delta) < 100) {
+ return false;
} else {
- saveFolderName = mSaveDirectory.getName();
+ return true;
}
- mSaveFileName = new SimpleDateFormat(TIME_STAMP_NAME).format(
- new Date(System.currentTimeMillis()));
+ }
- mDstFile = new File(mSaveDirectory, mSaveFileName + ".mp4");
- mSrcFile = new File(mSrcVideoPath);
+ private void trimVideo() {
+
+ mDstFileInfo = SaveVideoFileUtils.getDstMp4FileInfo(TIME_STAMP_NAME,
+ getContentResolver(), mUri, getString(R.string.folder_download));
+ final File mSrcFile = new File(mSrcVideoPath);
showProgressDialog();
@@ -294,9 +245,11 @@ public class TrimVideo extends Activity implements
@Override
public void run() {
try {
- TrimVideoUtils.startTrim(mSrcFile, mDstFile, mTrimStartTime, mTrimEndTime);
+ VideoUtils.startTrim(mSrcFile, mDstFileInfo.mFile,
+ mTrimStartTime, mTrimEndTime, mVideoView.getDuration());
// Update the database for adding a new video file.
- insertContent(mDstFile);
+ SaveVideoFileUtils.insertContent(mDstFileInfo,
+ getContentResolver(), mUri);
} catch (IOException e) {
e.printStackTrace();
}
@@ -305,7 +258,7 @@ public class TrimVideo extends Activity implements
@Override
public void run() {
Toast.makeText(getApplicationContext(),
- getString(R.string.save_into) + " " + saveFolderName,
+ getString(R.string.save_into, mDstFileInfo.mFolderName),
Toast.LENGTH_SHORT)
.show();
// TODO: change trimming into a service to avoid
@@ -315,7 +268,7 @@ public class TrimVideo extends Activity implements
mProgress = null;
// Show the result only when the activity not stopped.
Intent intent = new Intent(android.content.Intent.ACTION_VIEW);
- intent.setDataAndTypeAndNormalize(Uri.fromFile(mDstFile), "video/*");
+ intent.setDataAndType(Uri.fromFile(mDstFileInfo.mFile), "video/*");
intent.putExtra(MediaStore.EXTRA_FINISH_ON_COMPLETION, false);
startActivity(intent);
finish();
@@ -338,53 +291,6 @@ public class TrimVideo extends Activity implements
mProgress.show();
}
- /**
- * Insert the content (saved file) with proper video properties.
- */
- private Uri insertContent(File file) {
- long nowInMs = System.currentTimeMillis();
- long nowInSec = nowInMs / 1000;
- final ContentValues values = new ContentValues(12);
- values.put(Video.Media.TITLE, mSaveFileName);
- values.put(Video.Media.DISPLAY_NAME, file.getName());
- values.put(Video.Media.MIME_TYPE, "video/mp4");
- values.put(Video.Media.DATE_TAKEN, nowInMs);
- values.put(Video.Media.DATE_MODIFIED, nowInSec);
- values.put(Video.Media.DATE_ADDED, nowInSec);
- values.put(Video.Media.DATA, file.getAbsolutePath());
- values.put(Video.Media.SIZE, file.length());
- // Copy the data taken and location info from src.
- String[] projection = new String[] {
- VideoColumns.DATE_TAKEN,
- VideoColumns.LATITUDE,
- VideoColumns.LONGITUDE,
- VideoColumns.RESOLUTION,
- };
-
- // Copy some info from the source file.
- querySource(projection, new ContentResolverQueryCallback() {
- @Override
- public void onCursorResult(Cursor cursor) {
- long timeTaken = cursor.getLong(0);
- if (timeTaken > 0) {
- values.put(Video.Media.DATE_TAKEN, timeTaken);
- }
- double latitude = cursor.getDouble(1);
- double longitude = cursor.getDouble(2);
- // TODO: Change || to && after the default location issue is
- // fixed.
- if ((latitude != 0f) || (longitude != 0f)) {
- values.put(Video.Media.LATITUDE, latitude);
- values.put(Video.Media.LONGITUDE, longitude);
- }
- values.put(Video.Media.RESOLUTION, cursor.getString(3));
-
- }
- });
-
- return getContentResolver().insert(Video.Media.EXTERNAL_CONTENT_URI, values);
- }
-
@Override
public void onPlayPause() {
if (mVideoView.isPlaying()) {
@@ -410,6 +316,8 @@ public class TrimVideo extends Activity implements
mTrimStartTime = start;
mTrimEndTime = end;
setProgress();
+ // Enable save if there's modifications
+ mSaveVideoTextView.setEnabled(isModified());
}
@Override
diff --git a/src/com/android/gallery3d/app/TrimVideoUtils.java b/src/com/android/gallery3d/app/VideoUtils.java
index ae9b1e9ce..8ffc3d5eb 100644
--- a/src/com/android/gallery3d/app/TrimVideoUtils.java
+++ b/src/com/android/gallery3d/app/VideoUtils.java
@@ -19,6 +19,7 @@
package com.android.gallery3d.app;
+import com.android.gallery3d.util.SaveVideoFileInfo;
import com.coremedia.iso.IsoFile;
import com.coremedia.iso.boxes.TimeToSampleBox;
import com.googlecode.mp4parser.authoring.Movie;
@@ -36,12 +37,46 @@ import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
-/**
- * Shortens/Crops a track
- */
-public class TrimVideoUtils {
+public class VideoUtils {
- public static void startTrim(File src, File dst, int startMs, int endMs) throws IOException {
+ public static void startMute(String filePath, SaveVideoFileInfo dstFileInfo) throws IOException {
+ File dst = dstFileInfo.mFile;
+ File src = new File(filePath);
+ RandomAccessFile randomAccessFile = new RandomAccessFile(src, "r");
+ Movie movie = MovieCreator.build(randomAccessFile.getChannel());
+
+ // remove all tracks we will create new tracks from the old
+ List<Track> tracks = movie.getTracks();
+ movie.setTracks(new LinkedList<Track>());
+
+ for (Track track : tracks) {
+ if (track.getHandler().equals("vide")) {
+ movie.addTrack(track);
+ }
+ }
+ writeMovieIntoFile(dst, movie);
+ randomAccessFile.close();
+ }
+
+ private static void writeMovieIntoFile(File dst, Movie movie)
+ throws IOException {
+ if (!dst.exists()) {
+ dst.createNewFile();
+ }
+
+ IsoFile out = new DefaultMp4Builder().build(movie);
+ FileOutputStream fos = new FileOutputStream(dst);
+ FileChannel fc = fos.getChannel();
+ out.getBox(fc); // This one build up the memory.
+
+ fc.close();
+ fos.close();
+ }
+
+ /**
+ * Shortens/Crops a track
+ */
+ public static void startTrim(File src, File dst, int startMs, int endMs, int totalMs) throws IOException {
RandomAccessFile randomAccessFile = new RandomAccessFile(src, "r");
Movie movie = MovieCreator.build(randomAccessFile.getChannel());
@@ -100,18 +135,7 @@ public class TrimVideoUtils {
}
movie.addTrack(new CroppedTrack(track, startSample, endSample));
}
- IsoFile out = new DefaultMp4Builder().build(movie);
-
- if (!dst.exists()) {
- dst.createNewFile();
- }
-
- FileOutputStream fos = new FileOutputStream(dst);
- FileChannel fc = fos.getChannel();
- out.getBox(fc); // This one build up the memory.
-
- fc.close();
- fos.close();
+ writeMovieIntoFile(dst, movie);
randomAccessFile.close();
}
diff --git a/src/com/android/gallery3d/data/Exif.java b/src/com/android/gallery3d/data/Exif.java
index ba5862a86..30aba7e97 100644
--- a/src/com/android/gallery3d/data/Exif.java
+++ b/src/com/android/gallery3d/data/Exif.java
@@ -18,144 +18,55 @@ package com.android.gallery3d.data;
import android.util.Log;
+import com.android.gallery3d.exif.ExifInvalidFormatException;
+import com.android.gallery3d.exif.ExifParser;
+import com.android.gallery3d.exif.ExifTag;
+
import java.io.IOException;
import java.io.InputStream;
public class Exif {
- private static final String TAG = "CameraExif";
+ private static final String TAG = "GalleryExif";
public static int getOrientation(InputStream is) {
if (is == null) {
return 0;
}
- byte[] buf = new byte[8];
- int length = 0;
-
- // ISO/IEC 10918-1:1993(E)
- while (read(is, buf, 2) && (buf[0] & 0xFF) == 0xFF) {
- int marker = buf[1] & 0xFF;
-
- // Check if the marker is a padding.
- if (marker == 0xFF) {
- continue;
- }
-
- // Check if the marker is SOI or TEM.
- if (marker == 0xD8 || marker == 0x01) {
- continue;
- }
- // Check if the marker is EOI or SOS.
- if (marker == 0xD9 || marker == 0xDA) {
- return 0;
- }
-
- // Get the length and check if it is reasonable.
- if (!read(is, buf, 2)) {
- return 0;
- }
- length = pack(buf, 0, 2, false);
- if (length < 2) {
- Log.e(TAG, "Invalid length");
- return 0;
- }
- length -= 2;
-
- // Break if the marker is EXIF in APP1.
- if (marker == 0xE1 && length >= 6) {
- if (!read(is, buf, 6)) return 0;
- length -= 6;
- if (pack(buf, 0, 4, false) == 0x45786966 &&
- pack(buf, 4, 2, false) == 0) {
- break;
- }
- }
-
- // Skip other markers.
- try {
- is.skip(length);
- } catch (IOException ex) {
- return 0;
- }
- length = 0;
- }
-
- // JEITA CP-3451 Exif Version 2.2
- if (length > 8) {
- int offset = 0;
- byte[] jpeg = new byte[length];
- if (!read(is, jpeg, length)) {
- return 0;
- }
-
- // Identify the byte order.
- int tag = pack(jpeg, offset, 4, false);
- if (tag != 0x49492A00 && tag != 0x4D4D002A) {
- Log.e(TAG, "Invalid byte order");
- return 0;
- }
- boolean littleEndian = (tag == 0x49492A00);
-
- // Get the offset and check if it is reasonable.
- int count = pack(jpeg, offset + 4, 4, littleEndian) + 2;
- if (count < 10 || count > length) {
- Log.e(TAG, "Invalid offset");
- return 0;
- }
- offset += count;
- length -= count;
-
- // Get the count and go through all the elements.
- count = pack(jpeg, offset - 2, 2, littleEndian);
- while (count-- > 0 && length >= 12) {
- // Get the tag and check if it is orientation.
- tag = pack(jpeg, offset, 2, littleEndian);
- if (tag == 0x0112) {
- // We do not really care about type and count, do we?
- int orientation = pack(jpeg, offset + 8, 2, littleEndian);
- switch (orientation) {
- case 1:
- return 0;
- case 3:
- return 180;
- case 6:
- return 90;
- case 8:
- return 270;
+ try {
+ ExifParser parser = ExifParser.parse(is, ExifParser.OPTION_IFD_0);
+ int event = parser.next();
+ while (event != ExifParser.EVENT_END) {
+ if (event == ExifParser.EVENT_NEW_TAG) {
+ ExifTag tag = parser.getTag();
+ if (tag.getTagId() == ExifTag.TAG_ORIENTATION &&
+ tag.hasValue()) {
+ int orient = (int) tag.getValueAt(0);
+ switch (orient) {
+ case ExifTag.Orientation.TOP_LEFT:
+ return 0;
+ case ExifTag.Orientation.BOTTOM_LEFT:
+ return 180;
+ case ExifTag.Orientation.RIGHT_TOP:
+ return 90;
+ case ExifTag.Orientation.RIGHT_BOTTOM:
+ return 270;
+ default:
+ Log.i(TAG, "Unsupported orientation");
+ return 0;
+ }
}
- Log.i(TAG, "Unsupported orientation");
- return 0;
}
- offset += 12;
- length -= 12;
+ event = parser.next();
}
- }
-
- Log.i(TAG, "Orientation not found");
- return 0;
- }
-
- private static int pack(byte[] bytes, int offset, int length,
- boolean littleEndian) {
- int step = 1;
- if (littleEndian) {
- offset += length - 1;
- step = -1;
- }
-
- int value = 0;
- while (length-- > 0) {
- value = (value << 8) | (bytes[offset] & 0xFF);
- offset += step;
- }
- return value;
- }
-
- private static boolean read(InputStream is, byte[] buf, int length) {
- try {
- return is.read(buf, 0, length) == length;
- } catch (IOException ex) {
- return false;
+ Log.i(TAG, "Orientation not found");
+ return 0;
+ } catch (IOException e) {
+ Log.w(TAG, "Failed to read EXIF orientation", e);
+ return 0;
+ } catch (ExifInvalidFormatException e) {
+ Log.w(TAG, "Failed to read EXIF orientation", e);
+ return 0;
}
}
}
diff --git a/src/com/android/gallery3d/data/LocalAlbum.java b/src/com/android/gallery3d/data/LocalAlbum.java
index e05aac01b..6c5feb5c8 100644
--- a/src/com/android/gallery3d/data/LocalAlbum.java
+++ b/src/com/android/gallery3d/data/LocalAlbum.java
@@ -61,7 +61,7 @@ public class LocalAlbum extends MediaSet {
mApplication = application;
mResolver = application.getContentResolver();
mBucketId = bucketId;
- mName = getLocalizedName(application.getResources(), bucketId, name);
+ mName = name;
mIsImage = isImage;
if (isImage) {
@@ -245,7 +245,7 @@ public class LocalAlbum extends MediaSet {
@Override
public String getName() {
- return mName;
+ return getLocalizedName(mApplication.getResources(), mBucketId, mName);
}
@Override
diff --git a/src/com/android/gallery3d/data/LocalMergeAlbum.java b/src/com/android/gallery3d/data/LocalMergeAlbum.java
index cbaf82fff..f0b5e5726 100644
--- a/src/com/android/gallery3d/data/LocalMergeAlbum.java
+++ b/src/com/android/gallery3d/data/LocalMergeAlbum.java
@@ -41,7 +41,6 @@ public class LocalMergeAlbum extends MediaSet implements ContentListener {
private final Comparator<MediaItem> mComparator;
private final MediaSet[] mSources;
- private String mName;
private FetchCache[] mFetcher;
private int mSupportedOperation;
private int mBucketId;
@@ -54,7 +53,6 @@ public class LocalMergeAlbum extends MediaSet implements ContentListener {
super(path, INVALID_DATA_VERSION);
mComparator = comparator;
mSources = sources;
- mName = sources.length == 0 ? "" : sources[0].getName();
mBucketId = bucketId;
for (MediaSet set : mSources) {
set.addContentListener(this);
@@ -82,7 +80,6 @@ public class LocalMergeAlbum extends MediaSet implements ContentListener {
mSupportedOperation = supported;
mIndex.clear();
mIndex.put(0, new int[mSources.length]);
- mName = mSources.length == 0 ? "" : mSources[0].getName();
}
private void invalidateCache() {
@@ -111,7 +108,7 @@ public class LocalMergeAlbum extends MediaSet implements ContentListener {
@Override
public String getName() {
- return mName;
+ return mSources.length == 0 ? "" : mSources[0].getName();
}
@Override
diff --git a/src/com/android/gallery3d/data/LocalVideo.java b/src/com/android/gallery3d/data/LocalVideo.java
index 44b853901..b1e1cb3aa 100644
--- a/src/com/android/gallery3d/data/LocalVideo.java
+++ b/src/com/android/gallery3d/data/LocalVideo.java
@@ -180,7 +180,7 @@ public class LocalVideo extends LocalMediaItem {
@Override
public int getSupportedOperations() {
- return SUPPORT_DELETE | SUPPORT_SHARE | SUPPORT_PLAY | SUPPORT_INFO | SUPPORT_TRIM;
+ return SUPPORT_DELETE | SUPPORT_SHARE | SUPPORT_PLAY | SUPPORT_INFO | SUPPORT_TRIM | SUPPORT_MUTE;
}
@Override
diff --git a/src/com/android/gallery3d/data/MediaDetails.java b/src/com/android/gallery3d/data/MediaDetails.java
index 298224729..16716dae4 100644
--- a/src/com/android/gallery3d/data/MediaDetails.java
+++ b/src/com/android/gallery3d/data/MediaDetails.java
@@ -19,9 +19,15 @@ package com.android.gallery3d.data;
import android.media.ExifInterface;
import com.android.gallery3d.R;
-import com.android.gallery3d.common.ExifTags;
+import com.android.gallery3d.common.Utils;
+import com.android.gallery3d.exif.ExifData;
+import com.android.gallery3d.exif.ExifInvalidFormatException;
+import com.android.gallery3d.exif.ExifReader;
+import com.android.gallery3d.exif.ExifTag;
+import java.io.FileInputStream;
import java.io.IOException;
+import java.io.InputStream;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map.Entry;
@@ -105,10 +111,18 @@ public class MediaDetails implements Iterable<Entry<Integer, Object>> {
return mUnits.get(index);
}
- private static void setExifData(MediaDetails details, ExifInterface exif, String tag,
+ private static void setExifData(MediaDetails details, ExifTag tag,
int key) {
- String value = exif.getAttribute(tag);
- if (value != null) {
+ if (tag != null) {
+ String value = null;
+ int type = tag.getDataType();
+ if (type == ExifTag.TYPE_UNSIGNED_RATIONAL || type == ExifTag.TYPE_RATIONAL) {
+ value = String.valueOf(tag.getRational(0).toDouble());
+ } else if (type == ExifTag.TYPE_ASCII) {
+ value = tag.getString();
+ } else {
+ value = String.valueOf(tag.getValueAt(0));
+ }
if (key == MediaDetails.INDEX_FLASH) {
MediaDetails.FlashState state = new MediaDetails.FlashState(
Integer.valueOf(value.toString()));
@@ -120,29 +134,37 @@ public class MediaDetails implements Iterable<Entry<Integer, Object>> {
}
public static void extractExifInfo(MediaDetails details, String filePath) {
+ InputStream is = null;
try {
- ExifInterface exif = new ExifInterface(filePath);
- setExifData(details, exif, ExifInterface.TAG_FLASH, MediaDetails.INDEX_FLASH);
- setExifData(details, exif, ExifInterface.TAG_IMAGE_WIDTH, MediaDetails.INDEX_WIDTH);
- setExifData(details, exif, ExifInterface.TAG_IMAGE_LENGTH,
- MediaDetails.INDEX_HEIGHT);
- setExifData(details, exif, ExifInterface.TAG_MAKE, MediaDetails.INDEX_MAKE);
- setExifData(details, exif, ExifInterface.TAG_MODEL, MediaDetails.INDEX_MODEL);
- setExifData(details, exif, ExifTags.TAG_APERTURE, MediaDetails.INDEX_APERTURE);
- setExifData(details, exif, ExifTags.TAG_ISO, MediaDetails.INDEX_ISO);
- setExifData(details, exif, ExifInterface.TAG_WHITE_BALANCE,
+ is = new FileInputStream(filePath);
+ ExifData data = new ExifReader().read(is);
+ setExifData(details, data.getTag(ExifTag.TAG_FLASH), MediaDetails.INDEX_FLASH);
+ setExifData(details, data.getTag(ExifTag.TAG_IMAGE_WIDTH), MediaDetails.INDEX_WIDTH);
+ setExifData(details, data.getTag(ExifTag.TAG_IMAGE_LENGTH), MediaDetails.INDEX_HEIGHT);
+ setExifData(details, data.getTag(ExifTag.TAG_MAKE), MediaDetails.INDEX_MAKE);
+ setExifData(details, data.getTag(ExifTag.TAG_MODEL),MediaDetails.INDEX_MODEL);
+ setExifData(details, data.getTag(ExifTag.TAG_APERTURE_VALUE),
+ MediaDetails.INDEX_APERTURE);
+ setExifData(details, data.getTag(ExifTag.TAG_ISO_SPEED_RATINGS),
+ MediaDetails.INDEX_ISO);
+ setExifData(details, data.getTag(ExifTag.TAG_WHITE_BALANCE),
MediaDetails.INDEX_WHITE_BALANCE);
- setExifData(details, exif, ExifTags.TAG_EXPOSURE_TIME,
+ setExifData(details, data.getTag(ExifTag.TAG_EXPOSURE_TIME),
MediaDetails.INDEX_EXPOSURE_TIME);
-
- double data = exif.getAttributeDouble(ExifInterface.TAG_FOCAL_LENGTH, 0);
- if (data != 0f) {
- details.addDetail(MediaDetails.INDEX_FOCAL_LENGTH, data);
+ ExifTag focalTag = data.getTag(ExifTag.TAG_FOCAL_LENGTH);
+ if (focalTag != null) {
+ details.addDetail(MediaDetails.INDEX_FOCAL_LENGTH,
+ focalTag.getRational(0).toDouble());
details.setUnit(MediaDetails.INDEX_FOCAL_LENGTH, R.string.unit_mm);
}
} catch (IOException ex) {
// ignore it.
Log.w(TAG, "", ex);
+ } catch (ExifInvalidFormatException ex) {
+ // ignore it.
+ Log.w(TAG, "", ex);
+ } finally {
+ Utils.closeSilently(is);
}
}
}
diff --git a/src/com/android/gallery3d/data/MediaObject.java b/src/com/android/gallery3d/data/MediaObject.java
index a41b275fb..9c82661f6 100644
--- a/src/com/android/gallery3d/data/MediaObject.java
+++ b/src/com/android/gallery3d/data/MediaObject.java
@@ -41,6 +41,7 @@ public abstract class MediaObject {
public static final int SUPPORT_BACK = 1 << 14;
public static final int SUPPORT_ACTION = 1 << 15;
public static final int SUPPORT_CAMERA_SHORTCUT = 1 << 16;
+ public static final int SUPPORT_MUTE = 1 << 17;
public static final int SUPPORT_ALL = 0xffffffff;
// These are the bits returned from getMediaType():
diff --git a/src/com/android/gallery3d/filtershow/FilterShowActivity.java b/src/com/android/gallery3d/filtershow/FilterShowActivity.java
index ef0415f94..94d318558 100644
--- a/src/com/android/gallery3d/filtershow/FilterShowActivity.java
+++ b/src/com/android/gallery3d/filtershow/FilterShowActivity.java
@@ -117,6 +117,7 @@ public class FilterShowActivity extends Activity implements OnItemClickListener,
private View mListGeometry = null;
private View mListColors = null;
private View mListFilterButtons = null;
+ private View mSaveButton = null;
private ImageButton mFxButton = null;
private ImageButton mBorderButton = null;
@@ -178,7 +179,8 @@ public class FilterShowActivity extends Activity implements OnItemClickListener,
actionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM);
actionBar.setCustomView(R.layout.filtershow_actionbar);
- actionBar.getCustomView().setOnClickListener(new OnClickListener() {
+ mSaveButton = actionBar.getCustomView();
+ mSaveButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View view) {
saveImage();
@@ -633,6 +635,11 @@ public class FilterShowActivity extends Activity implements OnItemClickListener,
return false;
}
+ public void enableSave(boolean enable) {
+ if (mSaveButton != null)
+ mSaveButton.setEnabled(enable);
+ }
+
private void fillListImages(LinearLayout listFilters) {
// TODO: use listview
// TODO: load the filters straight from the filesystem
diff --git a/src/com/android/gallery3d/filtershow/cache/ImageLoader.java b/src/com/android/gallery3d/filtershow/cache/ImageLoader.java
index a89199602..7874881fa 100644
--- a/src/com/android/gallery3d/filtershow/cache/ImageLoader.java
+++ b/src/com/android/gallery3d/filtershow/cache/ImageLoader.java
@@ -36,6 +36,9 @@ import com.adobe.xmp.XMPMeta;
import com.android.gallery3d.R;
import com.android.gallery3d.common.Utils;
+import com.android.gallery3d.exif.ExifInvalidFormatException;
+import com.android.gallery3d.exif.ExifParser;
+import com.android.gallery3d.exif.ExifTag;
import com.android.gallery3d.filtershow.FilterShowActivity;
import com.android.gallery3d.filtershow.HistoryAdapter;
import com.android.gallery3d.filtershow.imageshow.ImageCrop;
@@ -46,6 +49,7 @@ import com.android.gallery3d.util.XmpUtilHelper;
import java.io.Closeable;
import java.io.File;
+import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
@@ -153,12 +157,27 @@ public class ImageLoader {
static int getOrientationFromPath(String path) {
int orientation = -1;
+ InputStream is = null;
try {
- ExifInterface EXIF = new ExifInterface(path);
- orientation = EXIF.getAttributeInt(ExifInterface.TAG_ORIENTATION,
- 1);
+ is = new FileInputStream(path);
+ ExifParser parser = ExifParser.parse(is, ExifParser.OPTION_IFD_0);
+ int event = parser.next();
+ while (event != ExifParser.EVENT_END) {
+ if (event == ExifParser.EVENT_NEW_TAG) {
+ ExifTag tag = parser.getTag();
+ if (tag.getTagId() == ExifTag.TAG_ORIENTATION) {
+ orientation = (int) tag.getValueAt(0);
+ break;
+ }
+ }
+ event = parser.next();
+ }
} catch (IOException e) {
e.printStackTrace();
+ } catch (ExifInvalidFormatException e) {
+ e.printStackTrace();
+ } finally {
+ Utils.closeSilently(is);
}
return orientation;
}
diff --git a/src/com/android/gallery3d/filtershow/imageshow/ImageShow.java b/src/com/android/gallery3d/filtershow/imageshow/ImageShow.java
index 0145c24dc..358d5b795 100644
--- a/src/com/android/gallery3d/filtershow/imageshow/ImageShow.java
+++ b/src/com/android/gallery3d/filtershow/imageshow/ImageShow.java
@@ -230,6 +230,7 @@ public class ImageShow extends View implements OnGestureListener,
}
updateSeekBar(parameter, minp, maxp);
invalidate();
+ mActivity.enableSave(hasModifications());
}
@Override
@@ -396,6 +397,7 @@ public class ImageShow extends View implements OnGestureListener,
public void updateImagePresets(boolean force) {
ImagePreset preset = getImagePreset();
if (preset == null) {
+ mActivity.enableSave(false);
return;
}
if (force) {
@@ -419,6 +421,7 @@ public class ImageShow extends View implements OnGestureListener,
mFiltersOnlyImage = null;
}
}
+ mActivity.enableSave(hasModifications());
}
public void requestFilteredImages() {
diff --git a/src/com/android/gallery3d/ui/ActionModeHandler.java b/src/com/android/gallery3d/ui/ActionModeHandler.java
index 7191599ad..0a3318d8d 100644
--- a/src/com/android/gallery3d/ui/ActionModeHandler.java
+++ b/src/com/android/gallery3d/ui/ActionModeHandler.java
@@ -17,21 +17,21 @@
package com.android.gallery3d.ui;
import android.annotation.TargetApi;
-import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.nfc.NfcAdapter;
import android.os.Handler;
-import android.view.ActionMode;
-import android.view.ActionMode.Callback;
import android.view.LayoutInflater;
-import android.view.Menu;
-import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
-import android.widget.ShareActionProvider;
-import android.widget.ShareActionProvider.OnShareTargetSelectedListener;
+import com.actionbarsherlock.app.SherlockActivity;
+import com.actionbarsherlock.view.ActionMode;
+import com.actionbarsherlock.view.ActionMode.Callback;
+import com.actionbarsherlock.view.Menu;
+import com.actionbarsherlock.view.MenuItem;
+import com.actionbarsherlock.widget.ShareActionProvider;
+import com.actionbarsherlock.widget.ShareActionProvider.OnShareTargetSelectedListener;
import com.android.gallery3d.R;
import com.android.gallery3d.app.AbstractGalleryActivity;
import com.android.gallery3d.common.ApiHelper;
@@ -129,7 +129,7 @@ public class ActionModeHandler implements Callback, PopupList.OnPopupItemClickLi
}
public void startActionMode() {
- Activity a = mActivity;
+ SherlockActivity a = mActivity;
mActionMode = a.startActionMode(this);
View customView = LayoutInflater.from(a).inflate(
R.layout.action_mode, null);
@@ -408,6 +408,15 @@ public class ActionModeHandler implements Callback, PopupList.OnPopupItemClickLi
// Pass1: Deal with unexpanded media object list for menu operation.
ArrayList<MediaObject> selected = getSelectedMediaObjects(jc);
if (selected == null) {
+ mMainHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ mMenuTask = null;
+ if (jc.isCancelled()) return;
+ // Disable all the operations when no item is selected
+ MenuExecutor.updateMenuOperation(mMenu, 0);
+ }
+ });
return null;
}
final int operation = computeMenuOptions(selected);
diff --git a/src/com/android/gallery3d/ui/MenuExecutor.java b/src/com/android/gallery3d/ui/MenuExecutor.java
index f432333ce..3d088d18a 100644
--- a/src/com/android/gallery3d/ui/MenuExecutor.java
+++ b/src/com/android/gallery3d/ui/MenuExecutor.java
@@ -26,12 +26,13 @@ import android.content.DialogInterface.OnClickListener;
import android.content.Intent;
import android.os.Handler;
import android.os.Message;
-import android.view.Menu;
-import android.view.MenuItem;
+import com.actionbarsherlock.view.Menu;
+import com.actionbarsherlock.view.MenuItem;
import com.android.gallery3d.R;
import com.android.gallery3d.app.AbstractGalleryActivity;
import com.android.gallery3d.app.CropImage;
+import com.android.gallery3d.common.ApiHelper;
import com.android.gallery3d.common.Utils;
import com.android.gallery3d.data.DataManager;
import com.android.gallery3d.data.MediaItem;
@@ -161,6 +162,7 @@ public class MenuExecutor {
boolean supportRotate = (supported & MediaObject.SUPPORT_ROTATE) != 0;
boolean supportCrop = (supported & MediaObject.SUPPORT_CROP) != 0;
boolean supportTrim = (supported & MediaObject.SUPPORT_TRIM) != 0;
+ boolean supportMute = (supported & MediaObject.SUPPORT_MUTE) != 0;
boolean supportShare = (supported & MediaObject.SUPPORT_SHARE) != 0;
boolean supportSetAs = (supported & MediaObject.SUPPORT_SETAS) != 0;
boolean supportShowOnMap = (supported & MediaObject.SUPPORT_SHOW_ON_MAP) != 0;
@@ -174,6 +176,7 @@ public class MenuExecutor {
setMenuItemVisible(menu, R.id.action_rotate_cw, supportRotate);
setMenuItemVisible(menu, R.id.action_crop, supportCrop);
setMenuItemVisible(menu, R.id.action_trim, supportTrim);
+ setMenuItemVisible(menu, R.id.action_mute, supportMute);
// Hide panorama until call to updateMenuForPanorama corrects it
setMenuItemVisible(menu, R.id.action_share_panorama, false);
setMenuItemVisible(menu, R.id.action_share, supportShare);
diff --git a/src/com/android/gallery3d/ui/PopupList.java b/src/com/android/gallery3d/ui/PopupList.java
index 248f50b25..dd6269380 100644
--- a/src/com/android/gallery3d/ui/PopupList.java
+++ b/src/com/android/gallery3d/ui/PopupList.java
@@ -159,7 +159,7 @@ public class PopupList {
R.drawable.menu_dropdown_panel_holo_dark));
mContentList = new ListView(mContext, null,
- android.R.attr.dropDownListViewStyle);
+ com.actionbarsherlock.R.attr.dropDownListViewStyle);
mContentList.setAdapter(new ItemDataAdapter());
mContentList.setOnItemClickListener(mOnItemClickListener);
popup.setContentView(mContentList);
diff --git a/src/com/android/gallery3d/ui/PositionController.java b/src/com/android/gallery3d/ui/PositionController.java
index 6a4bcea87..9069d5da2 100644
--- a/src/com/android/gallery3d/ui/PositionController.java
+++ b/src/com/android/gallery3d/ui/PositionController.java
@@ -18,10 +18,10 @@ package com.android.gallery3d.ui;
import android.content.Context;
import android.graphics.Rect;
+import android.os.Build;
import android.util.Log;
import android.widget.Scroller;
-import com.android.gallery3d.app.PhotoPage;
import com.android.gallery3d.common.Utils;
import com.android.gallery3d.ui.PhotoView.Size;
import com.android.gallery3d.util.GalleryUtils;
@@ -211,7 +211,11 @@ class PositionController {
public PositionController(Context context, Listener listener) {
mListener = listener;
mPageScroller = new FlingScroller();
- mFilmScroller = new Scroller(context, null, false);
+ if (Build.VERSION.SDK_INT >= 11) {
+ mFilmScroller = new Scroller(context, null, false);
+ } else {
+ mFilmScroller = new Scroller(context, null);
+ }
// Initialize the areas.
initPlatform();
diff --git a/src/com/android/gallery3d/util/AccessibilityUtils.java b/src/com/android/gallery3d/util/AccessibilityUtils.java
new file mode 100644
index 000000000..9df8e4ece
--- /dev/null
+++ b/src/com/android/gallery3d/util/AccessibilityUtils.java
@@ -0,0 +1,54 @@
+/*
+ * 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.util;
+
+import android.content.Context;
+import android.support.v4.view.accessibility.AccessibilityRecordCompat;
+import android.view.View;
+import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityManager;
+
+import com.android.gallery3d.common.ApiHelper;
+
+/**
+ * AccessibilityUtils provides functions needed in accessibility mode. All the functions
+ * in this class are made compatible with gingerbread and later API's
+*/
+public class AccessibilityUtils {
+ public static void makeAnnouncement(View view, CharSequence announcement) {
+ if (view == null)
+ return;
+ if (ApiHelper.HAS_ANNOUNCE_FOR_ACCESSIBILITY) {
+ view.announceForAccessibility(announcement);
+ } else {
+ // For API 15 and earlier, we need to construct an accessibility event
+ Context ctx = view.getContext();
+ AccessibilityManager am = (AccessibilityManager) ctx.getSystemService(
+ Context.ACCESSIBILITY_SERVICE);
+ if (!am.isEnabled()) return;
+ AccessibilityEvent event = AccessibilityEvent.obtain(
+ AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED);
+ AccessibilityRecordCompat arc = new AccessibilityRecordCompat(event);
+ arc.setSource(view);
+ event.setClassName(view.getClass().getName());
+ event.setPackageName(view.getContext().getPackageName());
+ event.setEnabled(view.isEnabled());
+ event.getText().add(announcement);
+ am.sendAccessibilityEvent(event);
+ }
+ }
+} \ No newline at end of file
diff --git a/src/com/android/gallery3d/util/SaveVideoFileInfo.java b/src/com/android/gallery3d/util/SaveVideoFileInfo.java
new file mode 100644
index 000000000..c7e5e8568
--- /dev/null
+++ b/src/com/android/gallery3d/util/SaveVideoFileInfo.java
@@ -0,0 +1,29 @@
+/*
+ * 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.util;
+
+import java.io.File;
+
+public class SaveVideoFileInfo {
+ public File mFile = null;
+ public String mFileName = null;
+ // This the full directory path.
+ public File mDirectory = null;
+ // This is just the folder's name.
+ public String mFolderName = null;
+
+}
diff --git a/src/com/android/gallery3d/util/SaveVideoFileUtils.java b/src/com/android/gallery3d/util/SaveVideoFileUtils.java
new file mode 100644
index 000000000..c281dd3e7
--- /dev/null
+++ b/src/com/android/gallery3d/util/SaveVideoFileUtils.java
@@ -0,0 +1,141 @@
+/*
+ * 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.util;
+
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.Environment;
+import android.provider.MediaStore.Video;
+import android.provider.MediaStore.Video.VideoColumns;
+
+import java.io.File;
+import java.sql.Date;
+import java.text.SimpleDateFormat;
+
+public class SaveVideoFileUtils {
+ // Copy from SaveCopyTask.java in terms of how to handle the destination
+ // path and filename : querySource() and getSaveDirectory().
+ public interface ContentResolverQueryCallback {
+ void onCursorResult(Cursor cursor);
+ }
+
+ // This function can decide which folder to save the video file, and generate
+ // the needed information for the video file including filename.
+ public static SaveVideoFileInfo getDstMp4FileInfo(String fileNameFormat,
+ ContentResolver contentResolver, Uri uri, String defaultFolderName) {
+ SaveVideoFileInfo dstFileInfo = new SaveVideoFileInfo();
+ // Use the default save directory if the source directory cannot be
+ // saved.
+ dstFileInfo.mDirectory = getSaveDirectory(contentResolver, uri);
+ if ((dstFileInfo.mDirectory == null) || !dstFileInfo.mDirectory.canWrite()) {
+ dstFileInfo.mDirectory = new File(Environment.getExternalStorageDirectory(),
+ BucketNames.DOWNLOAD);
+ dstFileInfo.mFolderName = defaultFolderName;
+ } else {
+ dstFileInfo.mFolderName = dstFileInfo.mDirectory.getName();
+ }
+ dstFileInfo.mFileName = new SimpleDateFormat(fileNameFormat).format(
+ new Date(System.currentTimeMillis()));
+
+ dstFileInfo.mFile = new File(dstFileInfo.mDirectory, dstFileInfo.mFileName + ".mp4");
+ return dstFileInfo;
+ }
+
+ private static void querySource(ContentResolver contentResolver, Uri uri,
+ String[] projection, ContentResolverQueryCallback callback) {
+ Cursor cursor = null;
+ try {
+ cursor = contentResolver.query(uri, projection, null, null, null);
+ if ((cursor != null) && cursor.moveToNext()) {
+ callback.onCursorResult(cursor);
+ }
+ } catch (Exception e) {
+ // Ignore error for lacking the data column from the source.
+ } finally {
+ if (cursor != null) {
+ cursor.close();
+ }
+ }
+ }
+
+ private static File getSaveDirectory(ContentResolver contentResolver, Uri uri) {
+ final File[] dir = new File[1];
+ querySource(contentResolver, uri,
+ new String[] { VideoColumns.DATA },
+ new ContentResolverQueryCallback() {
+ @Override
+ public void onCursorResult(Cursor cursor) {
+ dir[0] = new File(cursor.getString(0)).getParentFile();
+ }
+ });
+ return dir[0];
+ }
+
+
+ /**
+ * Insert the content (saved file) with proper video properties.
+ */
+ public static Uri insertContent(SaveVideoFileInfo mDstFileInfo,
+ ContentResolver contentResolver, Uri uri ) {
+ long nowInMs = System.currentTimeMillis();
+ long nowInSec = nowInMs / 1000;
+ final ContentValues values = new ContentValues(12);
+ values.put(Video.Media.TITLE, mDstFileInfo.mFileName);
+ values.put(Video.Media.DISPLAY_NAME, mDstFileInfo.mFile.getName());
+ values.put(Video.Media.MIME_TYPE, "video/mp4");
+ values.put(Video.Media.DATE_TAKEN, nowInMs);
+ values.put(Video.Media.DATE_MODIFIED, nowInSec);
+ values.put(Video.Media.DATE_ADDED, nowInSec);
+ values.put(Video.Media.DATA, mDstFileInfo.mFile.getAbsolutePath());
+ values.put(Video.Media.SIZE, mDstFileInfo.mFile.length());
+ // Copy the data taken and location info from src.
+ String[] projection = new String[] {
+ VideoColumns.DATE_TAKEN,
+ VideoColumns.LATITUDE,
+ VideoColumns.LONGITUDE,
+ VideoColumns.RESOLUTION,
+ };
+
+ // Copy some info from the source file.
+ querySource(contentResolver, uri, projection,
+ new ContentResolverQueryCallback() {
+ @Override
+ public void onCursorResult(Cursor cursor) {
+ long timeTaken = cursor.getLong(0);
+ if (timeTaken > 0) {
+ values.put(Video.Media.DATE_TAKEN, timeTaken);
+ }
+ double latitude = cursor.getDouble(1);
+ double longitude = cursor.getDouble(2);
+ // TODO: Change || to && after the default location
+ // issue is
+ // fixed.
+ if ((latitude != 0f) || (longitude != 0f)) {
+ values.put(Video.Media.LATITUDE, latitude);
+ values.put(Video.Media.LONGITUDE, longitude);
+ }
+ values.put(Video.Media.RESOLUTION, cursor.getString(3));
+
+ }
+ });
+
+ return contentResolver.insert(Video.Media.EXTERNAL_CONTENT_URI, values);
+ }
+
+}