diff options
Diffstat (limited to 'src/com/android/gallery3d/app')
50 files changed, 0 insertions, 12791 deletions
diff --git a/src/com/android/gallery3d/app/AbstractGalleryActivity.java b/src/com/android/gallery3d/app/AbstractGalleryActivity.java deleted file mode 100644 index ac39aa560..000000000 --- a/src/com/android/gallery3d/app/AbstractGalleryActivity.java +++ /dev/null @@ -1,343 +0,0 @@ -/* - * Copyright (C) 2010 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.annotation.TargetApi; -import android.app.Activity; -import android.app.AlertDialog; -import android.content.BroadcastReceiver; -import android.content.ComponentName; -import android.content.Context; -import android.content.DialogInterface; -import android.content.DialogInterface.OnCancelListener; -import android.content.DialogInterface.OnClickListener; -import android.content.Intent; -import android.content.IntentFilter; -import android.content.ServiceConnection; -import android.content.res.Configuration; -import android.os.Bundle; -import android.os.IBinder; -import android.view.Menu; -import android.view.MenuItem; -import android.view.Window; -import android.view.WindowManager; - -import com.android.gallery3d.R; -import com.android.gallery3d.common.ApiHelper; -import com.android.gallery3d.data.DataManager; -import com.android.gallery3d.data.MediaItem; -import com.android.gallery3d.ui.GLRoot; -import com.android.gallery3d.ui.GLRootView; -import com.android.gallery3d.util.LightCycleHelper.PanoramaViewHelper; -import com.android.gallery3d.util.ThreadPool; -import com.android.photos.data.GalleryBitmapPool; - -public class AbstractGalleryActivity extends Activity implements GalleryContext { - @SuppressWarnings("unused") - private static final String TAG = "AbstractGalleryActivity"; - private GLRootView mGLRootView; - private StateManager mStateManager; - private GalleryActionBar mActionBar; - private OrientationManager mOrientationManager; - private TransitionStore mTransitionStore = new TransitionStore(); - private boolean mDisableToggleStatusBar; - private PanoramaViewHelper mPanoramaViewHelper; - - private AlertDialog mAlertDialog = null; - private BroadcastReceiver mMountReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - if (getExternalCacheDir() != null) onStorageReady(); - } - }; - private IntentFilter mMountFilter = new IntentFilter(Intent.ACTION_MEDIA_MOUNTED); - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - mOrientationManager = new OrientationManager(this); - toggleStatusBarByOrientation(); - getWindow().setBackgroundDrawable(null); - mPanoramaViewHelper = new PanoramaViewHelper(this); - mPanoramaViewHelper.onCreate(); - doBindBatchService(); - } - - @Override - protected void onSaveInstanceState(Bundle outState) { - mGLRootView.lockRenderThread(); - try { - super.onSaveInstanceState(outState); - getStateManager().saveState(outState); - } finally { - mGLRootView.unlockRenderThread(); - } - } - - @Override - public void onConfigurationChanged(Configuration config) { - super.onConfigurationChanged(config); - mStateManager.onConfigurationChange(config); - getGalleryActionBar().onConfigurationChanged(); - invalidateOptionsMenu(); - toggleStatusBarByOrientation(); - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - super.onCreateOptionsMenu(menu); - return getStateManager().createOptionsMenu(menu); - } - - @Override - public Context getAndroidContext() { - return this; - } - - @Override - public DataManager getDataManager() { - return ((GalleryApp) getApplication()).getDataManager(); - } - - @Override - public ThreadPool getThreadPool() { - return ((GalleryApp) getApplication()).getThreadPool(); - } - - public synchronized StateManager getStateManager() { - if (mStateManager == null) { - mStateManager = new StateManager(this); - } - return mStateManager; - } - - public GLRoot getGLRoot() { - return mGLRootView; - } - - public OrientationManager getOrientationManager() { - return mOrientationManager; - } - - @Override - public void setContentView(int resId) { - super.setContentView(resId); - mGLRootView = (GLRootView) findViewById(R.id.gl_root_view); - } - - protected void onStorageReady() { - if (mAlertDialog != null) { - mAlertDialog.dismiss(); - mAlertDialog = null; - unregisterReceiver(mMountReceiver); - } - } - - @Override - protected void onStart() { - super.onStart(); - if (getExternalCacheDir() == null) { - OnCancelListener onCancel = new OnCancelListener() { - @Override - public void onCancel(DialogInterface dialog) { - finish(); - } - }; - OnClickListener onClick = new OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - dialog.cancel(); - } - }; - AlertDialog.Builder builder = new AlertDialog.Builder(this) - .setTitle(R.string.no_external_storage_title) - .setMessage(R.string.no_external_storage) - .setNegativeButton(android.R.string.cancel, onClick) - .setOnCancelListener(onCancel); - if (ApiHelper.HAS_SET_ICON_ATTRIBUTE) { - setAlertDialogIconAttribute(builder); - } else { - builder.setIcon(android.R.drawable.ic_dialog_alert); - } - mAlertDialog = builder.show(); - registerReceiver(mMountReceiver, mMountFilter); - } - mPanoramaViewHelper.onStart(); - } - - @TargetApi(ApiHelper.VERSION_CODES.HONEYCOMB) - private static void setAlertDialogIconAttribute( - AlertDialog.Builder builder) { - builder.setIconAttribute(android.R.attr.alertDialogIcon); - } - - @Override - protected void onStop() { - super.onStop(); - if (mAlertDialog != null) { - unregisterReceiver(mMountReceiver); - mAlertDialog.dismiss(); - mAlertDialog = null; - } - mPanoramaViewHelper.onStop(); - } - - @Override - protected void onResume() { - super.onResume(); - mGLRootView.lockRenderThread(); - try { - getStateManager().resume(); - getDataManager().resume(); - } finally { - mGLRootView.unlockRenderThread(); - } - mGLRootView.onResume(); - mOrientationManager.resume(); - } - - @Override - protected void onPause() { - super.onPause(); - mOrientationManager.pause(); - mGLRootView.onPause(); - mGLRootView.lockRenderThread(); - try { - getStateManager().pause(); - getDataManager().pause(); - } finally { - mGLRootView.unlockRenderThread(); - } - GalleryBitmapPool.getInstance().clear(); - MediaItem.getBytesBufferPool().clear(); - } - - @Override - protected void onDestroy() { - super.onDestroy(); - mGLRootView.lockRenderThread(); - try { - getStateManager().destroy(); - } finally { - mGLRootView.unlockRenderThread(); - } - doUnbindBatchService(); - } - - @Override - protected void onActivityResult(int requestCode, int resultCode, Intent data) { - mGLRootView.lockRenderThread(); - try { - getStateManager().notifyActivityResult( - requestCode, resultCode, data); - } finally { - mGLRootView.unlockRenderThread(); - } - } - - @Override - public void onBackPressed() { - // send the back event to the top sub-state - GLRoot root = getGLRoot(); - root.lockRenderThread(); - try { - getStateManager().onBackPressed(); - } finally { - root.unlockRenderThread(); - } - } - - public GalleryActionBar getGalleryActionBar() { - if (mActionBar == null) { - mActionBar = new GalleryActionBar(this); - } - return mActionBar; - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - GLRoot root = getGLRoot(); - root.lockRenderThread(); - try { - return getStateManager().itemSelected(item); - } finally { - root.unlockRenderThread(); - } - } - - protected void disableToggleStatusBar() { - mDisableToggleStatusBar = true; - } - - // Shows status bar in portrait view, hide in landscape view - private void toggleStatusBarByOrientation() { - if (mDisableToggleStatusBar) return; - - Window win = getWindow(); - if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) { - win.clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN); - } else { - win.addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN); - } - } - - public TransitionStore getTransitionStore() { - return mTransitionStore; - } - - public PanoramaViewHelper getPanoramaViewHelper() { - return mPanoramaViewHelper; - } - - protected boolean isFullscreen() { - return (getWindow().getAttributes().flags - & WindowManager.LayoutParams.FLAG_FULLSCREEN) != 0; - } - - private BatchService mBatchService; - private boolean mBatchServiceIsBound = false; - private ServiceConnection mBatchServiceConnection = new ServiceConnection() { - public void onServiceConnected(ComponentName className, IBinder service) { - mBatchService = ((BatchService.LocalBinder)service).getService(); - } - - public void onServiceDisconnected(ComponentName className) { - mBatchService = null; - } - }; - - private void doBindBatchService() { - bindService(new Intent(this, BatchService.class), mBatchServiceConnection, Context.BIND_AUTO_CREATE); - mBatchServiceIsBound = true; - } - - private void doUnbindBatchService() { - if (mBatchServiceIsBound) { - // Detach our existing connection. - unbindService(mBatchServiceConnection); - mBatchServiceIsBound = false; - } - } - - public ThreadPool getBatchServiceThreadPoolIfAvailable() { - if (mBatchServiceIsBound && mBatchService != null) { - return mBatchService.getThreadPool(); - } else { - throw new RuntimeException("Batch service unavailable"); - } - } -} diff --git a/src/com/android/gallery3d/app/ActivityState.java b/src/com/android/gallery3d/app/ActivityState.java deleted file mode 100644 index 2f1e0c9d9..000000000 --- a/src/com/android/gallery3d/app/ActivityState.java +++ /dev/null @@ -1,276 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.gallery3d.app; - -import android.app.ActionBar; -import android.app.Activity; -import android.content.BroadcastReceiver; -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.view.HapticFeedbackConstants; -import android.view.Menu; -import android.view.MenuInflater; -import android.view.MenuItem; -import android.view.Window; -import android.view.WindowManager; - -import com.android.gallery3d.R; -import com.android.gallery3d.anim.StateTransitionAnimation; -import com.android.gallery3d.glrenderer.RawTexture; -import com.android.gallery3d.ui.GLView; -import com.android.gallery3d.ui.PreparePageFadeoutTexture; -import com.android.gallery3d.util.GalleryUtils; - -abstract public class ActivityState { - protected static final int FLAG_HIDE_ACTION_BAR = 1; - protected static final int FLAG_HIDE_STATUS_BAR = 2; - protected static final int FLAG_SCREEN_ON_WHEN_PLUGGED = 4; - protected static final int FLAG_SCREEN_ON_ALWAYS = 8; - protected static final int FLAG_ALLOW_LOCK_WHILE_SCREEN_ON = 16; - protected static final int FLAG_SHOW_WHEN_LOCKED = 32; - - protected AbstractGalleryActivity mActivity; - protected Bundle mData; - protected int mFlags; - - protected ResultEntry mReceivedResults; - protected ResultEntry mResult; - - protected static class ResultEntry { - public int requestCode; - public int resultCode = Activity.RESULT_CANCELED; - public Intent resultData; - } - - private boolean mDestroyed = false; - private boolean mPlugged = false; - boolean mIsFinishing = false; - - private static final String KEY_TRANSITION_IN = "transition-in"; - - private StateTransitionAnimation.Transition mNextTransition = - StateTransitionAnimation.Transition.None; - private StateTransitionAnimation mIntroAnimation; - private GLView mContentPane; - - protected ActivityState() { - } - - protected void setContentPane(GLView content) { - mContentPane = content; - if (mIntroAnimation != null) { - mContentPane.setIntroAnimation(mIntroAnimation); - mIntroAnimation = null; - } - mContentPane.setBackgroundColor(getBackgroundColor()); - mActivity.getGLRoot().setContentPane(mContentPane); - } - - void initialize(AbstractGalleryActivity activity, Bundle data) { - mActivity = activity; - mData = data; - } - - public Bundle getData() { - return mData; - } - - protected void onBackPressed() { - mActivity.getStateManager().finishState(this); - } - - protected void setStateResult(int resultCode, Intent data) { - if (mResult == null) return; - mResult.resultCode = resultCode; - mResult.resultData = data; - } - - protected void onConfigurationChanged(Configuration config) { - } - - protected void onSaveState(Bundle outState) { - } - - protected void onStateResult(int requestCode, int resultCode, Intent data) { - } - - protected float[] mBackgroundColor; - - protected int getBackgroundColorId() { - return R.color.default_background; - } - - protected float[] getBackgroundColor() { - return mBackgroundColor; - } - - protected void onCreate(Bundle data, Bundle storedState) { - mBackgroundColor = GalleryUtils.intColorToFloatARGBArray( - mActivity.getResources().getColor(getBackgroundColorId())); - } - - protected void clearStateResult() { - } - - BroadcastReceiver mPowerIntentReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - final String action = intent.getAction(); - if (Intent.ACTION_BATTERY_CHANGED.equals(action)) { - boolean plugged = (0 != intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0)); - - if (plugged != mPlugged) { - mPlugged = plugged; - setScreenFlags(); - } - } - } - }; - - private void setScreenFlags() { - final Window win = mActivity.getWindow(); - final WindowManager.LayoutParams params = win.getAttributes(); - if ((0 != (mFlags & FLAG_SCREEN_ON_ALWAYS)) || - (mPlugged && 0 != (mFlags & FLAG_SCREEN_ON_WHEN_PLUGGED))) { - params.flags |= WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON; - } else { - params.flags &= ~WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON; - } - if (0 != (mFlags & FLAG_ALLOW_LOCK_WHILE_SCREEN_ON)) { - params.flags |= WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON; - } else { - params.flags &= ~WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON; - } - if (0 != (mFlags & FLAG_SHOW_WHEN_LOCKED)) { - params.flags |= WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED; - } else { - params.flags &= ~WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED; - } - win.setAttributes(params); - } - - protected void transitionOnNextPause(Class<? extends ActivityState> outgoing, - Class<? extends ActivityState> incoming, StateTransitionAnimation.Transition hint) { - if (outgoing == SinglePhotoPage.class && incoming == AlbumPage.class) { - mNextTransition = StateTransitionAnimation.Transition.Outgoing; - } 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); - } - if (mNextTransition != StateTransitionAnimation.Transition.None) { - mActivity.getTransitionStore().put(KEY_TRANSITION_IN, mNextTransition); - PreparePageFadeoutTexture.prepareFadeOutTexture(mActivity, mContentPane); - mNextTransition = StateTransitionAnimation.Transition.None; - } - } - - // should only be called by StateManager - void resume() { - AbstractGalleryActivity activity = mActivity; - ActionBar actionBar = activity.getActionBar(); - if (actionBar != null) { - if ((mFlags & FLAG_HIDE_ACTION_BAR) != 0) { - actionBar.hide(); - } else { - actionBar.show(); - } - int stateCount = mActivity.getStateManager().getStateCount(); - mActivity.getGalleryActionBar().setDisplayOptions(stateCount > 1, true); - // Default behavior, this can be overridden in ActivityState's onResume. - actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD); - } - - activity.invalidateOptionsMenu(); - - setScreenFlags(); - - boolean lightsOut = ((mFlags & FLAG_HIDE_STATUS_BAR) != 0); - mActivity.getGLRoot().setLightsOutMode(lightsOut); - - ResultEntry entry = mReceivedResults; - if (entry != null) { - mReceivedResults = null; - onStateResult(entry.requestCode, entry.resultCode, entry.resultData); - } - - if (0 != (mFlags & FLAG_SCREEN_ON_WHEN_PLUGGED)) { - // we need to know whether the device is plugged in to do this correctly - final IntentFilter filter = new IntentFilter(); - filter.addAction(Intent.ACTION_BATTERY_CHANGED); - activity.registerReceiver(mPowerIntentReceiver, filter); - } - - onResume(); - - // the transition store should be cleared after resume; - mActivity.getTransitionStore().clear(); - } - - // a subclass of ActivityState should override the method to resume itself - protected void onResume() { - RawTexture fade = mActivity.getTransitionStore().get( - PreparePageFadeoutTexture.KEY_FADE_TEXTURE); - mNextTransition = mActivity.getTransitionStore().get( - KEY_TRANSITION_IN, StateTransitionAnimation.Transition.None); - if (mNextTransition != StateTransitionAnimation.Transition.None) { - mIntroAnimation = new StateTransitionAnimation(mNextTransition, fade); - mNextTransition = StateTransitionAnimation.Transition.None; - } - } - - protected boolean onCreateActionBar(Menu menu) { - // TODO: we should return false if there is no menu to show - // this is a workaround for a bug in system - return true; - } - - protected boolean onItemSelected(MenuItem item) { - return false; - } - - protected void onDestroy() { - mDestroyed = true; - } - - boolean isDestroyed() { - return mDestroyed; - } - - public boolean isFinishing() { - return mIsFinishing; - } - - protected MenuInflater getSupportMenuInflater() { - return mActivity.getMenuInflater(); - } -} diff --git a/src/com/android/gallery3d/app/AlbumDataLoader.java b/src/com/android/gallery3d/app/AlbumDataLoader.java deleted file mode 100644 index 28a822830..000000000 --- a/src/com/android/gallery3d/app/AlbumDataLoader.java +++ /dev/null @@ -1,397 +0,0 @@ -/* - * Copyright (C) 2010 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.os.Handler; -import android.os.Message; -import android.os.Process; - -import com.android.gallery3d.common.Utils; -import com.android.gallery3d.data.ContentListener; -import com.android.gallery3d.data.MediaItem; -import com.android.gallery3d.data.MediaObject; -import com.android.gallery3d.data.MediaSet; -import com.android.gallery3d.data.Path; -import com.android.gallery3d.ui.SynchronizedHandler; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.concurrent.Callable; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.FutureTask; - -public class AlbumDataLoader { - @SuppressWarnings("unused") - private static final String TAG = "AlbumDataAdapter"; - private static final int DATA_CACHE_SIZE = 1000; - - private static final int MSG_LOAD_START = 1; - private static final int MSG_LOAD_FINISH = 2; - private static final int MSG_RUN_OBJECT = 3; - - private static final int MIN_LOAD_COUNT = 32; - private static final int MAX_LOAD_COUNT = 64; - - private final MediaItem[] mData; - private final long[] mItemVersion; - private final long[] mSetVersion; - - public static interface DataListener { - public void onContentChanged(int index); - public void onSizeChanged(int size); - } - - private int mActiveStart = 0; - private int mActiveEnd = 0; - - private int mContentStart = 0; - private int mContentEnd = 0; - - private final MediaSet mSource; - private long mSourceVersion = MediaObject.INVALID_DATA_VERSION; - - private final Handler mMainHandler; - private int mSize = 0; - - private DataListener mDataListener; - private MySourceListener mSourceListener = new MySourceListener(); - private LoadingListener mLoadingListener; - - private ReloadTask mReloadTask; - // the data version on which last loading failed - private long mFailedVersion = MediaObject.INVALID_DATA_VERSION; - - public AlbumDataLoader(AbstractGalleryActivity context, MediaSet mediaSet) { - mSource = mediaSet; - - mData = new MediaItem[DATA_CACHE_SIZE]; - mItemVersion = new long[DATA_CACHE_SIZE]; - mSetVersion = new long[DATA_CACHE_SIZE]; - Arrays.fill(mItemVersion, MediaObject.INVALID_DATA_VERSION); - Arrays.fill(mSetVersion, MediaObject.INVALID_DATA_VERSION); - - mMainHandler = new SynchronizedHandler(context.getGLRoot()) { - @Override - public void handleMessage(Message message) { - switch (message.what) { - case MSG_RUN_OBJECT: - ((Runnable) message.obj).run(); - return; - case MSG_LOAD_START: - if (mLoadingListener != null) mLoadingListener.onLoadingStarted(); - return; - case MSG_LOAD_FINISH: - if (mLoadingListener != null) { - boolean loadingFailed = - (mFailedVersion != MediaObject.INVALID_DATA_VERSION); - mLoadingListener.onLoadingFinished(loadingFailed); - } - return; - } - } - }; - } - - public void resume() { - mSource.addContentListener(mSourceListener); - mReloadTask = new ReloadTask(); - mReloadTask.start(); - } - - public void pause() { - mReloadTask.terminate(); - mReloadTask = null; - mSource.removeContentListener(mSourceListener); - } - - public MediaItem get(int index) { - if (!isActive(index)) { - return mSource.getMediaItem(index, 1).get(0); - } - return mData[index % mData.length]; - } - - public int getActiveStart() { - return mActiveStart; - } - - public boolean isActive(int index) { - return index >= mActiveStart && index < mActiveEnd; - } - - public int size() { - return mSize; - } - - // Returns the index of the MediaItem with the given path or - // -1 if the path is not cached - public int findItem(Path id) { - for (int i = mContentStart; i < mContentEnd; i++) { - MediaItem item = mData[i % DATA_CACHE_SIZE]; - if (item != null && id == item.getPath()) { - return i; - } - } - return -1; - } - - private void clearSlot(int slotIndex) { - mData[slotIndex] = null; - mItemVersion[slotIndex] = MediaObject.INVALID_DATA_VERSION; - mSetVersion[slotIndex] = MediaObject.INVALID_DATA_VERSION; - } - - private void setContentWindow(int contentStart, int contentEnd) { - if (contentStart == mContentStart && contentEnd == mContentEnd) return; - int end = mContentEnd; - int start = mContentStart; - - // We need change the content window before calling reloadData(...) - synchronized (this) { - mContentStart = contentStart; - mContentEnd = contentEnd; - } - long[] itemVersion = mItemVersion; - long[] setVersion = mSetVersion; - if (contentStart >= end || start >= contentEnd) { - for (int i = start, n = end; i < n; ++i) { - clearSlot(i % DATA_CACHE_SIZE); - } - } else { - for (int i = start; i < contentStart; ++i) { - clearSlot(i % DATA_CACHE_SIZE); - } - for (int i = contentEnd, n = end; i < n; ++i) { - clearSlot(i % DATA_CACHE_SIZE); - } - } - if (mReloadTask != null) mReloadTask.notifyDirty(); - } - - public void setActiveWindow(int start, int end) { - if (start == mActiveStart && end == mActiveEnd) return; - - Utils.assertTrue(start <= end - && end - start <= mData.length && end <= mSize); - - int length = mData.length; - mActiveStart = start; - mActiveEnd = end; - - // If no data is visible, keep the cache content - if (start == end) return; - - int contentStart = Utils.clamp((start + end) / 2 - length / 2, - 0, Math.max(0, mSize - length)); - int contentEnd = Math.min(contentStart + length, mSize); - if (mContentStart > start || mContentEnd < end - || Math.abs(contentStart - mContentStart) > MIN_LOAD_COUNT) { - setContentWindow(contentStart, contentEnd); - } - } - - private class MySourceListener implements ContentListener { - @Override - public void onContentDirty() { - if (mReloadTask != null) mReloadTask.notifyDirty(); - } - } - - public void setDataListener(DataListener listener) { - mDataListener = listener; - } - - public void setLoadingListener(LoadingListener listener) { - mLoadingListener = listener; - } - - private <T> T executeAndWait(Callable<T> callable) { - FutureTask<T> task = new FutureTask<T>(callable); - mMainHandler.sendMessage( - mMainHandler.obtainMessage(MSG_RUN_OBJECT, task)); - try { - return task.get(); - } catch (InterruptedException e) { - return null; - } catch (ExecutionException e) { - throw new RuntimeException(e); - } - } - - private static class UpdateInfo { - public long version; - public int reloadStart; - public int reloadCount; - - public int size; - public ArrayList<MediaItem> items; - } - - private class GetUpdateInfo implements Callable<UpdateInfo> { - private final long mVersion; - - public GetUpdateInfo(long version) { - mVersion = version; - } - - @Override - public UpdateInfo call() throws Exception { - if (mFailedVersion == mVersion) { - // previous loading failed, return null to pause loading - return null; - } - UpdateInfo info = new UpdateInfo(); - long version = mVersion; - info.version = mSourceVersion; - info.size = mSize; - long setVersion[] = mSetVersion; - for (int i = mContentStart, n = mContentEnd; i < n; ++i) { - int index = i % DATA_CACHE_SIZE; - if (setVersion[index] != version) { - info.reloadStart = i; - info.reloadCount = Math.min(MAX_LOAD_COUNT, n - i); - return info; - } - } - return mSourceVersion == mVersion ? null : info; - } - } - - private class UpdateContent implements Callable<Void> { - - private UpdateInfo mUpdateInfo; - - public UpdateContent(UpdateInfo info) { - mUpdateInfo = info; - } - - @Override - public Void call() throws Exception { - UpdateInfo info = mUpdateInfo; - mSourceVersion = info.version; - if (mSize != info.size) { - mSize = info.size; - if (mDataListener != null) mDataListener.onSizeChanged(mSize); - if (mContentEnd > mSize) mContentEnd = mSize; - if (mActiveEnd > mSize) mActiveEnd = mSize; - } - - ArrayList<MediaItem> items = info.items; - - mFailedVersion = MediaObject.INVALID_DATA_VERSION; - if ((items == null) || items.isEmpty()) { - if (info.reloadCount > 0) { - mFailedVersion = info.version; - Log.d(TAG, "loading failed: " + mFailedVersion); - } - return null; - } - int start = Math.max(info.reloadStart, mContentStart); - int end = Math.min(info.reloadStart + items.size(), mContentEnd); - - for (int i = start; i < end; ++i) { - int index = i % DATA_CACHE_SIZE; - mSetVersion[index] = info.version; - MediaItem updateItem = items.get(i - info.reloadStart); - long itemVersion = updateItem.getDataVersion(); - if (mItemVersion[index] != itemVersion) { - mItemVersion[index] = itemVersion; - mData[index] = updateItem; - if (mDataListener != null && i >= mActiveStart && i < mActiveEnd) { - mDataListener.onContentChanged(i); - } - } - } - return null; - } - } - - /* - * The thread model of ReloadTask - * * - * [Reload Task] [Main Thread] - * | | - * getUpdateInfo() --> | (synchronous call) - * (wait) <---- getUpdateInfo() - * | | - * Load Data | - * | | - * updateContent() --> | (synchronous call) - * (wait) updateContent() - * | | - * | | - */ - private class ReloadTask extends Thread { - - private volatile boolean mActive = true; - private volatile boolean mDirty = true; - private boolean mIsLoading = false; - - private void updateLoading(boolean loading) { - if (mIsLoading == loading) return; - mIsLoading = loading; - mMainHandler.sendEmptyMessage(loading ? MSG_LOAD_START : MSG_LOAD_FINISH); - } - - @Override - public void run() { - Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); - - boolean updateComplete = false; - while (mActive) { - synchronized (this) { - if (mActive && !mDirty && updateComplete) { - updateLoading(false); - if (mFailedVersion != MediaObject.INVALID_DATA_VERSION) { - Log.d(TAG, "reload pause"); - } - Utils.waitWithoutInterrupt(this); - if (mActive && (mFailedVersion != MediaObject.INVALID_DATA_VERSION)) { - Log.d(TAG, "reload resume"); - } - continue; - } - mDirty = false; - } - updateLoading(true); - long version = mSource.reload(); - UpdateInfo info = executeAndWait(new GetUpdateInfo(version)); - updateComplete = info == null; - if (updateComplete) continue; - if (info.version != version) { - info.size = mSource.getMediaItemCount(); - info.version = version; - } - if (info.reloadCount > 0) { - info.items = mSource.getMediaItem(info.reloadStart, info.reloadCount); - } - executeAndWait(new UpdateContent(info)); - } - updateLoading(false); - } - - public synchronized void notifyDirty() { - mDirty = true; - notifyAll(); - } - - public synchronized void terminate() { - mActive = false; - notifyAll(); - } - } -} diff --git a/src/com/android/gallery3d/app/AlbumPage.java b/src/com/android/gallery3d/app/AlbumPage.java deleted file mode 100644 index 658abbbd4..000000000 --- a/src/com/android/gallery3d/app/AlbumPage.java +++ /dev/null @@ -1,786 +0,0 @@ -/* - * Copyright (C) 2010 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.content.Context; -import android.content.Intent; -import android.graphics.Rect; -import android.net.Uri; -import android.os.Bundle; -import android.os.Handler; -import android.os.Message; -import android.provider.MediaStore; -import android.view.HapticFeedbackConstants; -import android.view.Menu; -import android.view.MenuInflater; -import android.view.MenuItem; -import android.widget.Toast; - -import com.android.gallery3d.R; -import com.android.gallery3d.common.Utils; -import com.android.gallery3d.data.DataManager; -import com.android.gallery3d.data.MediaDetails; -import com.android.gallery3d.data.MediaItem; -import com.android.gallery3d.data.MediaObject; -import com.android.gallery3d.data.MediaSet; -import com.android.gallery3d.data.Path; -import com.android.gallery3d.filtershow.crop.CropActivity; -import com.android.gallery3d.filtershow.crop.CropExtras; -import com.android.gallery3d.glrenderer.FadeTexture; -import com.android.gallery3d.glrenderer.GLCanvas; -import com.android.gallery3d.ui.ActionModeHandler; -import com.android.gallery3d.ui.ActionModeHandler.ActionModeListener; -import com.android.gallery3d.ui.AlbumSlotRenderer; -import com.android.gallery3d.ui.DetailsHelper; -import com.android.gallery3d.ui.DetailsHelper.CloseListener; -import com.android.gallery3d.ui.GLRoot; -import com.android.gallery3d.ui.GLView; -import com.android.gallery3d.ui.PhotoFallbackEffect; -import com.android.gallery3d.ui.RelativePosition; -import com.android.gallery3d.ui.SelectionManager; -import com.android.gallery3d.ui.SlotView; -import com.android.gallery3d.ui.SynchronizedHandler; -import com.android.gallery3d.util.Future; -import com.android.gallery3d.util.GalleryUtils; -import com.android.gallery3d.util.MediaSetUtils; - - -public class AlbumPage extends ActivityState implements GalleryActionBar.ClusterRunner, - SelectionManager.SelectionListener, MediaSet.SyncListener, GalleryActionBar.OnAlbumModeSelectedListener { - @SuppressWarnings("unused") - private static final String TAG = "AlbumPage"; - - public static final String KEY_MEDIA_PATH = "media-path"; - public static final String KEY_PARENT_MEDIA_PATH = "parent-media-path"; - public static final String KEY_SET_CENTER = "set-center"; - public static final String KEY_AUTO_SELECT_ALL = "auto-select-all"; - public static final String KEY_SHOW_CLUSTER_MENU = "cluster-menu"; - public static final String KEY_EMPTY_ALBUM = "empty-album"; - public static final String KEY_RESUME_ANIMATION = "resume_animation"; - - private static final int REQUEST_SLIDESHOW = 1; - public static final int REQUEST_PHOTO = 2; - private static final int REQUEST_DO_ANIMATION = 3; - - private static final int BIT_LOADING_RELOAD = 1; - private static final int BIT_LOADING_SYNC = 2; - - private static final float USER_DISTANCE_METER = 0.3f; - - private boolean mIsActive = false; - private AlbumSlotRenderer mAlbumView; - private Path mMediaSetPath; - private String mParentMediaSetString; - private SlotView mSlotView; - - private AlbumDataLoader mAlbumDataAdapter; - - protected SelectionManager mSelectionManager; - - private boolean mGetContent; - private boolean mShowClusterMenu; - - private ActionModeHandler mActionModeHandler; - private int mFocusIndex = 0; - private DetailsHelper mDetailsHelper; - private MyDetailsSource mDetailsSource; - private MediaSet mMediaSet; - private boolean mShowDetails; - private float mUserDistance; // in pixel - private Future<Integer> mSyncTask = null; - private boolean mLaunchedFromPhotoPage; - private boolean mInCameraApp; - private boolean mInCameraAndWantQuitOnPause; - - private int mLoadingBits = 0; - private boolean mInitialSynced = false; - private int mSyncResult; - private boolean mLoadingFailed; - private RelativePosition mOpenCenter = new RelativePosition(); - - private Handler mHandler; - private static final int MSG_PICK_PHOTO = 0; - - private PhotoFallbackEffect mResumeEffect; - private PhotoFallbackEffect.PositionProvider mPositionProvider = - new PhotoFallbackEffect.PositionProvider() { - @Override - public Rect getPosition(int index) { - Rect rect = mSlotView.getSlotRect(index); - Rect bounds = mSlotView.bounds(); - rect.offset(bounds.left - mSlotView.getScrollX(), - bounds.top - mSlotView.getScrollY()); - return rect; - } - - @Override - public int getItemIndex(Path path) { - int start = mSlotView.getVisibleStart(); - int end = mSlotView.getVisibleEnd(); - for (int i = start; i < end; ++i) { - MediaItem item = mAlbumDataAdapter.get(i); - if (item != null && item.getPath() == path) return i; - } - return -1; - } - }; - - @Override - protected int getBackgroundColorId() { - return R.color.album_background; - } - - private final GLView mRootPane = new GLView() { - private final float mMatrix[] = new float[16]; - - @Override - protected void onLayout( - boolean changed, int left, int top, int right, int bottom) { - - int slotViewTop = mActivity.getGalleryActionBar().getHeight(); - int slotViewBottom = bottom - top; - int slotViewRight = right - left; - - if (mShowDetails) { - mDetailsHelper.layout(left, slotViewTop, right, bottom); - } else { - mAlbumView.setHighlightItemPath(null); - } - - // Set the mSlotView as a reference point to the open animation - mOpenCenter.setReferencePosition(0, slotViewTop); - mSlotView.layout(0, slotViewTop, slotViewRight, slotViewBottom); - GalleryUtils.setViewPointMatrix(mMatrix, - (right - left) / 2, (bottom - top) / 2, -mUserDistance); - } - - @Override - protected void render(GLCanvas canvas) { - canvas.save(GLCanvas.SAVE_FLAG_MATRIX); - canvas.multiplyMatrix(mMatrix, 0); - super.render(canvas); - - if (mResumeEffect != null) { - boolean more = mResumeEffect.draw(canvas); - if (!more) { - mResumeEffect = null; - mAlbumView.setSlotFilter(null); - } - // We want to render one more time even when no more effect - // required. So that the animated thumbnails could be draw - // with declarations in super.render(). - invalidate(); - } - canvas.restore(); - } - }; - - // This are the transitions we want: - // - // +--------+ +------------+ +-------+ +----------+ - // | Camera |---------->| Fullscreen |--->| Album |--->| AlbumSet | - // | View | thumbnail | Photo | up | Page | up | Page | - // +--------+ +------------+ +-------+ +----------+ - // ^ | | ^ | - // | | | | | close - // +----------back--------+ +----back----+ +--back-> app - // - @Override - protected void onBackPressed() { - if (mShowDetails) { - hideDetails(); - } else if (mSelectionManager.inSelectionMode()) { - mSelectionManager.leaveSelectionMode(); - } else { - if(mLaunchedFromPhotoPage) { - mActivity.getTransitionStore().putIfNotPresent( - PhotoPage.KEY_ALBUMPAGE_TRANSITION, - PhotoPage.MSG_ALBUMPAGE_RESUMED); - } - // TODO: fix this regression - // mAlbumView.savePositions(PositionRepository.getInstance(mActivity)); - if (mInCameraApp) { - super.onBackPressed(); - } else { - onUpPressed(); - } - } - } - - private void onUpPressed() { - if (mInCameraApp) { - GalleryUtils.startGalleryActivity(mActivity); - } else if (mActivity.getStateManager().getStateCount() > 1) { - super.onBackPressed(); - } else if (mParentMediaSetString != null) { - Bundle data = new Bundle(getData()); - data.putString(AlbumSetPage.KEY_MEDIA_PATH, mParentMediaSetString); - mActivity.getStateManager().switchState( - this, AlbumSetPage.class, data); - } - } - - private void onDown(int index) { - mAlbumView.setPressedIndex(index); - } - - private void onUp(boolean followedByLongPress) { - if (followedByLongPress) { - // Avoid showing press-up animations for long-press. - mAlbumView.setPressedIndex(-1); - } else { - mAlbumView.setPressedUp(); - } - } - - private void onSingleTapUp(int slotIndex) { - if (!mIsActive) return; - - if (mSelectionManager.inSelectionMode()) { - MediaItem item = mAlbumDataAdapter.get(slotIndex); - if (item == null) return; // Item not ready yet, ignore the click - mSelectionManager.toggle(item.getPath()); - mSlotView.invalidate(); - } else { - // Render transition in pressed state - mAlbumView.setPressedIndex(slotIndex); - mAlbumView.setPressedUp(); - mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_PICK_PHOTO, slotIndex, 0), - FadeTexture.DURATION); - } - } - - private void pickPhoto(int slotIndex) { - pickPhoto(slotIndex, false); - } - - private void pickPhoto(int slotIndex, boolean startInFilmstrip) { - if (!mIsActive) return; - - if (!startInFilmstrip) { - // Launch photos in lights out mode - mActivity.getGLRoot().setLightsOutMode(true); - } - - MediaItem item = mAlbumDataAdapter.get(slotIndex); - if (item == null) return; // Item not ready yet, ignore the click - if (mGetContent) { - onGetContent(item); - } else if (mLaunchedFromPhotoPage) { - TransitionStore transitions = mActivity.getTransitionStore(); - transitions.put( - PhotoPage.KEY_ALBUMPAGE_TRANSITION, - PhotoPage.MSG_ALBUMPAGE_PICKED); - transitions.put(PhotoPage.KEY_INDEX_HINT, slotIndex); - onBackPressed(); - } else { - // Get into the PhotoPage. - // mAlbumView.savePositions(PositionRepository.getInstance(mActivity)); - Bundle data = new Bundle(); - data.putInt(PhotoPage.KEY_INDEX_HINT, slotIndex); - data.putParcelable(PhotoPage.KEY_OPEN_ANIMATION_RECT, - mSlotView.getSlotRect(slotIndex, mRootPane)); - data.putString(PhotoPage.KEY_MEDIA_SET_PATH, - mMediaSetPath.toString()); - data.putString(PhotoPage.KEY_MEDIA_ITEM_PATH, - item.getPath().toString()); - data.putInt(PhotoPage.KEY_ALBUMPAGE_TRANSITION, - PhotoPage.MSG_ALBUMPAGE_STARTED); - data.putBoolean(PhotoPage.KEY_START_IN_FILMSTRIP, - startInFilmstrip); - data.putBoolean(PhotoPage.KEY_IN_CAMERA_ROLL, mMediaSet.isCameraRoll()); - if (startInFilmstrip) { - mActivity.getStateManager().switchState(this, FilmstripPage.class, data); - } else { - mActivity.getStateManager().startStateForResult( - SinglePhotoPage.class, REQUEST_PHOTO, data); - } - } - } - - private void onGetContent(final MediaItem item) { - DataManager dm = mActivity.getDataManager(); - Activity activity = mActivity; - if (mData.getString(Gallery.EXTRA_CROP) != null) { - Uri uri = dm.getContentUri(item.getPath()); - Intent intent = new Intent(CropActivity.CROP_ACTION, uri) - .addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT) - .putExtras(getData()); - if (mData.getParcelable(MediaStore.EXTRA_OUTPUT) == null) { - intent.putExtra(CropExtras.KEY_RETURN_DATA, true); - } - activity.startActivity(intent); - activity.finish(); - } else { - Intent intent = new Intent(null, item.getContentUri()) - .addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); - activity.setResult(Activity.RESULT_OK, intent); - activity.finish(); - } - } - - public void onLongTap(int slotIndex) { - if (mGetContent) return; - MediaItem item = mAlbumDataAdapter.get(slotIndex); - if (item == null) return; - mSelectionManager.setAutoLeaveSelectionMode(true); - mSelectionManager.toggle(item.getPath()); - mSlotView.invalidate(); - } - - @Override - public void doCluster(int clusterType) { - String basePath = mMediaSet.getPath().toString(); - String newPath = FilterUtils.newClusterPath(basePath, clusterType); - Bundle data = new Bundle(getData()); - data.putString(AlbumSetPage.KEY_MEDIA_PATH, newPath); - if (mShowClusterMenu) { - Context context = mActivity.getAndroidContext(); - data.putString(AlbumSetPage.KEY_SET_TITLE, mMediaSet.getName()); - data.putString(AlbumSetPage.KEY_SET_SUBTITLE, - GalleryActionBar.getClusterByTypeString(context, clusterType)); - } - - // mAlbumView.savePositions(PositionRepository.getInstance(mActivity)); - mActivity.getStateManager().startStateForResult( - AlbumSetPage.class, REQUEST_DO_ANIMATION, data); - } - - @Override - protected void onCreate(Bundle data, Bundle restoreState) { - super.onCreate(data, restoreState); - mUserDistance = GalleryUtils.meterToPixel(USER_DISTANCE_METER); - initializeViews(); - initializeData(data); - mGetContent = data.getBoolean(Gallery.KEY_GET_CONTENT, false); - mShowClusterMenu = data.getBoolean(KEY_SHOW_CLUSTER_MENU, false); - mDetailsSource = new MyDetailsSource(); - Context context = mActivity.getAndroidContext(); - - if (data.getBoolean(KEY_AUTO_SELECT_ALL)) { - mSelectionManager.selectAll(); - } - - mLaunchedFromPhotoPage = - mActivity.getStateManager().hasStateClass(FilmstripPage.class); - mInCameraApp = data.getBoolean(PhotoPage.KEY_APP_BRIDGE, false); - - mHandler = new SynchronizedHandler(mActivity.getGLRoot()) { - @Override - public void handleMessage(Message message) { - switch (message.what) { - case MSG_PICK_PHOTO: { - pickPhoto(message.arg1); - break; - } - default: - throw new AssertionError(message.what); - } - } - }; - } - - @Override - protected void onResume() { - super.onResume(); - mIsActive = true; - - mResumeEffect = mActivity.getTransitionStore().get(KEY_RESUME_ANIMATION); - if (mResumeEffect != null) { - mAlbumView.setSlotFilter(mResumeEffect); - mResumeEffect.setPositionProvider(mPositionProvider); - mResumeEffect.start(); - } - - setContentPane(mRootPane); - - boolean enableHomeButton = (mActivity.getStateManager().getStateCount() > 1) | - mParentMediaSetString != null; - GalleryActionBar actionBar = mActivity.getGalleryActionBar(); - actionBar.setDisplayOptions(enableHomeButton, false); - if (!mGetContent) { - actionBar.enableAlbumModeMenu(GalleryActionBar.ALBUM_GRID_MODE_SELECTED, this); - } - - // Set the reload bit here to prevent it exit this page in clearLoadingBit(). - setLoadingBit(BIT_LOADING_RELOAD); - mLoadingFailed = false; - mAlbumDataAdapter.resume(); - - mAlbumView.resume(); - mAlbumView.setPressedIndex(-1); - mActionModeHandler.resume(); - if (!mInitialSynced) { - setLoadingBit(BIT_LOADING_SYNC); - mSyncTask = mMediaSet.requestSync(this); - } - mInCameraAndWantQuitOnPause = mInCameraApp; - } - - @Override - protected void onPause() { - super.onPause(); - mIsActive = false; - - if (mSelectionManager.inSelectionMode()) { - mSelectionManager.leaveSelectionMode(); - } - mAlbumView.setSlotFilter(null); - mActionModeHandler.pause(); - mAlbumDataAdapter.pause(); - mAlbumView.pause(); - DetailsHelper.pause(); - if (!mGetContent) { - mActivity.getGalleryActionBar().disableAlbumModeMenu(true); - } - - if (mSyncTask != null) { - mSyncTask.cancel(); - mSyncTask = null; - clearLoadingBit(BIT_LOADING_SYNC); - } - } - - @Override - protected void onDestroy() { - super.onDestroy(); - if (mAlbumDataAdapter != null) { - mAlbumDataAdapter.setLoadingListener(null); - } - mActionModeHandler.destroy(); - } - - private void initializeViews() { - mSelectionManager = new SelectionManager(mActivity, false); - mSelectionManager.setSelectionListener(this); - Config.AlbumPage config = Config.AlbumPage.get(mActivity); - mSlotView = new SlotView(mActivity, config.slotViewSpec); - mAlbumView = new AlbumSlotRenderer(mActivity, mSlotView, - mSelectionManager, config.placeholderColor); - mSlotView.setSlotRenderer(mAlbumView); - mRootPane.addComponent(mSlotView); - mSlotView.setListener(new SlotView.SimpleListener() { - @Override - public void onDown(int index) { - AlbumPage.this.onDown(index); - } - - @Override - public void onUp(boolean followedByLongPress) { - AlbumPage.this.onUp(followedByLongPress); - } - - @Override - public void onSingleTapUp(int slotIndex) { - AlbumPage.this.onSingleTapUp(slotIndex); - } - - @Override - public void onLongTap(int slotIndex) { - AlbumPage.this.onLongTap(slotIndex); - } - }); - mActionModeHandler = new ActionModeHandler(mActivity, mSelectionManager); - mActionModeHandler.setActionModeListener(new ActionModeListener() { - @Override - public boolean onActionItemClicked(MenuItem item) { - return onItemSelected(item); - } - }); - } - - private void initializeData(Bundle data) { - mMediaSetPath = Path.fromString(data.getString(KEY_MEDIA_PATH)); - mParentMediaSetString = data.getString(KEY_PARENT_MEDIA_PATH); - mMediaSet = mActivity.getDataManager().getMediaSet(mMediaSetPath); - if (mMediaSet == null) { - Utils.fail("MediaSet is null. Path = %s", mMediaSetPath); - } - mSelectionManager.setSourceMediaSet(mMediaSet); - mAlbumDataAdapter = new AlbumDataLoader(mActivity, mMediaSet); - mAlbumDataAdapter.setLoadingListener(new MyLoadingListener()); - mAlbumView.setModel(mAlbumDataAdapter); - } - - private void showDetails() { - mShowDetails = true; - if (mDetailsHelper == null) { - mDetailsHelper = new DetailsHelper(mActivity, mRootPane, mDetailsSource); - mDetailsHelper.setCloseListener(new CloseListener() { - @Override - public void onClose() { - hideDetails(); - } - }); - } - mDetailsHelper.show(); - } - - private void hideDetails() { - mShowDetails = false; - mDetailsHelper.hide(); - mAlbumView.setHighlightItemPath(null); - mSlotView.invalidate(); - } - - @Override - protected boolean onCreateActionBar(Menu menu) { - GalleryActionBar actionBar = mActivity.getGalleryActionBar(); - MenuInflater inflator = getSupportMenuInflater(); - if (mGetContent) { - inflator.inflate(R.menu.pickup, menu); - int typeBits = mData.getInt(Gallery.KEY_TYPE_BITS, - DataManager.INCLUDE_IMAGE); - actionBar.setTitle(GalleryUtils.getSelectionModePrompt(typeBits)); - } else { - inflator.inflate(R.menu.album, menu); - actionBar.setTitle(mMediaSet.getName()); - - FilterUtils.setupMenuItems(actionBar, mMediaSetPath, true); - - menu.findItem(R.id.action_group_by).setVisible(mShowClusterMenu); - menu.findItem(R.id.action_camera).setVisible( - MediaSetUtils.isCameraSource(mMediaSetPath) - && GalleryUtils.isCameraAvailable(mActivity)); - - } - actionBar.setSubtitle(null); - return true; - } - - private void prepareAnimationBackToFilmstrip(int slotIndex) { - if (mAlbumDataAdapter == null || !mAlbumDataAdapter.isActive(slotIndex)) return; - MediaItem item = mAlbumDataAdapter.get(slotIndex); - if (item == null) return; - TransitionStore transitions = mActivity.getTransitionStore(); - transitions.put(PhotoPage.KEY_INDEX_HINT, slotIndex); - transitions.put(PhotoPage.KEY_OPEN_ANIMATION_RECT, - mSlotView.getSlotRect(slotIndex, mRootPane)); - } - - private void switchToFilmstrip() { - if (mAlbumDataAdapter.size() < 1) return; - int targetPhoto = mSlotView.getVisibleStart(); - prepareAnimationBackToFilmstrip(targetPhoto); - if(mLaunchedFromPhotoPage) { - onBackPressed(); - } else { - pickPhoto(targetPhoto, true); - } - } - - @Override - protected boolean onItemSelected(MenuItem item) { - switch (item.getItemId()) { - case android.R.id.home: { - onUpPressed(); - return true; - } - case R.id.action_cancel: - mActivity.getStateManager().finishState(this); - return true; - case R.id.action_select: - mSelectionManager.setAutoLeaveSelectionMode(false); - mSelectionManager.enterSelectionMode(); - return true; - case R.id.action_group_by: { - mActivity.getGalleryActionBar().showClusterDialog(this); - return true; - } - case R.id.action_slideshow: { - mInCameraAndWantQuitOnPause = false; - Bundle data = new Bundle(); - data.putString(SlideshowPage.KEY_SET_PATH, - mMediaSetPath.toString()); - data.putBoolean(SlideshowPage.KEY_REPEAT, true); - mActivity.getStateManager().startStateForResult( - SlideshowPage.class, REQUEST_SLIDESHOW, data); - return true; - } - case R.id.action_details: { - if (mShowDetails) { - hideDetails(); - } else { - showDetails(); - } - return true; - } - case R.id.action_camera: { - GalleryUtils.startCameraActivity(mActivity); - return true; - } - default: - return false; - } - } - - @Override - protected void onStateResult(int request, int result, Intent data) { - switch (request) { - case REQUEST_SLIDESHOW: { - // data could be null, if there is no images in the album - if (data == null) return; - mFocusIndex = data.getIntExtra(SlideshowPage.KEY_PHOTO_INDEX, 0); - mSlotView.setCenterIndex(mFocusIndex); - break; - } - case REQUEST_PHOTO: { - if (data == null) return; - mFocusIndex = data.getIntExtra(PhotoPage.KEY_RETURN_INDEX_HINT, 0); - mSlotView.makeSlotVisible(mFocusIndex); - break; - } - case REQUEST_DO_ANIMATION: { - mSlotView.startRisingAnimation(); - break; - } - } - } - - @Override - public void onSelectionModeChange(int mode) { - switch (mode) { - case SelectionManager.ENTER_SELECTION_MODE: { - mActionModeHandler.startActionMode(); - performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); - break; - } - case SelectionManager.LEAVE_SELECTION_MODE: { - mActionModeHandler.finishActionMode(); - mRootPane.invalidate(); - break; - } - case SelectionManager.SELECT_ALL_MODE: { - mActionModeHandler.updateSupportedOperation(); - mRootPane.invalidate(); - break; - } - } - } - - @Override - public void onSelectionChange(Path path, boolean selected) { - int count = mSelectionManager.getSelectedCount(); - String format = mActivity.getResources().getQuantityString( - R.plurals.number_of_items_selected, count); - mActionModeHandler.setTitle(String.format(format, count)); - mActionModeHandler.updateSupportedOperation(path, selected); - } - - @Override - public void onSyncDone(final MediaSet mediaSet, final int resultCode) { - Log.d(TAG, "onSyncDone: " + Utils.maskDebugInfo(mediaSet.getName()) + " result=" - + resultCode); - ((Activity) mActivity).runOnUiThread(new Runnable() { - @Override - public void run() { - GLRoot root = mActivity.getGLRoot(); - root.lockRenderThread(); - mSyncResult = resultCode; - try { - if (resultCode == MediaSet.SYNC_RESULT_SUCCESS) { - mInitialSynced = true; - } - clearLoadingBit(BIT_LOADING_SYNC); - showSyncErrorIfNecessary(mLoadingFailed); - } finally { - root.unlockRenderThread(); - } - } - }); - } - - // Show sync error toast when all the following conditions are met: - // (1) both loading and sync are done, - // (2) sync result is error, - // (3) the page is still active, and - // (4) no photo is shown or loading fails. - private void showSyncErrorIfNecessary(boolean loadingFailed) { - if ((mLoadingBits == 0) && (mSyncResult == MediaSet.SYNC_RESULT_ERROR) && mIsActive - && (loadingFailed || (mAlbumDataAdapter.size() == 0))) { - Toast.makeText(mActivity, R.string.sync_album_error, - Toast.LENGTH_LONG).show(); - } - } - - private void setLoadingBit(int loadTaskBit) { - mLoadingBits |= loadTaskBit; - } - - private void clearLoadingBit(int loadTaskBit) { - mLoadingBits &= ~loadTaskBit; - if (mLoadingBits == 0 && mIsActive) { - if (mAlbumDataAdapter.size() == 0) { - Intent result = new Intent(); - result.putExtra(KEY_EMPTY_ALBUM, true); - setStateResult(Activity.RESULT_OK, result); - mActivity.getStateManager().finishState(this); - } - } - } - - private class MyLoadingListener implements LoadingListener { - @Override - public void onLoadingStarted() { - setLoadingBit(BIT_LOADING_RELOAD); - mLoadingFailed = false; - } - - @Override - public void onLoadingFinished(boolean loadingFailed) { - clearLoadingBit(BIT_LOADING_RELOAD); - mLoadingFailed = loadingFailed; - showSyncErrorIfNecessary(loadingFailed); - } - } - - private class MyDetailsSource implements DetailsHelper.DetailsSource { - private int mIndex; - - @Override - public int size() { - return mAlbumDataAdapter.size(); - } - - @Override - public int setIndex() { - Path id = mSelectionManager.getSelected(false).get(0); - mIndex = mAlbumDataAdapter.findItem(id); - return mIndex; - } - - @Override - public MediaDetails getDetails() { - // this relies on setIndex() being called beforehand - MediaObject item = mAlbumDataAdapter.get(mIndex); - if (item != null) { - mAlbumView.setHighlightItemPath(item.getPath()); - return item.getDetails(); - } else { - return null; - } - } - } - - @Override - public void onAlbumModeSelected(int mode) { - if (mode == GalleryActionBar.ALBUM_FILMSTRIP_MODE_SELECTED) { - switchToFilmstrip(); - } - } -} diff --git a/src/com/android/gallery3d/app/AlbumPicker.java b/src/com/android/gallery3d/app/AlbumPicker.java deleted file mode 100644 index 65eb77291..000000000 --- a/src/com/android/gallery3d/app/AlbumPicker.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (C) 2011 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.content.Intent; -import android.os.Bundle; - -import com.android.gallery3d.R; -import com.android.gallery3d.data.DataManager; - -public class AlbumPicker extends PickerActivity { - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setTitle(R.string.select_album); - Intent intent = getIntent(); - Bundle extras = intent.getExtras(); - Bundle data = extras == null ? new Bundle() : new Bundle(extras); - - data.putBoolean(Gallery.KEY_GET_ALBUM, true); - data.putString(AlbumSetPage.KEY_MEDIA_PATH, - getDataManager().getTopSetPath(DataManager.INCLUDE_IMAGE)); - getStateManager().startState(AlbumSetPage.class, data); - } -} diff --git a/src/com/android/gallery3d/app/AlbumSetDataLoader.java b/src/com/android/gallery3d/app/AlbumSetDataLoader.java deleted file mode 100644 index cf380f812..000000000 --- a/src/com/android/gallery3d/app/AlbumSetDataLoader.java +++ /dev/null @@ -1,393 +0,0 @@ -/* - * Copyright (C) 2010 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.os.Handler; -import android.os.Message; -import android.os.Process; - -import com.android.gallery3d.common.Utils; -import com.android.gallery3d.data.ContentListener; -import com.android.gallery3d.data.MediaItem; -import com.android.gallery3d.data.MediaObject; -import com.android.gallery3d.data.MediaSet; -import com.android.gallery3d.data.Path; -import com.android.gallery3d.ui.SynchronizedHandler; - -import java.util.Arrays; -import java.util.concurrent.Callable; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.FutureTask; - -public class AlbumSetDataLoader { - @SuppressWarnings("unused") - private static final String TAG = "AlbumSetDataAdapter"; - - private static final int INDEX_NONE = -1; - - private static final int MIN_LOAD_COUNT = 4; - - private static final int MSG_LOAD_START = 1; - private static final int MSG_LOAD_FINISH = 2; - private static final int MSG_RUN_OBJECT = 3; - - public static interface DataListener { - public void onContentChanged(int index); - public void onSizeChanged(int size); - } - - private final MediaSet[] mData; - private final MediaItem[] mCoverItem; - private final int[] mTotalCount; - private final long[] mItemVersion; - private final long[] mSetVersion; - - private int mActiveStart = 0; - private int mActiveEnd = 0; - - private int mContentStart = 0; - private int mContentEnd = 0; - - private final MediaSet mSource; - private long mSourceVersion = MediaObject.INVALID_DATA_VERSION; - private int mSize; - - private DataListener mDataListener; - private LoadingListener mLoadingListener; - private ReloadTask mReloadTask; - - private final Handler mMainHandler; - - private final MySourceListener mSourceListener = new MySourceListener(); - - public AlbumSetDataLoader(AbstractGalleryActivity activity, MediaSet albumSet, int cacheSize) { - mSource = Utils.checkNotNull(albumSet); - mCoverItem = new MediaItem[cacheSize]; - mData = new MediaSet[cacheSize]; - mTotalCount = new int[cacheSize]; - mItemVersion = new long[cacheSize]; - mSetVersion = new long[cacheSize]; - Arrays.fill(mItemVersion, MediaObject.INVALID_DATA_VERSION); - Arrays.fill(mSetVersion, MediaObject.INVALID_DATA_VERSION); - - mMainHandler = new SynchronizedHandler(activity.getGLRoot()) { - @Override - public void handleMessage(Message message) { - switch (message.what) { - case MSG_RUN_OBJECT: - ((Runnable) message.obj).run(); - return; - case MSG_LOAD_START: - if (mLoadingListener != null) mLoadingListener.onLoadingStarted(); - return; - case MSG_LOAD_FINISH: - if (mLoadingListener != null) mLoadingListener.onLoadingFinished(false); - return; - } - } - }; - } - - public void pause() { - mReloadTask.terminate(); - mReloadTask = null; - mSource.removeContentListener(mSourceListener); - } - - public void resume() { - mSource.addContentListener(mSourceListener); - mReloadTask = new ReloadTask(); - mReloadTask.start(); - } - - private void assertIsActive(int index) { - if (index < mActiveStart && index >= mActiveEnd) { - throw new IllegalArgumentException(String.format( - "%s not in (%s, %s)", index, mActiveStart, mActiveEnd)); - } - } - - public MediaSet getMediaSet(int index) { - assertIsActive(index); - return mData[index % mData.length]; - } - - public MediaItem getCoverItem(int index) { - assertIsActive(index); - return mCoverItem[index % mCoverItem.length]; - } - - public int getTotalCount(int index) { - assertIsActive(index); - return mTotalCount[index % mTotalCount.length]; - } - - public int getActiveStart() { - return mActiveStart; - } - - public boolean isActive(int index) { - return index >= mActiveStart && index < mActiveEnd; - } - - public int size() { - return mSize; - } - - // Returns the index of the MediaSet with the given path or - // -1 if the path is not cached - public int findSet(Path id) { - int length = mData.length; - for (int i = mContentStart; i < mContentEnd; i++) { - MediaSet set = mData[i % length]; - if (set != null && id == set.getPath()) { - return i; - } - } - return -1; - } - - private void clearSlot(int slotIndex) { - mData[slotIndex] = null; - mCoverItem[slotIndex] = null; - mTotalCount[slotIndex] = 0; - mItemVersion[slotIndex] = MediaObject.INVALID_DATA_VERSION; - mSetVersion[slotIndex] = MediaObject.INVALID_DATA_VERSION; - } - - private void setContentWindow(int contentStart, int contentEnd) { - if (contentStart == mContentStart && contentEnd == mContentEnd) return; - int length = mCoverItem.length; - - int start = this.mContentStart; - int end = this.mContentEnd; - - mContentStart = contentStart; - mContentEnd = contentEnd; - - if (contentStart >= end || start >= contentEnd) { - for (int i = start, n = end; i < n; ++i) { - clearSlot(i % length); - } - } else { - for (int i = start; i < contentStart; ++i) { - clearSlot(i % length); - } - for (int i = contentEnd, n = end; i < n; ++i) { - clearSlot(i % length); - } - } - mReloadTask.notifyDirty(); - } - - public void setActiveWindow(int start, int end) { - if (start == mActiveStart && end == mActiveEnd) return; - - Utils.assertTrue(start <= end - && end - start <= mCoverItem.length && end <= mSize); - - mActiveStart = start; - mActiveEnd = end; - - int length = mCoverItem.length; - // If no data is visible, keep the cache content - if (start == end) return; - - int contentStart = Utils.clamp((start + end) / 2 - length / 2, - 0, Math.max(0, mSize - length)); - int contentEnd = Math.min(contentStart + length, mSize); - if (mContentStart > start || mContentEnd < end - || Math.abs(contentStart - mContentStart) > MIN_LOAD_COUNT) { - setContentWindow(contentStart, contentEnd); - } - } - - private class MySourceListener implements ContentListener { - @Override - public void onContentDirty() { - mReloadTask.notifyDirty(); - } - } - - public void setModelListener(DataListener listener) { - mDataListener = listener; - } - - public void setLoadingListener(LoadingListener listener) { - mLoadingListener = listener; - } - - private static class UpdateInfo { - public long version; - public int index; - - public int size; - public MediaSet item; - public MediaItem cover; - public int totalCount; - } - - private class GetUpdateInfo implements Callable<UpdateInfo> { - - private final long mVersion; - - public GetUpdateInfo(long version) { - mVersion = version; - } - - private int getInvalidIndex(long version) { - long setVersion[] = mSetVersion; - int length = setVersion.length; - for (int i = mContentStart, n = mContentEnd; i < n; ++i) { - int index = i % length; - if (setVersion[i % length] != version) return i; - } - return INDEX_NONE; - } - - @Override - public UpdateInfo call() throws Exception { - int index = getInvalidIndex(mVersion); - if (index == INDEX_NONE && mSourceVersion == mVersion) return null; - UpdateInfo info = new UpdateInfo(); - info.version = mSourceVersion; - info.index = index; - info.size = mSize; - return info; - } - } - - private class UpdateContent implements Callable<Void> { - private final UpdateInfo mUpdateInfo; - - public UpdateContent(UpdateInfo info) { - mUpdateInfo = info; - } - - @Override - public Void call() { - // Avoid notifying listeners of status change after pause - // Otherwise gallery will be in inconsistent state after resume. - if (mReloadTask == null) return null; - UpdateInfo info = mUpdateInfo; - mSourceVersion = info.version; - if (mSize != info.size) { - mSize = info.size; - if (mDataListener != null) mDataListener.onSizeChanged(mSize); - if (mContentEnd > mSize) mContentEnd = mSize; - if (mActiveEnd > mSize) mActiveEnd = mSize; - } - // Note: info.index could be INDEX_NONE, i.e., -1 - if (info.index >= mContentStart && info.index < mContentEnd) { - int pos = info.index % mCoverItem.length; - mSetVersion[pos] = info.version; - long itemVersion = info.item.getDataVersion(); - if (mItemVersion[pos] == itemVersion) return null; - mItemVersion[pos] = itemVersion; - mData[pos] = info.item; - mCoverItem[pos] = info.cover; - mTotalCount[pos] = info.totalCount; - if (mDataListener != null - && info.index >= mActiveStart && info.index < mActiveEnd) { - mDataListener.onContentChanged(info.index); - } - } - return null; - } - } - - private <T> T executeAndWait(Callable<T> callable) { - FutureTask<T> task = new FutureTask<T>(callable); - mMainHandler.sendMessage( - mMainHandler.obtainMessage(MSG_RUN_OBJECT, task)); - try { - return task.get(); - } catch (InterruptedException e) { - return null; - } catch (ExecutionException e) { - throw new RuntimeException(e); - } - } - - // TODO: load active range first - private class ReloadTask extends Thread { - private volatile boolean mActive = true; - private volatile boolean mDirty = true; - private volatile boolean mIsLoading = false; - - private void updateLoading(boolean loading) { - if (mIsLoading == loading) return; - mIsLoading = loading; - mMainHandler.sendEmptyMessage(loading ? MSG_LOAD_START : MSG_LOAD_FINISH); - } - - @Override - public void run() { - Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); - - boolean updateComplete = false; - while (mActive) { - synchronized (this) { - if (mActive && !mDirty && updateComplete) { - if (!mSource.isLoading()) updateLoading(false); - Utils.waitWithoutInterrupt(this); - continue; - } - } - mDirty = false; - updateLoading(true); - - long version = mSource.reload(); - UpdateInfo info = executeAndWait(new GetUpdateInfo(version)); - updateComplete = info == null; - if (updateComplete) continue; - if (info.version != version) { - info.version = version; - info.size = mSource.getSubMediaSetCount(); - - // If the size becomes smaller after reload(), we may - // receive from GetUpdateInfo an index which is too - // big. Because the main thread is not aware of the size - // change until we call UpdateContent. - if (info.index >= info.size) { - info.index = INDEX_NONE; - } - } - if (info.index != INDEX_NONE) { - info.item = mSource.getSubMediaSet(info.index); - if (info.item == null) continue; - info.cover = info.item.getCoverMediaItem(); - info.totalCount = info.item.getTotalMediaItemCount(); - } - executeAndWait(new UpdateContent(info)); - } - updateLoading(false); - } - - public synchronized void notifyDirty() { - mDirty = true; - notifyAll(); - } - - public synchronized void terminate() { - mActive = false; - notifyAll(); - } - } -} - - diff --git a/src/com/android/gallery3d/app/AlbumSetPage.java b/src/com/android/gallery3d/app/AlbumSetPage.java deleted file mode 100644 index dd9d8ec41..000000000 --- a/src/com/android/gallery3d/app/AlbumSetPage.java +++ /dev/null @@ -1,764 +0,0 @@ -/* - * Copyright (C) 2010 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.content.Context; -import android.content.Intent; -import android.graphics.Rect; -import android.os.Bundle; -import android.os.Handler; -import android.os.Message; -import android.view.HapticFeedbackConstants; -import android.view.Menu; -import android.view.MenuInflater; -import android.view.MenuItem; -import android.view.View; -import android.view.View.OnClickListener; -import android.widget.Button; -import android.widget.RelativeLayout; -import android.widget.Toast; - -import com.android.gallery3d.R; -import com.android.gallery3d.common.Utils; -import com.android.gallery3d.data.DataManager; -import com.android.gallery3d.data.MediaDetails; -import com.android.gallery3d.data.MediaItem; -import com.android.gallery3d.data.MediaObject; -import com.android.gallery3d.data.MediaSet; -import com.android.gallery3d.data.Path; -import com.android.gallery3d.glrenderer.FadeTexture; -import com.android.gallery3d.glrenderer.GLCanvas; -import com.android.gallery3d.picasasource.PicasaSource; -import com.android.gallery3d.settings.GallerySettings; -import com.android.gallery3d.ui.ActionModeHandler; -import com.android.gallery3d.ui.ActionModeHandler.ActionModeListener; -import com.android.gallery3d.ui.AlbumSetSlotRenderer; -import com.android.gallery3d.ui.DetailsHelper; -import com.android.gallery3d.ui.DetailsHelper.CloseListener; -import com.android.gallery3d.ui.GLRoot; -import com.android.gallery3d.ui.GLView; -import com.android.gallery3d.ui.SelectionManager; -import com.android.gallery3d.ui.SlotView; -import com.android.gallery3d.ui.SynchronizedHandler; -import com.android.gallery3d.util.Future; -import com.android.gallery3d.util.GalleryUtils; -import com.android.gallery3d.util.HelpUtils; - -import java.lang.ref.WeakReference; -import java.util.ArrayList; - -public class AlbumSetPage extends ActivityState implements - SelectionManager.SelectionListener, GalleryActionBar.ClusterRunner, - EyePosition.EyePositionListener, MediaSet.SyncListener { - @SuppressWarnings("unused") - private static final String TAG = "AlbumSetPage"; - - private static final int MSG_PICK_ALBUM = 1; - - public static final String KEY_MEDIA_PATH = "media-path"; - public static final String KEY_SET_TITLE = "set-title"; - public static final String KEY_SET_SUBTITLE = "set-subtitle"; - public static final String KEY_SELECTED_CLUSTER_TYPE = "selected-cluster"; - - private static final int DATA_CACHE_SIZE = 256; - private static final int REQUEST_DO_ANIMATION = 1; - - private static final int BIT_LOADING_RELOAD = 1; - private static final int BIT_LOADING_SYNC = 2; - - private boolean mIsActive = false; - private SlotView mSlotView; - private AlbumSetSlotRenderer mAlbumSetView; - private Config.AlbumSetPage mConfig; - - private MediaSet mMediaSet; - private String mTitle; - private String mSubtitle; - private boolean mShowClusterMenu; - private GalleryActionBar mActionBar; - private int mSelectedAction; - - protected SelectionManager mSelectionManager; - private AlbumSetDataLoader mAlbumSetDataAdapter; - - private boolean mGetContent; - private boolean mGetAlbum; - private ActionModeHandler mActionModeHandler; - private DetailsHelper mDetailsHelper; - private MyDetailsSource mDetailsSource; - private boolean mShowDetails; - private EyePosition mEyePosition; - private Handler mHandler; - - // The eyes' position of the user, the origin is at the center of the - // device and the unit is in pixels. - private float mX; - private float mY; - private float mZ; - - private Future<Integer> mSyncTask = null; - - private int mLoadingBits = 0; - private boolean mInitialSynced = false; - - private Button mCameraButton; - private boolean mShowedEmptyToastForSelf = false; - - @Override - protected int getBackgroundColorId() { - return R.color.albumset_background; - } - - private final GLView mRootPane = new GLView() { - private final float mMatrix[] = new float[16]; - - @Override - protected void onLayout( - boolean changed, int left, int top, int right, int bottom) { - mEyePosition.resetPosition(); - - int slotViewTop = mActionBar.getHeight() + mConfig.paddingTop; - int slotViewBottom = bottom - top - mConfig.paddingBottom; - int slotViewRight = right - left; - - if (mShowDetails) { - mDetailsHelper.layout(left, slotViewTop, right, bottom); - } else { - mAlbumSetView.setHighlightItemPath(null); - } - - mSlotView.layout(0, slotViewTop, slotViewRight, slotViewBottom); - } - - @Override - protected void render(GLCanvas canvas) { - canvas.save(GLCanvas.SAVE_FLAG_MATRIX); - GalleryUtils.setViewPointMatrix(mMatrix, - getWidth() / 2 + mX, getHeight() / 2 + mY, mZ); - canvas.multiplyMatrix(mMatrix, 0); - super.render(canvas); - canvas.restore(); - } - }; - - @Override - public void onEyePositionChanged(float x, float y, float z) { - mRootPane.lockRendering(); - mX = x; - mY = y; - mZ = z; - mRootPane.unlockRendering(); - mRootPane.invalidate(); - } - - @Override - public void onBackPressed() { - if (mShowDetails) { - hideDetails(); - } else if (mSelectionManager.inSelectionMode()) { - mSelectionManager.leaveSelectionMode(); - } else { - super.onBackPressed(); - } - } - - private void getSlotCenter(int slotIndex, int center[]) { - Rect offset = new Rect(); - mRootPane.getBoundsOf(mSlotView, offset); - Rect r = mSlotView.getSlotRect(slotIndex); - int scrollX = mSlotView.getScrollX(); - int scrollY = mSlotView.getScrollY(); - center[0] = offset.left + (r.left + r.right) / 2 - scrollX; - center[1] = offset.top + (r.top + r.bottom) / 2 - scrollY; - } - - public void onSingleTapUp(int slotIndex) { - if (!mIsActive) return; - - if (mSelectionManager.inSelectionMode()) { - MediaSet targetSet = mAlbumSetDataAdapter.getMediaSet(slotIndex); - if (targetSet == null) return; // Content is dirty, we shall reload soon - mSelectionManager.toggle(targetSet.getPath()); - mSlotView.invalidate(); - } else { - // Show pressed-up animation for the single-tap. - mAlbumSetView.setPressedIndex(slotIndex); - mAlbumSetView.setPressedUp(); - mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_PICK_ALBUM, slotIndex, 0), - FadeTexture.DURATION); - } - } - - private static boolean albumShouldOpenInFilmstrip(MediaSet album) { - int itemCount = album.getMediaItemCount(); - ArrayList<MediaItem> list = (itemCount == 1) ? album.getMediaItem(0, 1) : null; - // open in film strip only if there's one item in the album and the item exists - return (list != null && !list.isEmpty()); - } - - WeakReference<Toast> mEmptyAlbumToast = null; - - private void showEmptyAlbumToast(int toastLength) { - Toast toast; - if (mEmptyAlbumToast != null) { - toast = mEmptyAlbumToast.get(); - if (toast != null) { - toast.show(); - return; - } - } - toast = Toast.makeText(mActivity, R.string.empty_album, toastLength); - mEmptyAlbumToast = new WeakReference<Toast>(toast); - toast.show(); - } - - private void hideEmptyAlbumToast() { - if (mEmptyAlbumToast != null) { - Toast toast = mEmptyAlbumToast.get(); - if (toast != null) toast.cancel(); - } - } - - private void pickAlbum(int slotIndex) { - if (!mIsActive) return; - - MediaSet targetSet = mAlbumSetDataAdapter.getMediaSet(slotIndex); - if (targetSet == null) return; // Content is dirty, we shall reload soon - if (targetSet.getTotalMediaItemCount() == 0) { - showEmptyAlbumToast(Toast.LENGTH_SHORT); - return; - } - hideEmptyAlbumToast(); - - String mediaPath = targetSet.getPath().toString(); - - Bundle data = new Bundle(getData()); - int[] center = new int[2]; - getSlotCenter(slotIndex, center); - data.putIntArray(AlbumPage.KEY_SET_CENTER, center); - if (mGetAlbum && targetSet.isLeafAlbum()) { - Activity activity = mActivity; - Intent result = new Intent() - .putExtra(AlbumPicker.KEY_ALBUM_PATH, targetSet.getPath().toString()); - activity.setResult(Activity.RESULT_OK, result); - activity.finish(); - } else if (targetSet.getSubMediaSetCount() > 0) { - data.putString(AlbumSetPage.KEY_MEDIA_PATH, mediaPath); - mActivity.getStateManager().startStateForResult( - AlbumSetPage.class, REQUEST_DO_ANIMATION, data); - } else { - if (!mGetContent && albumShouldOpenInFilmstrip(targetSet)) { - data.putParcelable(PhotoPage.KEY_OPEN_ANIMATION_RECT, - mSlotView.getSlotRect(slotIndex, mRootPane)); - data.putInt(PhotoPage.KEY_INDEX_HINT, 0); - data.putString(PhotoPage.KEY_MEDIA_SET_PATH, - mediaPath); - data.putBoolean(PhotoPage.KEY_START_IN_FILMSTRIP, true); - data.putBoolean(PhotoPage.KEY_IN_CAMERA_ROLL, targetSet.isCameraRoll()); - mActivity.getStateManager().startStateForResult( - FilmstripPage.class, AlbumPage.REQUEST_PHOTO, data); - return; - } - data.putString(AlbumPage.KEY_MEDIA_PATH, mediaPath); - - // We only show cluster menu in the first AlbumPage in stack - boolean inAlbum = mActivity.getStateManager().hasStateClass(AlbumPage.class); - data.putBoolean(AlbumPage.KEY_SHOW_CLUSTER_MENU, !inAlbum); - mActivity.getStateManager().startStateForResult( - AlbumPage.class, REQUEST_DO_ANIMATION, data); - } - } - - private void onDown(int index) { - mAlbumSetView.setPressedIndex(index); - } - - private void onUp(boolean followedByLongPress) { - if (followedByLongPress) { - // Avoid showing press-up animations for long-press. - mAlbumSetView.setPressedIndex(-1); - } else { - mAlbumSetView.setPressedUp(); - } - } - - public void onLongTap(int slotIndex) { - if (mGetContent || mGetAlbum) return; - MediaSet set = mAlbumSetDataAdapter.getMediaSet(slotIndex); - if (set == null) return; - mSelectionManager.setAutoLeaveSelectionMode(true); - mSelectionManager.toggle(set.getPath()); - mSlotView.invalidate(); - } - - @Override - public void doCluster(int clusterType) { - String basePath = mMediaSet.getPath().toString(); - String newPath = FilterUtils.switchClusterPath(basePath, clusterType); - Bundle data = new Bundle(getData()); - data.putString(AlbumSetPage.KEY_MEDIA_PATH, newPath); - data.putInt(KEY_SELECTED_CLUSTER_TYPE, clusterType); - mActivity.getStateManager().switchState(this, AlbumSetPage.class, data); - } - - @Override - public void onCreate(Bundle data, Bundle restoreState) { - super.onCreate(data, restoreState); - initializeViews(); - initializeData(data); - Context context = mActivity.getAndroidContext(); - mGetContent = data.getBoolean(Gallery.KEY_GET_CONTENT, false); - mGetAlbum = data.getBoolean(Gallery.KEY_GET_ALBUM, false); - mTitle = data.getString(AlbumSetPage.KEY_SET_TITLE); - mSubtitle = data.getString(AlbumSetPage.KEY_SET_SUBTITLE); - mEyePosition = new EyePosition(context, this); - mDetailsSource = new MyDetailsSource(); - mActionBar = mActivity.getGalleryActionBar(); - mSelectedAction = data.getInt(AlbumSetPage.KEY_SELECTED_CLUSTER_TYPE, - FilterUtils.CLUSTER_BY_ALBUM); - - mHandler = new SynchronizedHandler(mActivity.getGLRoot()) { - @Override - public void handleMessage(Message message) { - switch (message.what) { - case MSG_PICK_ALBUM: { - pickAlbum(message.arg1); - break; - } - default: throw new AssertionError(message.what); - } - } - }; - } - - @Override - public void onDestroy() { - super.onDestroy(); - cleanupCameraButton(); - mActionModeHandler.destroy(); - } - - private boolean setupCameraButton() { - if (!GalleryUtils.isCameraAvailable(mActivity)) return false; - RelativeLayout galleryRoot = (RelativeLayout) ((Activity) mActivity) - .findViewById(R.id.gallery_root); - if (galleryRoot == null) return false; - - mCameraButton = new Button(mActivity); - mCameraButton.setText(R.string.camera_label); - mCameraButton.setCompoundDrawablesWithIntrinsicBounds(0, R.drawable.frame_overlay_gallery_camera, 0, 0); - mCameraButton.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View arg0) { - GalleryUtils.startCameraActivity(mActivity); - } - }); - RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams( - RelativeLayout.LayoutParams.WRAP_CONTENT, - RelativeLayout.LayoutParams.WRAP_CONTENT); - lp.addRule(RelativeLayout.CENTER_IN_PARENT); - galleryRoot.addView(mCameraButton, lp); - return true; - } - - private void cleanupCameraButton() { - if (mCameraButton == null) return; - RelativeLayout galleryRoot = (RelativeLayout) ((Activity) mActivity) - .findViewById(R.id.gallery_root); - if (galleryRoot == null) return; - galleryRoot.removeView(mCameraButton); - mCameraButton = null; - } - - private void showCameraButton() { - if (mCameraButton == null && !setupCameraButton()) return; - mCameraButton.setVisibility(View.VISIBLE); - } - - private void hideCameraButton() { - if (mCameraButton == null) return; - mCameraButton.setVisibility(View.GONE); - } - - private void clearLoadingBit(int loadingBit) { - mLoadingBits &= ~loadingBit; - if (mLoadingBits == 0 && mIsActive) { - if (mAlbumSetDataAdapter.size() == 0) { - // If this is not the top of the gallery folder hierarchy, - // tell the parent AlbumSetPage instance to handle displaying - // the empty album toast, otherwise show it within this - // instance - if (mActivity.getStateManager().getStateCount() > 1) { - Intent result = new Intent(); - result.putExtra(AlbumPage.KEY_EMPTY_ALBUM, true); - setStateResult(Activity.RESULT_OK, result); - mActivity.getStateManager().finishState(this); - } else { - mShowedEmptyToastForSelf = true; - showEmptyAlbumToast(Toast.LENGTH_LONG); - mSlotView.invalidate(); - showCameraButton(); - } - return; - } - } - // Hide the empty album toast if we are in the root instance of - // AlbumSetPage and the album is no longer empty (for instance, - // after a sync is completed and web albums have been synced) - if (mShowedEmptyToastForSelf) { - mShowedEmptyToastForSelf = false; - hideEmptyAlbumToast(); - hideCameraButton(); - } - } - - private void setLoadingBit(int loadingBit) { - mLoadingBits |= loadingBit; - } - - @Override - public void onPause() { - super.onPause(); - mIsActive = false; - mAlbumSetDataAdapter.pause(); - mAlbumSetView.pause(); - mActionModeHandler.pause(); - mEyePosition.pause(); - DetailsHelper.pause(); - // Call disableClusterMenu to avoid receiving callback after paused. - // Don't hide menu here otherwise the list menu will disappear earlier than - // the action bar, which is janky and unwanted behavior. - mActionBar.disableClusterMenu(false); - if (mSyncTask != null) { - mSyncTask.cancel(); - mSyncTask = null; - clearLoadingBit(BIT_LOADING_SYNC); - } - } - - @Override - public void onResume() { - super.onResume(); - mIsActive = true; - setContentPane(mRootPane); - - // Set the reload bit here to prevent it exit this page in clearLoadingBit(). - setLoadingBit(BIT_LOADING_RELOAD); - mAlbumSetDataAdapter.resume(); - - mAlbumSetView.resume(); - mEyePosition.resume(); - mActionModeHandler.resume(); - if (mShowClusterMenu) { - mActionBar.enableClusterMenu(mSelectedAction, this); - } - if (!mInitialSynced) { - setLoadingBit(BIT_LOADING_SYNC); - mSyncTask = mMediaSet.requestSync(AlbumSetPage.this); - } - } - - private void initializeData(Bundle data) { - String mediaPath = data.getString(AlbumSetPage.KEY_MEDIA_PATH); - mMediaSet = mActivity.getDataManager().getMediaSet(mediaPath); - mSelectionManager.setSourceMediaSet(mMediaSet); - mAlbumSetDataAdapter = new AlbumSetDataLoader( - mActivity, mMediaSet, DATA_CACHE_SIZE); - mAlbumSetDataAdapter.setLoadingListener(new MyLoadingListener()); - mAlbumSetView.setModel(mAlbumSetDataAdapter); - } - - private void initializeViews() { - mSelectionManager = new SelectionManager(mActivity, true); - mSelectionManager.setSelectionListener(this); - - mConfig = Config.AlbumSetPage.get(mActivity); - mSlotView = new SlotView(mActivity, mConfig.slotViewSpec); - mAlbumSetView = new AlbumSetSlotRenderer( - mActivity, mSelectionManager, mSlotView, mConfig.labelSpec, - mConfig.placeholderColor); - mSlotView.setSlotRenderer(mAlbumSetView); - mSlotView.setListener(new SlotView.SimpleListener() { - @Override - public void onDown(int index) { - AlbumSetPage.this.onDown(index); - } - - @Override - public void onUp(boolean followedByLongPress) { - AlbumSetPage.this.onUp(followedByLongPress); - } - - @Override - public void onSingleTapUp(int slotIndex) { - AlbumSetPage.this.onSingleTapUp(slotIndex); - } - - @Override - public void onLongTap(int slotIndex) { - AlbumSetPage.this.onLongTap(slotIndex); - } - }); - - mActionModeHandler = new ActionModeHandler(mActivity, mSelectionManager); - mActionModeHandler.setActionModeListener(new ActionModeListener() { - @Override - public boolean onActionItemClicked(MenuItem item) { - return onItemSelected(item); - } - }); - mRootPane.addComponent(mSlotView); - } - - @Override - protected boolean onCreateActionBar(Menu menu) { - Activity activity = mActivity; - final boolean inAlbum = mActivity.getStateManager().hasStateClass(AlbumPage.class); - MenuInflater inflater = getSupportMenuInflater(); - - if (mGetContent) { - inflater.inflate(R.menu.pickup, menu); - int typeBits = mData.getInt( - Gallery.KEY_TYPE_BITS, DataManager.INCLUDE_IMAGE); - mActionBar.setTitle(GalleryUtils.getSelectionModePrompt(typeBits)); - } else if (mGetAlbum) { - inflater.inflate(R.menu.pickup, menu); - mActionBar.setTitle(R.string.select_album); - } else { - inflater.inflate(R.menu.albumset, menu); - boolean wasShowingClusterMenu = mShowClusterMenu; - mShowClusterMenu = !inAlbum; - boolean selectAlbums = !inAlbum && - mActionBar.getClusterTypeAction() == FilterUtils.CLUSTER_BY_ALBUM; - MenuItem selectItem = menu.findItem(R.id.action_select); - selectItem.setTitle(activity.getString( - selectAlbums ? R.string.select_album : R.string.select_group)); - - MenuItem cameraItem = menu.findItem(R.id.action_camera); - cameraItem.setVisible(GalleryUtils.isCameraAvailable(activity)); - - FilterUtils.setupMenuItems(mActionBar, mMediaSet.getPath(), false); - - Intent helpIntent = HelpUtils.getHelpIntent(activity); - - MenuItem helpItem = menu.findItem(R.id.action_general_help); - helpItem.setVisible(helpIntent != null); - if (helpIntent != null) helpItem.setIntent(helpIntent); - - mActionBar.setTitle(mTitle); - mActionBar.setSubtitle(mSubtitle); - if (mShowClusterMenu != wasShowingClusterMenu) { - if (mShowClusterMenu) { - mActionBar.enableClusterMenu(mSelectedAction, this); - } else { - mActionBar.disableClusterMenu(true); - } - } - } - return true; - } - - @Override - protected boolean onItemSelected(MenuItem item) { - Activity activity = mActivity; - switch (item.getItemId()) { - case R.id.action_cancel: - activity.setResult(Activity.RESULT_CANCELED); - activity.finish(); - return true; - case R.id.action_select: - mSelectionManager.setAutoLeaveSelectionMode(false); - mSelectionManager.enterSelectionMode(); - return true; - case R.id.action_details: - if (mAlbumSetDataAdapter.size() != 0) { - if (mShowDetails) { - hideDetails(); - } else { - showDetails(); - } - } else { - Toast.makeText(activity, - activity.getText(R.string.no_albums_alert), - Toast.LENGTH_SHORT).show(); - } - return true; - case R.id.action_camera: { - GalleryUtils.startCameraActivity(activity); - return true; - } - case R.id.action_manage_offline: { - Bundle data = new Bundle(); - String mediaPath = mActivity.getDataManager().getTopSetPath( - DataManager.INCLUDE_ALL); - data.putString(AlbumSetPage.KEY_MEDIA_PATH, mediaPath); - mActivity.getStateManager().startState(ManageCachePage.class, data); - return true; - } - case R.id.action_sync_picasa_albums: { - PicasaSource.requestSync(activity); - return true; - } - case R.id.action_settings: { - activity.startActivity(new Intent(activity, GallerySettings.class)); - return true; - } - default: - return false; - } - } - - @Override - protected void onStateResult(int requestCode, int resultCode, Intent data) { - if (data != null && data.getBooleanExtra(AlbumPage.KEY_EMPTY_ALBUM, false)) { - showEmptyAlbumToast(Toast.LENGTH_SHORT); - } - switch (requestCode) { - case REQUEST_DO_ANIMATION: { - mSlotView.startRisingAnimation(); - } - } - } - - private String getSelectedString() { - int count = mSelectionManager.getSelectedCount(); - int action = mActionBar.getClusterTypeAction(); - int string = action == FilterUtils.CLUSTER_BY_ALBUM - ? R.plurals.number_of_albums_selected - : R.plurals.number_of_groups_selected; - String format = mActivity.getResources().getQuantityString(string, count); - return String.format(format, count); - } - - @Override - public void onSelectionModeChange(int mode) { - switch (mode) { - case SelectionManager.ENTER_SELECTION_MODE: { - mActionBar.disableClusterMenu(true); - mActionModeHandler.startActionMode(); - performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); - break; - } - case SelectionManager.LEAVE_SELECTION_MODE: { - mActionModeHandler.finishActionMode(); - if (mShowClusterMenu) { - mActionBar.enableClusterMenu(mSelectedAction, this); - } - mRootPane.invalidate(); - break; - } - case SelectionManager.SELECT_ALL_MODE: { - mActionModeHandler.updateSupportedOperation(); - mRootPane.invalidate(); - break; - } - } - } - - @Override - public void onSelectionChange(Path path, boolean selected) { - mActionModeHandler.setTitle(getSelectedString()); - mActionModeHandler.updateSupportedOperation(path, selected); - } - - private void hideDetails() { - mShowDetails = false; - mDetailsHelper.hide(); - mAlbumSetView.setHighlightItemPath(null); - mSlotView.invalidate(); - } - - private void showDetails() { - mShowDetails = true; - if (mDetailsHelper == null) { - mDetailsHelper = new DetailsHelper(mActivity, mRootPane, mDetailsSource); - mDetailsHelper.setCloseListener(new CloseListener() { - @Override - public void onClose() { - hideDetails(); - } - }); - } - mDetailsHelper.show(); - } - - @Override - public void onSyncDone(final MediaSet mediaSet, final int resultCode) { - if (resultCode == MediaSet.SYNC_RESULT_ERROR) { - Log.d(TAG, "onSyncDone: " + Utils.maskDebugInfo(mediaSet.getName()) + " result=" - + resultCode); - } - ((Activity) mActivity).runOnUiThread(new Runnable() { - @Override - public void run() { - GLRoot root = mActivity.getGLRoot(); - root.lockRenderThread(); - try { - if (resultCode == MediaSet.SYNC_RESULT_SUCCESS) { - mInitialSynced = true; - } - clearLoadingBit(BIT_LOADING_SYNC); - if (resultCode == MediaSet.SYNC_RESULT_ERROR && mIsActive) { - Log.w(TAG, "failed to load album set"); - } - } finally { - root.unlockRenderThread(); - } - } - }); - } - - private class MyLoadingListener implements LoadingListener { - @Override - public void onLoadingStarted() { - setLoadingBit(BIT_LOADING_RELOAD); - } - - @Override - public void onLoadingFinished(boolean loadingFailed) { - clearLoadingBit(BIT_LOADING_RELOAD); - } - } - - private class MyDetailsSource implements DetailsHelper.DetailsSource { - private int mIndex; - - @Override - public int size() { - return mAlbumSetDataAdapter.size(); - } - - @Override - public int setIndex() { - Path id = mSelectionManager.getSelected(false).get(0); - mIndex = mAlbumSetDataAdapter.findSet(id); - return mIndex; - } - - @Override - public MediaDetails getDetails() { - MediaObject item = mAlbumSetDataAdapter.getMediaSet(mIndex); - if (item != null) { - mAlbumSetView.setHighlightItemPath(item.getPath()); - return item.getDetails(); - } else { - return null; - } - } - } -} diff --git a/src/com/android/gallery3d/app/AppBridge.java b/src/com/android/gallery3d/app/AppBridge.java deleted file mode 100644 index ee55fa6db..000000000 --- a/src/com/android/gallery3d/app/AppBridge.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * 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.graphics.Rect; -import android.os.Parcel; -import android.os.Parcelable; - -import com.android.gallery3d.ui.ScreenNail; - -// This is the bridge to connect a PhotoPage to the external environment. -public abstract class AppBridge implements Parcelable { - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel dest, int flags) { - } - - ////////////////////////////////////////////////////////////////////////// - // These are requests sent from PhotoPage to the app - ////////////////////////////////////////////////////////////////////////// - - public abstract boolean isPanorama(); - public abstract boolean isStaticCamera(); - public abstract ScreenNail attachScreenNail(); - public abstract void detachScreenNail(); - - // Return true if the tap is consumed. - public abstract boolean onSingleTapUp(int x, int y); - - // This is used to notify that the screen nail will be drawn in full screen - // or not in next draw() call. - public abstract void onFullScreenChanged(boolean full); - - ////////////////////////////////////////////////////////////////////////// - // These are requests send from app to PhotoPage - ////////////////////////////////////////////////////////////////////////// - - public interface Server { - // Set the camera frame relative to GLRootView. - public void setCameraRelativeFrame(Rect frame); - // Switch to the previous or next picture using the capture animation. - // The offset is -1 to switch to the previous picture, 1 to switch to - // the next picture. - public boolean switchWithCaptureAnimation(int offset); - // Enable or disable the swiping gestures (the default is enabled). - public void setSwipingEnabled(boolean enabled); - // Notify that the ScreenNail is changed. - public void notifyScreenNailChanged(); - // Add a new media item to the secure album. - public void addSecureAlbumItem(boolean isVideo, int id); - } - - // If server is null, the services are not available. - public abstract void setServer(Server server); -} diff --git a/src/com/android/gallery3d/app/BatchService.java b/src/com/android/gallery3d/app/BatchService.java deleted file mode 100644 index 564001d5b..000000000 --- a/src/com/android/gallery3d/app/BatchService.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * 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.Service; -import android.content.Intent; -import android.os.Binder; -import android.os.IBinder; - -import com.android.gallery3d.util.ThreadPool; - -public class BatchService extends Service { - - public class LocalBinder extends Binder { - BatchService getService() { - return BatchService.this; - } - } - - private final IBinder mBinder = new LocalBinder(); - private ThreadPool mThreadPool = new ThreadPool(1, 1); - - @Override - public IBinder onBind(Intent intent) { - return mBinder; - } - - // The threadpool returned by getThreadPool must have only 1 thread - // running at a time, as MenuExecutor (atrociously) depends on this - // guarantee for synchronization. - public ThreadPool getThreadPool() { - return mThreadPool; - } -} diff --git a/src/com/android/gallery3d/app/CommonControllerOverlay.java b/src/com/android/gallery3d/app/CommonControllerOverlay.java deleted file mode 100644 index 9adb4e7a8..000000000 --- a/src/com/android/gallery3d/app/CommonControllerOverlay.java +++ /dev/null @@ -1,346 +0,0 @@ -/* - * 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.content.Context; -import android.content.res.Resources; -import android.graphics.Rect; -import android.view.Gravity; -import android.view.KeyEvent; -import android.view.MotionEvent; -import android.view.View; -import android.view.View.OnClickListener; -import android.widget.FrameLayout; -import android.widget.ImageView; -import android.widget.ImageView.ScaleType; -import android.widget.LinearLayout; -import android.widget.ProgressBar; -import android.widget.RelativeLayout; -import android.widget.TextView; - -import com.android.gallery3d.R; - -/** - * The common playback controller for the Movie Player or Video Trimming. - */ -public abstract class CommonControllerOverlay extends FrameLayout implements - ControllerOverlay, - OnClickListener, - TimeBar.Listener { - - protected enum State { - PLAYING, - PAUSED, - ENDED, - ERROR, - LOADING - } - - private static final float ERROR_MESSAGE_RELATIVE_PADDING = 1.0f / 6; - - protected Listener mListener; - - protected final View mBackground; - protected TimeBar mTimeBar; - - protected View mMainView; - protected final LinearLayout mLoadingView; - protected final TextView mErrorView; - protected final ImageView mPlayPauseReplayView; - - protected State mState; - - protected boolean mCanReplay = true; - - public void setSeekable(boolean canSeek) { - mTimeBar.setSeekable(canSeek); - } - - public CommonControllerOverlay(Context context) { - super(context); - - mState = State.LOADING; - // TODO: Move the following layout code into xml file. - LayoutParams wrapContent = - new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); - LayoutParams matchParent = - new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); - - mBackground = new View(context); - mBackground.setBackgroundColor(context.getResources().getColor(R.color.darker_transparent)); - addView(mBackground, matchParent); - - // Depending on the usage, the timeBar can show a single scrubber, or - // multiple ones for trimming. - createTimeBar(context); - addView(mTimeBar, wrapContent); - mTimeBar.setContentDescription( - context.getResources().getString(R.string.accessibility_time_bar)); - mLoadingView = new LinearLayout(context); - mLoadingView.setOrientation(LinearLayout.VERTICAL); - mLoadingView.setGravity(Gravity.CENTER_HORIZONTAL); - ProgressBar spinner = new ProgressBar(context); - spinner.setIndeterminate(true); - mLoadingView.addView(spinner, wrapContent); - TextView loadingText = createOverlayTextView(context); - loadingText.setText(R.string.loading_video); - mLoadingView.addView(loadingText, wrapContent); - addView(mLoadingView, wrapContent); - - mPlayPauseReplayView = new ImageView(context); - mPlayPauseReplayView.setImageResource(R.drawable.ic_vidcontrol_play); - mPlayPauseReplayView.setContentDescription( - context.getResources().getString(R.string.accessibility_play_video)); - mPlayPauseReplayView.setBackgroundResource(R.drawable.bg_vidcontrol); - mPlayPauseReplayView.setScaleType(ScaleType.CENTER); - mPlayPauseReplayView.setFocusable(true); - mPlayPauseReplayView.setClickable(true); - mPlayPauseReplayView.setOnClickListener(this); - addView(mPlayPauseReplayView, wrapContent); - - mErrorView = createOverlayTextView(context); - addView(mErrorView, matchParent); - - RelativeLayout.LayoutParams params = - new RelativeLayout.LayoutParams( - LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); - setLayoutParams(params); - hide(); - } - - abstract protected void createTimeBar(Context context); - - private TextView createOverlayTextView(Context context) { - TextView view = new TextView(context); - view.setGravity(Gravity.CENTER); - view.setTextColor(0xFFFFFFFF); - view.setPadding(0, 15, 0, 15); - return view; - } - - @Override - public void setListener(Listener listener) { - this.mListener = listener; - } - - @Override - public void setCanReplay(boolean canReplay) { - this.mCanReplay = canReplay; - } - - @Override - public View getView() { - return this; - } - - @Override - public void showPlaying() { - mState = State.PLAYING; - showMainView(mPlayPauseReplayView); - } - - @Override - public void showPaused() { - mState = State.PAUSED; - showMainView(mPlayPauseReplayView); - } - - @Override - public void showEnded() { - mState = State.ENDED; - if (mCanReplay) showMainView(mPlayPauseReplayView); - } - - @Override - public void showLoading() { - mState = State.LOADING; - showMainView(mLoadingView); - } - - @Override - public void showErrorMessage(String message) { - mState = State.ERROR; - int padding = (int) (getMeasuredWidth() * ERROR_MESSAGE_RELATIVE_PADDING); - mErrorView.setPadding( - padding, mErrorView.getPaddingTop(), padding, mErrorView.getPaddingBottom()); - mErrorView.setText(message); - showMainView(mErrorView); - } - - @Override - public void setTimes(int currentTime, int totalTime, - int trimStartTime, int trimEndTime) { - mTimeBar.setTime(currentTime, totalTime, trimStartTime, trimEndTime); - } - - public void hide() { - mPlayPauseReplayView.setVisibility(View.INVISIBLE); - mLoadingView.setVisibility(View.INVISIBLE); - mBackground.setVisibility(View.INVISIBLE); - mTimeBar.setVisibility(View.INVISIBLE); - setVisibility(View.INVISIBLE); - setFocusable(true); - requestFocus(); - } - - private void showMainView(View view) { - mMainView = view; - mErrorView.setVisibility(mMainView == mErrorView ? View.VISIBLE : View.INVISIBLE); - mLoadingView.setVisibility(mMainView == mLoadingView ? View.VISIBLE : View.INVISIBLE); - mPlayPauseReplayView.setVisibility( - mMainView == mPlayPauseReplayView ? View.VISIBLE : View.INVISIBLE); - show(); - } - - @Override - public void show() { - updateViews(); - setVisibility(View.VISIBLE); - setFocusable(false); - } - - @Override - public void onClick(View view) { - if (mListener != null) { - if (view == mPlayPauseReplayView) { - if (mState == State.ENDED) { - if (mCanReplay) { - mListener.onReplay(); - } - } else if (mState == State.PAUSED || mState == State.PLAYING) { - mListener.onPlayPause(); - } - } - } - } - - @Override - public boolean onKeyDown(int keyCode, KeyEvent event) { - return super.onKeyDown(keyCode, event); - } - - @Override - public boolean onTouchEvent(MotionEvent event) { - if (super.onTouchEvent(event)) { - return true; - } - return false; - } - - // The paddings of 4 sides which covered by system components. E.g. - // +-----------------+\ - // | Action Bar | insets.top - // +-----------------+/ - // | | - // | Content Area | insets.right = insets.left = 0 - // | | - // +-----------------+\ - // | Navigation Bar | insets.bottom - // +-----------------+/ - // Please see View.fitSystemWindows() for more details. - private final Rect mWindowInsets = new Rect(); - - @Override - protected boolean fitSystemWindows(Rect insets) { - // We don't set the paddings of this View, otherwise, - // the content will get cropped outside window - mWindowInsets.set(insets); - return true; - } - - @Override - protected void onLayout(boolean changed, int left, int top, int right, int bottom) { - Rect insets = mWindowInsets; - int pl = insets.left; // the left paddings - int pr = insets.right; - int pt = insets.top; - int pb = insets.bottom; - - int h = bottom - top; - int w = right - left; - boolean error = mErrorView.getVisibility() == View.VISIBLE; - - int y = h - pb; - // Put both TimeBar and Background just above the bottom system - // component. - // But extend the background to the width of the screen, since we don't - // care if it will be covered by a system component and it looks better. - mBackground.layout(0, y - mTimeBar.getBarHeight(), w, y); - mTimeBar.layout(pl, y - mTimeBar.getPreferredHeight(), w - pr, y); - - // Put the play/pause/next/ previous button in the center of the screen - layoutCenteredView(mPlayPauseReplayView, 0, 0, w, h); - - if (mMainView != null) { - layoutCenteredView(mMainView, 0, 0, w, h); - } - } - - private void layoutCenteredView(View view, int l, int t, int r, int b) { - int cw = view.getMeasuredWidth(); - int ch = view.getMeasuredHeight(); - int cl = (r - l - cw) / 2; - int ct = (b - t - ch) / 2; - view.layout(cl, ct, cl + cw, ct + ch); - } - - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - super.onMeasure(widthMeasureSpec, heightMeasureSpec); - measureChildren(widthMeasureSpec, heightMeasureSpec); - } - - protected void updateViews() { - mBackground.setVisibility(View.VISIBLE); - mTimeBar.setVisibility(View.VISIBLE); - Resources resources = getContext().getResources(); - int imageResource = R.drawable.ic_vidcontrol_reload; - String contentDescription = resources.getString(R.string.accessibility_reload_video); - if (mState == State.PAUSED) { - imageResource = R.drawable.ic_vidcontrol_play; - contentDescription = resources.getString(R.string.accessibility_play_video); - } else if (mState == State.PLAYING) { - imageResource = R.drawable.ic_vidcontrol_pause; - contentDescription = resources.getString(R.string.accessibility_pause_video); - } - - mPlayPauseReplayView.setImageResource(imageResource); - mPlayPauseReplayView.setContentDescription(contentDescription); - mPlayPauseReplayView.setVisibility( - (mState != State.LOADING && mState != State.ERROR && - !(mState == State.ENDED && !mCanReplay)) - ? View.VISIBLE : View.GONE); - requestLayout(); - } - - // TimeBar listener - - @Override - public void onScrubbingStart() { - mListener.onSeekStart(); - } - - @Override - public void onScrubbingMove(int time) { - mListener.onSeekMove(time); - } - - @Override - public void onScrubbingEnd(int time, int trimStartTime, int trimEndTime) { - mListener.onSeekEnd(time, trimStartTime, trimEndTime); - } -} diff --git a/src/com/android/gallery3d/app/Config.java b/src/com/android/gallery3d/app/Config.java deleted file mode 100644 index 7183acc33..000000000 --- a/src/com/android/gallery3d/app/Config.java +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Copyright (C) 2010 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.content.Context; -import android.content.res.Resources; - -import com.android.gallery3d.R; -import com.android.gallery3d.ui.AlbumSetSlotRenderer; -import com.android.gallery3d.ui.SlotView; - -final class Config { - public static class AlbumSetPage { - private static AlbumSetPage sInstance; - - public SlotView.Spec slotViewSpec; - public AlbumSetSlotRenderer.LabelSpec labelSpec; - public int paddingTop; - public int paddingBottom; - public int placeholderColor; - - public static synchronized AlbumSetPage get(Context context) { - if (sInstance == null) { - sInstance = new AlbumSetPage(context); - } - return sInstance; - } - - private AlbumSetPage(Context context) { - Resources r = context.getResources(); - - placeholderColor = r.getColor(R.color.albumset_placeholder); - - slotViewSpec = new SlotView.Spec(); - slotViewSpec.rowsLand = r.getInteger(R.integer.albumset_rows_land); - slotViewSpec.rowsPort = r.getInteger(R.integer.albumset_rows_port); - slotViewSpec.slotGap = r.getDimensionPixelSize(R.dimen.albumset_slot_gap); - slotViewSpec.slotHeightAdditional = 0; - - paddingTop = r.getDimensionPixelSize(R.dimen.albumset_padding_top); - paddingBottom = r.getDimensionPixelSize(R.dimen.albumset_padding_bottom); - - labelSpec = new AlbumSetSlotRenderer.LabelSpec(); - labelSpec.labelBackgroundHeight = r.getDimensionPixelSize( - R.dimen.albumset_label_background_height); - labelSpec.titleOffset = r.getDimensionPixelSize( - R.dimen.albumset_title_offset); - labelSpec.countOffset = r.getDimensionPixelSize( - R.dimen.albumset_count_offset); - labelSpec.titleFontSize = r.getDimensionPixelSize( - R.dimen.albumset_title_font_size); - labelSpec.countFontSize = r.getDimensionPixelSize( - R.dimen.albumset_count_font_size); - labelSpec.leftMargin = r.getDimensionPixelSize( - R.dimen.albumset_left_margin); - labelSpec.titleRightMargin = r.getDimensionPixelSize( - R.dimen.albumset_title_right_margin); - labelSpec.iconSize = r.getDimensionPixelSize( - R.dimen.albumset_icon_size); - labelSpec.backgroundColor = r.getColor( - R.color.albumset_label_background); - labelSpec.titleColor = r.getColor(R.color.albumset_label_title); - labelSpec.countColor = r.getColor(R.color.albumset_label_count); - } - } - - public static class AlbumPage { - private static AlbumPage sInstance; - - public SlotView.Spec slotViewSpec; - public int placeholderColor; - - public static synchronized AlbumPage get(Context context) { - if (sInstance == null) { - sInstance = new AlbumPage(context); - } - return sInstance; - } - - private AlbumPage(Context context) { - Resources r = context.getResources(); - - placeholderColor = r.getColor(R.color.album_placeholder); - - slotViewSpec = new SlotView.Spec(); - slotViewSpec.rowsLand = r.getInteger(R.integer.album_rows_land); - slotViewSpec.rowsPort = r.getInteger(R.integer.album_rows_port); - slotViewSpec.slotGap = r.getDimensionPixelSize(R.dimen.album_slot_gap); - } - } - - public static class ManageCachePage extends AlbumSetPage { - private static ManageCachePage sInstance; - - public final int cachePinSize; - public final int cachePinMargin; - - public static synchronized ManageCachePage get(Context context) { - if (sInstance == null) { - sInstance = new ManageCachePage(context); - } - return sInstance; - } - - public ManageCachePage(Context context) { - super(context); - Resources r = context.getResources(); - cachePinSize = r.getDimensionPixelSize(R.dimen.cache_pin_size); - cachePinMargin = r.getDimensionPixelSize(R.dimen.cache_pin_margin); - } - } -} - diff --git a/src/com/android/gallery3d/app/ControllerOverlay.java b/src/com/android/gallery3d/app/ControllerOverlay.java deleted file mode 100644 index 078f59e28..000000000 --- a/src/com/android/gallery3d/app/ControllerOverlay.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (C) 2011 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.view.View; - -public interface ControllerOverlay { - - interface Listener { - void onPlayPause(); - void onSeekStart(); - void onSeekMove(int time); - void onSeekEnd(int time, int trimStartTime, int trimEndTime); - void onShown(); - void onHidden(); - void onReplay(); - } - - void setListener(Listener listener); - - void setCanReplay(boolean canReplay); - - /** - * @return The overlay view that should be added to the player. - */ - View getView(); - - void show(); - - void showPlaying(); - - void showPaused(); - - void showEnded(); - - void showLoading(); - - void showErrorMessage(String message); - - void setTimes(int currentTime, int totalTime, - int trimStartTime, int trimEndTime); -} diff --git a/src/com/android/gallery3d/app/DialogPicker.java b/src/com/android/gallery3d/app/DialogPicker.java deleted file mode 100644 index 7ca86e5b4..000000000 --- a/src/com/android/gallery3d/app/DialogPicker.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (C) 2010 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.content.Intent; -import android.os.Bundle; - -import com.android.gallery3d.util.GalleryUtils; - -public class DialogPicker extends PickerActivity { - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - int typeBits = GalleryUtils.determineTypeBits(this, getIntent()); - setTitle(GalleryUtils.getSelectionModePrompt(typeBits)); - Intent intent = getIntent(); - Bundle extras = intent.getExtras(); - Bundle data = extras == null ? new Bundle() : new Bundle(extras); - - data.putBoolean(Gallery.KEY_GET_CONTENT, true); - data.putString(AlbumSetPage.KEY_MEDIA_PATH, - getDataManager().getTopSetPath(typeBits)); - getStateManager().startState(AlbumSetPage.class, data); - } -} diff --git a/src/com/android/gallery3d/app/EyePosition.java b/src/com/android/gallery3d/app/EyePosition.java deleted file mode 100644 index d99d97b0e..000000000 --- a/src/com/android/gallery3d/app/EyePosition.java +++ /dev/null @@ -1,226 +0,0 @@ -/* - * Copyright (C) 2010 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.content.Context; -import android.hardware.Sensor; -import android.hardware.SensorEvent; -import android.hardware.SensorEventListener; -import android.hardware.SensorManager; -import android.os.SystemClock; -import android.util.FloatMath; -import android.view.Display; -import android.view.Surface; -import android.view.WindowManager; - -import com.android.gallery3d.common.Utils; -import com.android.gallery3d.util.GalleryUtils; - -public class EyePosition { - @SuppressWarnings("unused") - private static final String TAG = "EyePosition"; - - public interface EyePositionListener { - public void onEyePositionChanged(float x, float y, float z); - } - - private static final float GYROSCOPE_THRESHOLD = 0.15f; - private static final float GYROSCOPE_LIMIT = 10f; - private static final int GYROSCOPE_SETTLE_DOWN = 15; - private static final float GYROSCOPE_RESTORE_FACTOR = 0.995f; - - private static final float USER_ANGEL = (float) Math.toRadians(10); - private static final float USER_ANGEL_COS = FloatMath.cos(USER_ANGEL); - private static final float USER_ANGEL_SIN = FloatMath.sin(USER_ANGEL); - private static final float MAX_VIEW_RANGE = (float) 0.5; - private static final int NOT_STARTED = -1; - - private static final float USER_DISTANCE_METER = 0.3f; - - private Context mContext; - private EyePositionListener mListener; - private Display mDisplay; - // The eyes' position of the user, the origin is at the center of the - // device and the unit is in pixels. - private float mX; - private float mY; - private float mZ; - - private final float mUserDistance; // in pixel - private final float mLimit; - private long mStartTime = NOT_STARTED; - private Sensor mSensor; - private PositionListener mPositionListener = new PositionListener(); - - private int mGyroscopeCountdown = 0; - - public EyePosition(Context context, EyePositionListener listener) { - mContext = context; - mListener = listener; - mUserDistance = GalleryUtils.meterToPixel(USER_DISTANCE_METER); - mLimit = mUserDistance * MAX_VIEW_RANGE; - - WindowManager wManager = (WindowManager) mContext - .getSystemService(Context.WINDOW_SERVICE); - mDisplay = wManager.getDefaultDisplay(); - - // The 3D effect where the photo albums fan out in 3D based on angle - // of device tilt is currently disabled. -/* - SensorManager sManager = (SensorManager) mContext - .getSystemService(Context.SENSOR_SERVICE); - mSensor = sManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE); - if (mSensor == null) { - Log.w(TAG, "no gyroscope, use accelerometer instead"); - mSensor = sManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); - } - if (mSensor == null) { - Log.w(TAG, "no sensor available"); - } -*/ - } - - public void resetPosition() { - mStartTime = NOT_STARTED; - mX = mY = 0; - mZ = -mUserDistance; - mListener.onEyePositionChanged(mX, mY, mZ); - } - - /* - * We assume the user is at the following position - * - * /|\ user's eye - * | / - * -G(gravity) | / - * |_/ - * / |/_____\ -Y (-y direction of device) - * user angel - */ - private void onAccelerometerChanged(float gx, float gy, float gz) { - - float x = gx, y = gy, z = gz; - - switch (mDisplay.getRotation()) { - case Surface.ROTATION_90: x = -gy; y= gx; break; - case Surface.ROTATION_180: x = -gx; y = -gy; break; - case Surface.ROTATION_270: x = gy; y = -gx; break; - } - - float temp = x * x + y * y + z * z; - float t = -y /temp; - - float tx = t * x; - float ty = -1 + t * y; - float tz = t * z; - - float length = FloatMath.sqrt(tx * tx + ty * ty + tz * tz); - float glength = FloatMath.sqrt(temp); - - mX = Utils.clamp((x * USER_ANGEL_COS / glength - + tx * USER_ANGEL_SIN / length) * mUserDistance, - -mLimit, mLimit); - mY = -Utils.clamp((y * USER_ANGEL_COS / glength - + ty * USER_ANGEL_SIN / length) * mUserDistance, - -mLimit, mLimit); - mZ = -FloatMath.sqrt( - mUserDistance * mUserDistance - mX * mX - mY * mY); - mListener.onEyePositionChanged(mX, mY, mZ); - } - - private void onGyroscopeChanged(float gx, float gy, float gz) { - long now = SystemClock.elapsedRealtime(); - float distance = (gx > 0 ? gx : -gx) + (gy > 0 ? gy : - gy); - if (distance < GYROSCOPE_THRESHOLD - || distance > GYROSCOPE_LIMIT || mGyroscopeCountdown > 0) { - --mGyroscopeCountdown; - mStartTime = now; - float limit = mUserDistance / 20f; - if (mX > limit || mX < -limit || mY > limit || mY < -limit) { - mX *= GYROSCOPE_RESTORE_FACTOR; - mY *= GYROSCOPE_RESTORE_FACTOR; - mZ = (float) -Math.sqrt( - mUserDistance * mUserDistance - mX * mX - mY * mY); - mListener.onEyePositionChanged(mX, mY, mZ); - } - return; - } - - float t = (now - mStartTime) / 1000f * mUserDistance * (-mZ); - mStartTime = now; - - float x = -gy, y = -gx; - switch (mDisplay.getRotation()) { - case Surface.ROTATION_90: x = -gx; y= gy; break; - case Surface.ROTATION_180: x = gy; y = gx; break; - case Surface.ROTATION_270: x = gx; y = -gy; break; - } - - mX = Utils.clamp((float) (mX + x * t / Math.hypot(mZ, mX)), - -mLimit, mLimit) * GYROSCOPE_RESTORE_FACTOR; - mY = Utils.clamp((float) (mY + y * t / Math.hypot(mZ, mY)), - -mLimit, mLimit) * GYROSCOPE_RESTORE_FACTOR; - - mZ = -FloatMath.sqrt( - mUserDistance * mUserDistance - mX * mX - mY * mY); - mListener.onEyePositionChanged(mX, mY, mZ); - } - - private class PositionListener implements SensorEventListener { - @Override - public void onAccuracyChanged(Sensor sensor, int accuracy) { - } - - @Override - public void onSensorChanged(SensorEvent event) { - switch (event.sensor.getType()) { - case Sensor.TYPE_GYROSCOPE: { - onGyroscopeChanged( - event.values[0], event.values[1], event.values[2]); - break; - } - case Sensor.TYPE_ACCELEROMETER: { - onAccelerometerChanged( - event.values[0], event.values[1], event.values[2]); - } - } - } - } - - public void pause() { - if (mSensor != null) { - SensorManager sManager = (SensorManager) mContext - .getSystemService(Context.SENSOR_SERVICE); - sManager.unregisterListener(mPositionListener); - } - } - - public void resume() { - if (mSensor != null) { - SensorManager sManager = (SensorManager) mContext - .getSystemService(Context.SENSOR_SERVICE); - sManager.registerListener(mPositionListener, - mSensor, SensorManager.SENSOR_DELAY_GAME); - } - - mStartTime = NOT_STARTED; - mGyroscopeCountdown = GYROSCOPE_SETTLE_DOWN; - mX = mY = 0; - mZ = -mUserDistance; - mListener.onEyePositionChanged(mX, mY, mZ); - } -} diff --git a/src/com/android/gallery3d/app/FilmstripPage.java b/src/com/android/gallery3d/app/FilmstripPage.java deleted file mode 100644 index a9726cdc9..000000000 --- a/src/com/android/gallery3d/app/FilmstripPage.java +++ /dev/null @@ -1,21 +0,0 @@ -/* - * 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/FilterUtils.java b/src/com/android/gallery3d/app/FilterUtils.java deleted file mode 100644 index bc28a9cc1..000000000 --- a/src/com/android/gallery3d/app/FilterUtils.java +++ /dev/null @@ -1,257 +0,0 @@ -/* - * Copyright (C) 2010 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 com.android.gallery3d.R; -import com.android.gallery3d.data.MediaObject; -import com.android.gallery3d.data.Path; - -// This class handles filtering and clustering. -// -// We allow at most only one filter operation at a time (Currently it -// doesn't make sense to use more than one). Also each clustering operation -// can be applied at most once. In addition, there is one more constraint -// ("fixed set constraint") described below. -// -// A clustered album (not including album set) and its base sets are fixed. -// For example, -// -// /cluster/{base_set}/time/7 -// -// This set and all sets inside base_set (recursively) are fixed because -// 1. We can not change this set to use another clustering condition (like -// changing "time" to "location"). -// 2. Neither can we change any set in the base_set. -// The reason is in both cases the 7th set may not exist in the new clustering. -// --------------------- -// newPath operation: create a new path based on a source path and put an extra -// condition on top of it: -// -// T = newFilterPath(S, filterType); -// T = newClusterPath(S, clusterType); -// -// Similar functions can be used to replace the current condition (if there is one). -// -// T = switchFilterPath(S, filterType); -// T = switchClusterPath(S, clusterType); -// -// For all fixed set in the path defined above, if some clusterType and -// filterType are already used, they cannot not be used as parameter for these -// functions. setupMenuItems() makes sure those types cannot be selected. -// -public class FilterUtils { - @SuppressWarnings("unused") - private static final String TAG = "FilterUtils"; - - public static final int CLUSTER_BY_ALBUM = 1; - public static final int CLUSTER_BY_TIME = 2; - public static final int CLUSTER_BY_LOCATION = 4; - public static final int CLUSTER_BY_TAG = 8; - public static final int CLUSTER_BY_SIZE = 16; - public static final int CLUSTER_BY_FACE = 32; - - public static final int FILTER_IMAGE_ONLY = 1; - public static final int FILTER_VIDEO_ONLY = 2; - public static final int FILTER_ALL = 4; - - // These are indices of the return values of getAppliedFilters(). - // The _F suffix means "fixed". - private static final int CLUSTER_TYPE = 0; - private static final int FILTER_TYPE = 1; - private static final int CLUSTER_TYPE_F = 2; - private static final int FILTER_TYPE_F = 3; - private static final int CLUSTER_CURRENT_TYPE = 4; - private static final int FILTER_CURRENT_TYPE = 5; - - public static void setupMenuItems(GalleryActionBar actionBar, Path path, boolean inAlbum) { - int[] result = new int[6]; - getAppliedFilters(path, result); - int ctype = result[CLUSTER_TYPE]; - int ftype = result[FILTER_TYPE]; - int ftypef = result[FILTER_TYPE_F]; - int ccurrent = result[CLUSTER_CURRENT_TYPE]; - int fcurrent = result[FILTER_CURRENT_TYPE]; - - setMenuItemApplied(actionBar, CLUSTER_BY_TIME, - (ctype & CLUSTER_BY_TIME) != 0, (ccurrent & CLUSTER_BY_TIME) != 0); - setMenuItemApplied(actionBar, CLUSTER_BY_LOCATION, - (ctype & CLUSTER_BY_LOCATION) != 0, (ccurrent & CLUSTER_BY_LOCATION) != 0); - setMenuItemApplied(actionBar, CLUSTER_BY_TAG, - (ctype & CLUSTER_BY_TAG) != 0, (ccurrent & CLUSTER_BY_TAG) != 0); - setMenuItemApplied(actionBar, CLUSTER_BY_FACE, - (ctype & CLUSTER_BY_FACE) != 0, (ccurrent & CLUSTER_BY_FACE) != 0); - - actionBar.setClusterItemVisibility(CLUSTER_BY_ALBUM, !inAlbum || ctype == 0); - - setMenuItemApplied(actionBar, R.id.action_cluster_album, ctype == 0, - ccurrent == 0); - - // A filtering is available if it's not applied, and the old filtering - // (if any) is not fixed. - setMenuItemAppliedEnabled(actionBar, R.string.show_images_only, - (ftype & FILTER_IMAGE_ONLY) != 0, - (ftype & FILTER_IMAGE_ONLY) == 0 && ftypef == 0, - (fcurrent & FILTER_IMAGE_ONLY) != 0); - setMenuItemAppliedEnabled(actionBar, R.string.show_videos_only, - (ftype & FILTER_VIDEO_ONLY) != 0, - (ftype & FILTER_VIDEO_ONLY) == 0 && ftypef == 0, - (fcurrent & FILTER_VIDEO_ONLY) != 0); - setMenuItemAppliedEnabled(actionBar, R.string.show_all, - ftype == 0, ftype != 0 && ftypef == 0, fcurrent == 0); - } - - // Gets the filters applied in the path. - private static void getAppliedFilters(Path path, int[] result) { - getAppliedFilters(path, result, false); - } - - private static void getAppliedFilters(Path path, int[] result, boolean underCluster) { - String[] segments = path.split(); - // Recurse into sub media sets. - for (int i = 0; i < segments.length; i++) { - if (segments[i].startsWith("{")) { - String[] sets = Path.splitSequence(segments[i]); - for (int j = 0; j < sets.length; j++) { - Path sub = Path.fromString(sets[j]); - getAppliedFilters(sub, result, underCluster); - } - } - } - - // update current selection - if (segments[0].equals("cluster")) { - // if this is a clustered album, set underCluster to true. - if (segments.length == 4) { - underCluster = true; - } - - int ctype = toClusterType(segments[2]); - result[CLUSTER_TYPE] |= ctype; - result[CLUSTER_CURRENT_TYPE] = ctype; - if (underCluster) { - result[CLUSTER_TYPE_F] |= ctype; - } - } - } - - private static int toClusterType(String s) { - if (s.equals("time")) { - return CLUSTER_BY_TIME; - } else if (s.equals("location")) { - return CLUSTER_BY_LOCATION; - } else if (s.equals("tag")) { - return CLUSTER_BY_TAG; - } else if (s.equals("size")) { - return CLUSTER_BY_SIZE; - } else if (s.equals("face")) { - return CLUSTER_BY_FACE; - } - return 0; - } - - private static void setMenuItemApplied( - GalleryActionBar model, int id, boolean applied, boolean updateTitle) { - model.setClusterItemEnabled(id, !applied); - } - - private static void setMenuItemAppliedEnabled(GalleryActionBar model, int id, boolean applied, boolean enabled, boolean updateTitle) { - model.setClusterItemEnabled(id, enabled); - } - - // Add a specified filter to the path. - public static String newFilterPath(String base, int filterType) { - int mediaType; - switch (filterType) { - case FILTER_IMAGE_ONLY: - mediaType = MediaObject.MEDIA_TYPE_IMAGE; - break; - case FILTER_VIDEO_ONLY: - mediaType = MediaObject.MEDIA_TYPE_VIDEO; - break; - default: /* FILTER_ALL */ - return base; - } - - return "/filter/mediatype/" + mediaType + "/{" + base + "}"; - } - - // Add a specified clustering to the path. - public static String newClusterPath(String base, int clusterType) { - String kind; - switch (clusterType) { - case CLUSTER_BY_TIME: - kind = "time"; - break; - case CLUSTER_BY_LOCATION: - kind = "location"; - break; - case CLUSTER_BY_TAG: - kind = "tag"; - break; - case CLUSTER_BY_SIZE: - kind = "size"; - break; - case CLUSTER_BY_FACE: - kind = "face"; - break; - default: /* CLUSTER_BY_ALBUM */ - return base; - } - - return "/cluster/{" + base + "}/" + kind; - } - - // Change the topmost clustering to the specified type. - public static String switchClusterPath(String base, int clusterType) { - return newClusterPath(removeOneClusterFromPath(base), clusterType); - } - - // Remove the topmost clustering (if any) from the path. - private static String removeOneClusterFromPath(String base) { - boolean[] done = new boolean[1]; - return removeOneClusterFromPath(base, done); - } - - private static String removeOneClusterFromPath(String base, boolean[] done) { - if (done[0]) return base; - - String[] segments = Path.split(base); - if (segments[0].equals("cluster")) { - done[0] = true; - return Path.splitSequence(segments[1])[0]; - } - - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < segments.length; i++) { - sb.append("/"); - if (segments[i].startsWith("{")) { - sb.append("{"); - String[] sets = Path.splitSequence(segments[i]); - for (int j = 0; j < sets.length; j++) { - if (j > 0) { - sb.append(","); - } - sb.append(removeOneClusterFromPath(sets[j], done)); - } - sb.append("}"); - } else { - sb.append(segments[i]); - } - } - return sb.toString(); - } -} diff --git a/src/com/android/gallery3d/app/Gallery.java b/src/com/android/gallery3d/app/Gallery.java deleted file mode 100644 index baef56b44..000000000 --- a/src/com/android/gallery3d/app/Gallery.java +++ /dev/null @@ -1,274 +0,0 @@ -/* - * Copyright (C) 2009 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.Dialog; -import android.content.ContentResolver; -import android.content.DialogInterface; -import android.content.DialogInterface.OnCancelListener; -import android.content.Intent; -import android.net.Uri; -import android.os.Bundle; -import android.view.InputDevice; -import android.view.MotionEvent; -import android.view.View; -import android.view.Window; -import android.view.WindowManager; -import android.widget.Toast; - -import com.android.gallery3d.R; -import com.android.gallery3d.common.Utils; -import com.android.gallery3d.data.DataManager; -import com.android.gallery3d.data.MediaItem; -import com.android.gallery3d.data.MediaSet; -import com.android.gallery3d.data.Path; -import com.android.gallery3d.picasasource.PicasaSource; -import com.android.gallery3d.util.GalleryUtils; - -public final class Gallery extends AbstractGalleryActivity implements OnCancelListener { - public static final String EXTRA_SLIDESHOW = "slideshow"; - public static final String EXTRA_DREAM = "dream"; - public static final String EXTRA_CROP = "crop"; - - public static final String ACTION_REVIEW = "com.android.camera.action.REVIEW"; - public static final String KEY_GET_CONTENT = "get-content"; - 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; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - 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) { - getStateManager().restoreFromState(savedInstanceState); - } else { - initializeByIntent(); - } - } - - private void initializeByIntent() { - Intent intent = getIntent(); - String action = intent.getAction(); - - if (Intent.ACTION_GET_CONTENT.equalsIgnoreCase(action)) { - startGetContent(intent); - } else if (Intent.ACTION_PICK.equalsIgnoreCase(action)) { - // We do NOT really support the PICK intent. Handle it as - // the GET_CONTENT. However, we need to translate the type - // in the intent here. - Log.w(TAG, "action PICK is not supported"); - String type = Utils.ensureNotNull(intent.getType()); - if (type.startsWith("vnd.android.cursor.dir/")) { - if (type.endsWith("/image")) intent.setType("image/*"); - if (type.endsWith("/video")) intent.setType("video/*"); - } - startGetContent(intent); - } else if (Intent.ACTION_VIEW.equalsIgnoreCase(action) - || ACTION_REVIEW.equalsIgnoreCase(action)){ - startViewAction(intent); - } else { - startDefaultPage(); - } - } - - public void startDefaultPage() { - PicasaSource.showSignInReminder(this); - Bundle data = new Bundle(); - data.putString(AlbumSetPage.KEY_MEDIA_PATH, - getDataManager().getTopSetPath(DataManager.INCLUDE_ALL)); - getStateManager().startState(AlbumSetPage.class, data); - mVersionCheckDialog = PicasaSource.getVersionCheckDialog(this); - if (mVersionCheckDialog != null) { - mVersionCheckDialog.setOnCancelListener(this); - } - } - - private void startGetContent(Intent intent) { - Bundle data = intent.getExtras() != null - ? new Bundle(intent.getExtras()) - : new Bundle(); - data.putBoolean(KEY_GET_CONTENT, true); - int typeBits = GalleryUtils.determineTypeBits(this, intent); - data.putInt(KEY_TYPE_BITS, typeBits); - data.putString(AlbumSetPage.KEY_MEDIA_PATH, - getDataManager().getTopSetPath(typeBits)); - getStateManager().startState(AlbumSetPage.class, data); - } - - private String getContentType(Intent intent) { - String type = intent.getType(); - if (type != null) { - return GalleryUtils.MIME_TYPE_PANORAMA360.equals(type) - ? MediaItem.MIME_TYPE_JPEG : type; - } - - Uri uri = intent.getData(); - try { - return getContentResolver().getType(uri); - } catch (Throwable t) { - Log.w(TAG, "get type fail", t); - return null; - } - } - - private void startViewAction(Intent intent) { - Boolean slideshow = intent.getBooleanExtra(EXTRA_SLIDESHOW, false); - if (slideshow) { - getActionBar().hide(); - DataManager manager = getDataManager(); - Path path = manager.findPathByUri(intent.getData(), intent.getType()); - if (path == null || manager.getMediaObject(path) - instanceof MediaItem) { - path = Path.fromString( - manager.getTopSetPath(DataManager.INCLUDE_IMAGE)); - } - Bundle data = new Bundle(); - data.putString(SlideshowPage.KEY_SET_PATH, path.toString()); - data.putBoolean(SlideshowPage.KEY_RANDOM_ORDER, true); - data.putBoolean(SlideshowPage.KEY_REPEAT, true); - if (intent.getBooleanExtra(EXTRA_DREAM, false)) { - data.putBoolean(SlideshowPage.KEY_DREAM, true); - } - getStateManager().startState(SlideshowPage.class, data); - } else { - Bundle data = new Bundle(); - DataManager dm = getDataManager(); - Uri uri = intent.getData(); - String contentType = getContentType(intent); - if (contentType == null) { - Toast.makeText(this, - R.string.no_such_item, Toast.LENGTH_LONG).show(); - finish(); - return; - } - if (uri == null) { - int typeBits = GalleryUtils.determineTypeBits(this, intent); - data.putInt(KEY_TYPE_BITS, typeBits); - data.putString(AlbumSetPage.KEY_MEDIA_PATH, - getDataManager().getTopSetPath(typeBits)); - getStateManager().startState(AlbumSetPage.class, data); - } else if (contentType.startsWith( - ContentResolver.CURSOR_DIR_BASE_TYPE)) { - int mediaType = intent.getIntExtra(KEY_MEDIA_TYPES, 0); - if (mediaType != 0) { - uri = uri.buildUpon().appendQueryParameter( - KEY_MEDIA_TYPES, String.valueOf(mediaType)) - .build(); - } - Path setPath = dm.findPathByUri(uri, null); - MediaSet mediaSet = null; - if (setPath != null) { - mediaSet = (MediaSet) dm.getMediaObject(setPath); - } - if (mediaSet != null) { - if (mediaSet.isLeafAlbum()) { - data.putString(AlbumPage.KEY_MEDIA_PATH, setPath.toString()); - data.putString(AlbumPage.KEY_PARENT_MEDIA_PATH, - dm.getTopSetPath(DataManager.INCLUDE_ALL)); - getStateManager().startState(AlbumPage.class, data); - } else { - data.putString(AlbumSetPage.KEY_MEDIA_PATH, setPath.toString()); - getStateManager().startState(AlbumSetPage.class, data); - } - } else { - startDefaultPage(); - } - } else { - Path itemPath = dm.findPathByUri(uri, contentType); - Path albumPath = dm.getDefaultSetOf(itemPath); - - data.putString(PhotoPage.KEY_MEDIA_ITEM_PATH, itemPath.toString()); - - // TODO: Make the parameter "SingleItemOnly" public so other - // activities can reference it. - boolean singleItemOnly = (albumPath == null) - || intent.getBooleanExtra("SingleItemOnly", false); - if (!singleItemOnly) { - data.putString(PhotoPage.KEY_MEDIA_SET_PATH, albumPath.toString()); - // when FLAG_ACTIVITY_NEW_TASK is set, (e.g. when intent is fired - // from notification), back button should behave the same as up button - // rather than taking users back to the home screen - if (intent.getBooleanExtra(PhotoPage.KEY_TREAT_BACK_AS_UP, false) - || ((intent.getFlags() & Intent.FLAG_ACTIVITY_NEW_TASK) != 0)) { - data.putBoolean(PhotoPage.KEY_TREAT_BACK_AS_UP, true); - } - } - - getStateManager().startState(SinglePhotoPage.class, data); - } - } - } - - @Override - protected void onResume() { - Utils.assertTrue(getStateManager().getStateCount() > 0); - super.onResume(); - if (mVersionCheckDialog != null) { - mVersionCheckDialog.show(); - } - } - - @Override - protected void onPause() { - super.onPause(); - if (mVersionCheckDialog != null) { - mVersionCheckDialog.dismiss(); - } - } - - @Override - public void onCancel(DialogInterface dialog) { - if (dialog == mVersionCheckDialog) { - mVersionCheckDialog = null; - } - } - - @Override - public boolean onGenericMotionEvent(MotionEvent event) { - final boolean isTouchPad = (event.getSource() - & InputDevice.SOURCE_CLASS_POSITION) != 0; - if (isTouchPad) { - float maxX = event.getDevice().getMotionRange(MotionEvent.AXIS_X).getMax(); - float maxY = event.getDevice().getMotionRange(MotionEvent.AXIS_Y).getMax(); - View decor = getWindow().getDecorView(); - float scaleX = decor.getWidth() / maxX; - float scaleY = decor.getHeight() / maxY; - float x = event.getX() * scaleX; - //x = decor.getWidth() - x; // invert x - float y = event.getY() * scaleY; - //y = decor.getHeight() - y; // invert y - MotionEvent touchEvent = MotionEvent.obtain(event.getDownTime(), - event.getEventTime(), event.getAction(), x, y, event.getMetaState()); - return dispatchTouchEvent(touchEvent); - } - return super.onGenericMotionEvent(event); - } -} diff --git a/src/com/android/gallery3d/app/GalleryActionBar.java b/src/com/android/gallery3d/app/GalleryActionBar.java deleted file mode 100644 index 588f5842a..000000000 --- a/src/com/android/gallery3d/app/GalleryActionBar.java +++ /dev/null @@ -1,438 +0,0 @@ -/* - * Copyright (C) 2011 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.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; -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.android.gallery3d.R; -import com.android.gallery3d.common.ApiHelper; - -import java.util.ArrayList; - -public class GalleryActionBar implements OnNavigationListener { - @SuppressWarnings("unused") - private static final String TAG = "GalleryActionBar"; - - private ClusterRunner mClusterRunner; - private CharSequence[] mTitles; - private ArrayList<Integer> mActions; - private Context mContext; - private LayoutInflater mInflater; - private AbstractGalleryActivity mActivity; - private ActionBar mActionBar; - private int mCurrentIndex; - private ClusterAdapter mAdapter = new ClusterAdapter(); - - private AlbumModeAdapter mAlbumModeAdapter; - private OnAlbumModeSelectedListener mAlbumModeListener; - private int mLastAlbumModeSelected; - private CharSequence [] mAlbumModes; - public static final int ALBUM_FILMSTRIP_MODE_SELECTED = 0; - public static final int ALBUM_GRID_MODE_SELECTED = 1; - - public interface ClusterRunner { - public void doCluster(int id); - } - - public interface OnAlbumModeSelectedListener { - public void onAlbumModeSelected(int mode); - } - - private static class ActionItem { - public int action; - public boolean enabled; - public boolean visible; - public int spinnerTitle; - public int dialogTitle; - public int clusterBy; - - public ActionItem(int action, boolean applied, boolean enabled, int title, - int clusterBy) { - this(action, applied, enabled, title, title, clusterBy); - } - - public ActionItem(int action, boolean applied, boolean enabled, int spinnerTitle, - int dialogTitle, int clusterBy) { - this.action = action; - this.enabled = enabled; - this.spinnerTitle = spinnerTitle; - this.dialogTitle = dialogTitle; - this.clusterBy = clusterBy; - this.visible = true; - } - } - - private static final ActionItem[] sClusterItems = new ActionItem[] { - new ActionItem(FilterUtils.CLUSTER_BY_ALBUM, true, false, R.string.albums, - R.string.group_by_album), - new ActionItem(FilterUtils.CLUSTER_BY_LOCATION, true, false, - R.string.locations, R.string.location, R.string.group_by_location), - new ActionItem(FilterUtils.CLUSTER_BY_TIME, true, false, R.string.times, - R.string.time, R.string.group_by_time), - new ActionItem(FilterUtils.CLUSTER_BY_FACE, true, false, R.string.people, - R.string.group_by_faces), - new ActionItem(FilterUtils.CLUSTER_BY_TAG, true, false, R.string.tags, - R.string.group_by_tags) - }; - - private class ClusterAdapter extends BaseAdapter { - - @Override - public int getCount() { - return sClusterItems.length; - } - - @Override - public Object getItem(int position) { - return sClusterItems[position]; - } - - @Override - public long getItemId(int position) { - return sClusterItems[position].action; - } - - @Override - public View getView(int position, View convertView, ViewGroup parent) { - if (convertView == null) { - convertView = mInflater.inflate(R.layout.action_bar_text, - parent, false); - } - TextView view = (TextView) convertView; - view.setText(sClusterItems[position].spinnerTitle); - return convertView; - } - } - - private class AlbumModeAdapter extends BaseAdapter { - @Override - public int getCount() { - return mAlbumModes.length; - } - - @Override - public Object getItem(int position) { - return mAlbumModes[position]; - } - - @Override - public long getItemId(int position) { - return position; - } - - @Override - public View getView(int position, View convertView, ViewGroup parent) { - if (convertView == null) { - convertView = mInflater.inflate(R.layout.action_bar_two_line_text, - parent, false); - } - TwoLineListItem view = (TwoLineListItem) convertView; - view.getText1().setText(mActionBar.getTitle()); - view.getText2().setText((CharSequence) getItem(position)); - return convertView; - } - - @Override - public View getDropDownView(int position, View convertView, ViewGroup parent) { - if (convertView == null) { - convertView = mInflater.inflate(R.layout.action_bar_text, - parent, false); - } - TextView view = (TextView) convertView; - view.setText((CharSequence) getItem(position)); - return convertView; - } - } - - public static String getClusterByTypeString(Context context, int type) { - for (ActionItem item : sClusterItems) { - if (item.action == type) { - return context.getString(item.clusterBy); - } - } - return null; - } - - public GalleryActionBar(AbstractGalleryActivity activity) { - mActionBar = activity.getActionBar(); - mContext = activity.getAndroidContext(); - mActivity = activity; - mInflater = ((Activity) mActivity).getLayoutInflater(); - mCurrentIndex = 0; - } - - private void createDialogData() { - ArrayList<CharSequence> titles = new ArrayList<CharSequence>(); - mActions = new ArrayList<Integer>(); - for (ActionItem item : sClusterItems) { - if (item.enabled && item.visible) { - titles.add(mContext.getString(item.dialogTitle)); - mActions.add(item.action); - } - } - mTitles = new CharSequence[titles.size()]; - titles.toArray(mTitles); - } - - public int getHeight() { - return mActionBar != null ? mActionBar.getHeight() : 0; - } - - public void setClusterItemEnabled(int id, boolean enabled) { - for (ActionItem item : sClusterItems) { - if (item.action == id) { - item.enabled = enabled; - return; - } - } - } - - public void setClusterItemVisibility(int id, boolean visible) { - for (ActionItem item : sClusterItems) { - if (item.action == id) { - item.visible = visible; - return; - } - } - } - - public int getClusterTypeAction() { - return sClusterItems[mCurrentIndex].action; - } - - public void enableClusterMenu(int action, ClusterRunner runner) { - if (mActionBar != null) { - // Don't set cluster runner until action bar is ready. - mClusterRunner = null; - mActionBar.setListNavigationCallbacks(mAdapter, this); - mActionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_LIST); - setSelectedAction(action); - mClusterRunner = runner; - } - } - - // The only use case not to hideMenu in this method is to ensure - // all elements disappear at the same time when exiting gallery. - // hideMenu should always be true in all other cases. - public void disableClusterMenu(boolean hideMenu) { - if (mActionBar != null) { - mClusterRunner = null; - if (hideMenu) { - mActionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD); - } - } - } - - public void onConfigurationChanged() { - if (mActionBar != null && mAlbumModeListener != null) { - OnAlbumModeSelectedListener listener = mAlbumModeListener; - enableAlbumModeMenu(mLastAlbumModeSelected, listener); - } - } - - public void enableAlbumModeMenu(int selected, OnAlbumModeSelectedListener listener) { - if (mActionBar != null) { - if (mAlbumModeAdapter == null) { - // Initialize the album mode options if they haven't been already - Resources res = mActivity.getResources(); - mAlbumModes = new CharSequence[] { - res.getString(R.string.switch_photo_filmstrip), - res.getString(R.string.switch_photo_grid)}; - mAlbumModeAdapter = new AlbumModeAdapter(); - } - mAlbumModeListener = null; - mLastAlbumModeSelected = selected; - mActionBar.setListNavigationCallbacks(mAlbumModeAdapter, this); - mActionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_LIST); - mActionBar.setSelectedNavigationItem(selected); - mAlbumModeListener = listener; - } - } - - public void disableAlbumModeMenu(boolean hideMenu) { - if (mActionBar != null) { - mAlbumModeListener = null; - if (hideMenu) { - mActionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD); - } - } - } - - public void showClusterDialog(final ClusterRunner clusterRunner) { - createDialogData(); - final ArrayList<Integer> actions = mActions; - new AlertDialog.Builder(mContext).setTitle(R.string.group_by).setItems( - mTitles, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - // Need to lock rendering when operations invoked by system UI (main thread) are - // modifying slot data used in GL thread for rendering. - mActivity.getGLRoot().lockRenderThread(); - try { - clusterRunner.doCluster(actions.get(which).intValue()); - } finally { - mActivity.getGLRoot().unlockRenderThread(); - } - } - }).create().show(); - } - - @TargetApi(ApiHelper.VERSION_CODES.ICE_CREAM_SANDWICH) - private void setHomeButtonEnabled(boolean enabled) { - if (mActionBar != null) mActionBar.setHomeButtonEnabled(enabled); - } - - public void setDisplayOptions(boolean displayHomeAsUp, boolean showTitle) { - if (mActionBar == null) return; - int options = 0; - if (displayHomeAsUp) options |= ActionBar.DISPLAY_HOME_AS_UP; - if (showTitle) options |= ActionBar.DISPLAY_SHOW_TITLE; - - mActionBar.setDisplayOptions(options, - ActionBar.DISPLAY_HOME_AS_UP | ActionBar.DISPLAY_SHOW_TITLE); - mActionBar.setHomeButtonEnabled(displayHomeAsUp); - } - - public void setTitle(String title) { - if (mActionBar != null) mActionBar.setTitle(title); - } - - public void setTitle(int titleId) { - if (mActionBar != null) { - mActionBar.setTitle(mContext.getString(titleId)); - } - } - - public void setSubtitle(String title) { - if (mActionBar != null) mActionBar.setSubtitle(title); - } - - public void show() { - if (mActionBar != null) mActionBar.show(); - } - - public void hide() { - if (mActionBar != null) mActionBar.hide(); - } - - public void addOnMenuVisibilityListener(OnMenuVisibilityListener listener) { - if (mActionBar != null) mActionBar.addOnMenuVisibilityListener(listener); - } - - public void removeOnMenuVisibilityListener(OnMenuVisibilityListener listener) { - if (mActionBar != null) mActionBar.removeOnMenuVisibilityListener(listener); - } - - public boolean setSelectedAction(int type) { - if (mActionBar == null) return false; - - for (int i = 0, n = sClusterItems.length; i < n; i++) { - ActionItem item = sClusterItems[i]; - if (item.action == type) { - mActionBar.setSelectedNavigationItem(i); - mCurrentIndex = i; - return true; - } - } - return false; - } - - @Override - public boolean onNavigationItemSelected(int itemPosition, long itemId) { - if (itemPosition != mCurrentIndex && mClusterRunner != null - || mAlbumModeListener != null) { - // Need to lock rendering when operations invoked by system UI (main thread) are - // modifying slot data used in GL thread for rendering. - mActivity.getGLRoot().lockRenderThread(); - try { - if (mAlbumModeListener != null) { - mAlbumModeListener.onAlbumModeSelected(itemPosition); - } else { - mClusterRunner.doCluster(sClusterItems[itemPosition].action); - } - } finally { - mActivity.getGLRoot().unlockRenderThread(); - } - } - return false; - } - - private Menu mActionBarMenu; - private ShareActionProvider mSharePanoramaActionProvider; - private ShareActionProvider mShareActionProvider; - private Intent mSharePanoramaIntent; - private Intent mShareIntent; - - public void createActionBarMenu(int menuRes, Menu menu) { - mActivity.getMenuInflater().inflate(menuRes, menu); - mActionBarMenu = menu; - - MenuItem item = menu.findItem(R.id.action_share_panorama); - if (item != null) { - mSharePanoramaActionProvider = (ShareActionProvider) - item.getActionProvider(); - mSharePanoramaActionProvider - .setShareHistoryFileName("panorama_share_history.xml"); - mSharePanoramaActionProvider.setShareIntent(mSharePanoramaIntent); - } - - item = menu.findItem(R.id.action_share); - if (item != null) { - mShareActionProvider = (ShareActionProvider) - item.getActionProvider(); - mShareActionProvider - .setShareHistoryFileName("share_history.xml"); - mShareActionProvider.setShareIntent(mShareIntent); - } - } - - public Menu getMenu() { - return mActionBarMenu; - } - - public void setShareIntents(Intent sharePanoramaIntent, Intent shareIntent, - ShareActionProvider.OnShareTargetSelectedListener onShareListener) { - mSharePanoramaIntent = sharePanoramaIntent; - if (mSharePanoramaActionProvider != null) { - mSharePanoramaActionProvider.setShareIntent(sharePanoramaIntent); - } - mShareIntent = shareIntent; - if (mShareActionProvider != null) { - mShareActionProvider.setShareIntent(shareIntent); - mShareActionProvider.setOnShareTargetSelectedListener( - onShareListener); - } - } -} diff --git a/src/com/android/gallery3d/app/GalleryApp.java b/src/com/android/gallery3d/app/GalleryApp.java deleted file mode 100644 index b56b8a82c..000000000 --- a/src/com/android/gallery3d/app/GalleryApp.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (C) 2010 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.content.ContentResolver; -import android.content.Context; -import android.content.res.Resources; -import android.os.Looper; - -import com.android.gallery3d.data.DataManager; -import com.android.gallery3d.data.DownloadCache; -import com.android.gallery3d.data.ImageCacheService; -import com.android.gallery3d.util.ThreadPool; - -public interface GalleryApp { - public DataManager getDataManager(); - - public StitchingProgressManager getStitchingProgressManager(); - public ImageCacheService getImageCacheService(); - public DownloadCache getDownloadCache(); - public ThreadPool getThreadPool(); - - public Context getAndroidContext(); - public Looper getMainLooper(); - public ContentResolver getContentResolver(); - public Resources getResources(); -} diff --git a/src/com/android/gallery3d/app/GalleryAppImpl.java b/src/com/android/gallery3d/app/GalleryAppImpl.java deleted file mode 100644 index 2abdaa0c1..000000000 --- a/src/com/android/gallery3d/app/GalleryAppImpl.java +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Copyright (C) 2010 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.Application; -import android.content.Context; -import android.os.AsyncTask; - -import com.android.gallery3d.data.DataManager; -import com.android.gallery3d.data.DownloadCache; -import com.android.gallery3d.data.ImageCacheService; -import com.android.gallery3d.gadget.WidgetUtils; -import com.android.gallery3d.picasasource.PicasaSource; -import com.android.gallery3d.util.GalleryUtils; -import com.android.gallery3d.util.LightCycleHelper; -import com.android.gallery3d.util.ThreadPool; -import com.android.gallery3d.util.UsageStatistics; -import com.android.photos.data.MediaCache; - -import java.io.File; - -public class GalleryAppImpl extends Application implements GalleryApp { - - private static final String DOWNLOAD_FOLDER = "download"; - private static final long DOWNLOAD_CAPACITY = 64 * 1024 * 1024; // 64M - - private ImageCacheService mImageCacheService; - private Object mLock = new Object(); - private DataManager mDataManager; - private ThreadPool mThreadPool; - private DownloadCache mDownloadCache; - private StitchingProgressManager mStitchingProgressManager; - - @Override - public void onCreate() { - super.onCreate(); - com.android.camera.Util.initialize(this); - initializeAsyncTask(); - GalleryUtils.initialize(this); - WidgetUtils.initialize(this); - PicasaSource.initialize(this); - UsageStatistics.initialize(this); - MediaCache.initialize(this); - - mStitchingProgressManager = LightCycleHelper.createStitchingManagerInstance(this); - if (mStitchingProgressManager != null) { - mStitchingProgressManager.addChangeListener(getDataManager()); - } - } - - @Override - public Context getAndroidContext() { - return this; - } - - @Override - public synchronized DataManager getDataManager() { - if (mDataManager == null) { - mDataManager = new DataManager(this); - mDataManager.initializeSourceMap(); - } - return mDataManager; - } - - @Override - public StitchingProgressManager getStitchingProgressManager() { - return mStitchingProgressManager; - } - - @Override - public ImageCacheService getImageCacheService() { - // This method may block on file I/O so a dedicated lock is needed here. - synchronized (mLock) { - if (mImageCacheService == null) { - mImageCacheService = new ImageCacheService(getAndroidContext()); - } - return mImageCacheService; - } - } - - @Override - public synchronized ThreadPool getThreadPool() { - if (mThreadPool == null) { - mThreadPool = new ThreadPool(); - } - return mThreadPool; - } - - @Override - public synchronized DownloadCache getDownloadCache() { - if (mDownloadCache == null) { - File cacheDir = new File(getExternalCacheDir(), DOWNLOAD_FOLDER); - - if (!cacheDir.isDirectory()) cacheDir.mkdirs(); - - if (!cacheDir.isDirectory()) { - throw new RuntimeException( - "fail to create: " + cacheDir.getAbsolutePath()); - } - mDownloadCache = new DownloadCache(this, cacheDir, DOWNLOAD_CAPACITY); - } - return mDownloadCache; - } - - private void initializeAsyncTask() { - // AsyncTask class needs to be loaded in UI thread. - // So we load it here to comply the rule. - try { - Class.forName(AsyncTask.class.getName()); - } catch (ClassNotFoundException e) { - } - } -} diff --git a/src/com/android/gallery3d/app/GalleryContext.java b/src/com/android/gallery3d/app/GalleryContext.java deleted file mode 100644 index 06f4fe4d1..000000000 --- a/src/com/android/gallery3d/app/GalleryContext.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (C) 2010 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.content.Context; -import android.content.res.Resources; -import android.os.Looper; - -import com.android.gallery3d.data.DataManager; -import com.android.gallery3d.util.ThreadPool; - -public interface GalleryContext { - public DataManager getDataManager(); - - public Context getAndroidContext(); - - public Looper getMainLooper(); - public Resources getResources(); - public ThreadPool getThreadPool(); -} diff --git a/src/com/android/gallery3d/app/LoadingListener.java b/src/com/android/gallery3d/app/LoadingListener.java deleted file mode 100644 index e94df9307..000000000 --- a/src/com/android/gallery3d/app/LoadingListener.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (C) 2010 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 interface LoadingListener { - public void onLoadingStarted(); - /** - * Called when loading is complete or no further progress can be made. - * - * @param loadingFailed true if data source cannot provide requested data - */ - public void onLoadingFinished(boolean loadingFailed); -} diff --git a/src/com/android/gallery3d/app/Log.java b/src/com/android/gallery3d/app/Log.java deleted file mode 100644 index 07a8ea588..000000000 --- a/src/com/android/gallery3d/app/Log.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (C) 2010 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 Log { - public static int v(String tag, String msg) { - return android.util.Log.v(tag, msg); - } - public static int v(String tag, String msg, Throwable tr) { - return android.util.Log.v(tag, msg, tr); - } - public static int d(String tag, String msg) { - return android.util.Log.d(tag, msg); - } - public static int d(String tag, String msg, Throwable tr) { - return android.util.Log.d(tag, msg, tr); - } - public static int i(String tag, String msg) { - return android.util.Log.i(tag, msg); - } - public static int i(String tag, String msg, Throwable tr) { - return android.util.Log.i(tag, msg, tr); - } - public static int w(String tag, String msg) { - return android.util.Log.w(tag, msg); - } - public static int w(String tag, String msg, Throwable tr) { - return android.util.Log.w(tag, msg, tr); - } - public static int w(String tag, Throwable tr) { - return android.util.Log.w(tag, tr); - } - public static int e(String tag, String msg) { - return android.util.Log.e(tag, msg); - } - public static int e(String tag, String msg, Throwable tr) { - return android.util.Log.e(tag, msg, tr); - } -} diff --git a/src/com/android/gallery3d/app/ManageCachePage.java b/src/com/android/gallery3d/app/ManageCachePage.java deleted file mode 100644 index 4f5c35819..000000000 --- a/src/com/android/gallery3d/app/ManageCachePage.java +++ /dev/null @@ -1,419 +0,0 @@ -/* - * Copyright (C) 2010 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.content.res.Configuration; -import android.os.Bundle; -import android.os.Handler; -import android.os.Message; -import android.text.format.Formatter; -import android.view.LayoutInflater; -import android.view.View; -import android.view.View.OnClickListener; -import android.widget.FrameLayout; -import android.widget.ProgressBar; -import android.widget.TextView; -import android.widget.Toast; - -import com.android.gallery3d.R; -import com.android.gallery3d.common.Utils; -import com.android.gallery3d.data.MediaObject; -import com.android.gallery3d.data.MediaSet; -import com.android.gallery3d.data.Path; -import com.android.gallery3d.glrenderer.GLCanvas; -import com.android.gallery3d.ui.CacheStorageUsageInfo; -import com.android.gallery3d.ui.GLRoot; -import com.android.gallery3d.ui.GLView; -import com.android.gallery3d.ui.ManageCacheDrawer; -import com.android.gallery3d.ui.MenuExecutor; -import com.android.gallery3d.ui.SelectionManager; -import com.android.gallery3d.ui.SlotView; -import com.android.gallery3d.ui.SynchronizedHandler; -import com.android.gallery3d.util.Future; -import com.android.gallery3d.util.GalleryUtils; -import com.android.gallery3d.util.ThreadPool.Job; -import com.android.gallery3d.util.ThreadPool.JobContext; - -import java.util.ArrayList; - -public class ManageCachePage extends ActivityState implements - SelectionManager.SelectionListener, MenuExecutor.ProgressListener, - EyePosition.EyePositionListener, OnClickListener { - public static final String KEY_MEDIA_PATH = "media-path"; - - @SuppressWarnings("unused") - private static final String TAG = "ManageCachePage"; - - private static final int DATA_CACHE_SIZE = 256; - private static final int MSG_REFRESH_STORAGE_INFO = 1; - private static final int MSG_REQUEST_LAYOUT = 2; - private static final int PROGRESS_BAR_MAX = 10000; - - private SlotView mSlotView; - private MediaSet mMediaSet; - - protected SelectionManager mSelectionManager; - protected ManageCacheDrawer mSelectionDrawer; - private AlbumSetDataLoader mAlbumSetDataAdapter; - - private EyePosition mEyePosition; - - // The eyes' position of the user, the origin is at the center of the - // device and the unit is in pixels. - private float mX; - private float mY; - private float mZ; - - private int mAlbumCountToMakeAvailableOffline; - private View mFooterContent; - private CacheStorageUsageInfo mCacheStorageInfo; - private Future<Void> mUpdateStorageInfo; - private Handler mHandler; - private boolean mLayoutReady = false; - - @Override - protected int getBackgroundColorId() { - return R.color.cache_background; - } - - private GLView mRootPane = new GLView() { - private float mMatrix[] = new float[16]; - - @Override - protected void renderBackground(GLCanvas view) { - view.clearBuffer(getBackgroundColor()); - } - - @Override - protected void onLayout( - boolean changed, int left, int top, int right, int bottom) { - // Hack: our layout depends on other components on the screen. - // We assume the other components will complete before we get a change - // to run a message in main thread. - if (!mLayoutReady) { - mHandler.sendEmptyMessage(MSG_REQUEST_LAYOUT); - return; - } - mLayoutReady = false; - - mEyePosition.resetPosition(); - int slotViewTop = mActivity.getGalleryActionBar().getHeight(); - int slotViewBottom = bottom - top; - - View footer = mActivity.findViewById(R.id.footer); - if (footer != null) { - int location[] = {0, 0}; - footer.getLocationOnScreen(location); - slotViewBottom = location[1]; - } - - mSlotView.layout(0, slotViewTop, right - left, slotViewBottom); - } - - @Override - protected void render(GLCanvas canvas) { - canvas.save(GLCanvas.SAVE_FLAG_MATRIX); - GalleryUtils.setViewPointMatrix(mMatrix, - getWidth() / 2 + mX, getHeight() / 2 + mY, mZ); - canvas.multiplyMatrix(mMatrix, 0); - super.render(canvas); - canvas.restore(); - } - }; - - @Override - public void onEyePositionChanged(float x, float y, float z) { - mRootPane.lockRendering(); - mX = x; - mY = y; - mZ = z; - mRootPane.unlockRendering(); - mRootPane.invalidate(); - } - - private void onDown(int index) { - mSelectionDrawer.setPressedIndex(index); - } - - private void onUp() { - mSelectionDrawer.setPressedIndex(-1); - } - - public void onSingleTapUp(int slotIndex) { - MediaSet targetSet = mAlbumSetDataAdapter.getMediaSet(slotIndex); - if (targetSet == null) return; // Content is dirty, we shall reload soon - - // ignore selection action if the target set does not support cache - // operation (like a local album). - if ((targetSet.getSupportedOperations() - & MediaSet.SUPPORT_CACHE) == 0) { - showToastForLocalAlbum(); - return; - } - - Path path = targetSet.getPath(); - boolean isFullyCached = - (targetSet.getCacheFlag() == MediaObject.CACHE_FLAG_FULL); - boolean isSelected = mSelectionManager.isItemSelected(path); - - if (!isFullyCached) { - // We only count the media sets that will be made available offline - // in this session. - if (isSelected) { - --mAlbumCountToMakeAvailableOffline; - } else { - ++mAlbumCountToMakeAvailableOffline; - } - } - - long sizeOfTarget = targetSet.getCacheSize(); - mCacheStorageInfo.increaseTargetCacheSize( - (isFullyCached ^ isSelected) ? -sizeOfTarget : sizeOfTarget); - refreshCacheStorageInfo(); - - mSelectionManager.toggle(path); - mSlotView.invalidate(); - } - - @Override - public void onCreate(Bundle data, Bundle restoreState) { - super.onCreate(data, restoreState); - mCacheStorageInfo = new CacheStorageUsageInfo(mActivity); - initializeViews(); - initializeData(data); - mEyePosition = new EyePosition(mActivity.getAndroidContext(), this); - mHandler = new SynchronizedHandler(mActivity.getGLRoot()) { - @Override - public void handleMessage(Message message) { - switch (message.what) { - case MSG_REFRESH_STORAGE_INFO: - refreshCacheStorageInfo(); - break; - case MSG_REQUEST_LAYOUT: { - mLayoutReady = true; - removeMessages(MSG_REQUEST_LAYOUT); - mRootPane.requestLayout(); - break; - } - } - } - }; - } - - @Override - public void onConfigurationChanged(Configuration config) { - // We use different layout resources for different configs - initializeFooterViews(); - FrameLayout layout = (FrameLayout) ((Activity) mActivity).findViewById(R.id.footer); - if (layout.getVisibility() == View.VISIBLE) { - layout.removeAllViews(); - layout.addView(mFooterContent); - } - } - - @Override - public void onPause() { - super.onPause(); - mAlbumSetDataAdapter.pause(); - mSelectionDrawer.pause(); - mEyePosition.pause(); - - if (mUpdateStorageInfo != null) { - mUpdateStorageInfo.cancel(); - mUpdateStorageInfo = null; - } - mHandler.removeMessages(MSG_REFRESH_STORAGE_INFO); - - FrameLayout layout = (FrameLayout) ((Activity) mActivity).findViewById(R.id.footer); - layout.removeAllViews(); - layout.setVisibility(View.INVISIBLE); - } - - private Job<Void> mUpdateStorageInfoJob = new Job<Void>() { - @Override - public Void run(JobContext jc) { - mCacheStorageInfo.loadStorageInfo(jc); - if (!jc.isCancelled()) { - mHandler.sendEmptyMessage(MSG_REFRESH_STORAGE_INFO); - } - return null; - } - }; - - @Override - public void onResume() { - super.onResume(); - setContentPane(mRootPane); - mAlbumSetDataAdapter.resume(); - mSelectionDrawer.resume(); - mEyePosition.resume(); - mUpdateStorageInfo = mActivity.getThreadPool().submit(mUpdateStorageInfoJob); - FrameLayout layout = (FrameLayout) ((Activity) mActivity).findViewById(R.id.footer); - layout.addView(mFooterContent); - layout.setVisibility(View.VISIBLE); - } - - private void initializeData(Bundle data) { - String mediaPath = data.getString(ManageCachePage.KEY_MEDIA_PATH); - mMediaSet = mActivity.getDataManager().getMediaSet(mediaPath); - mSelectionManager.setSourceMediaSet(mMediaSet); - - // We will always be in selection mode in this page. - mSelectionManager.setAutoLeaveSelectionMode(false); - mSelectionManager.enterSelectionMode(); - - mAlbumSetDataAdapter = new AlbumSetDataLoader( - mActivity, mMediaSet, DATA_CACHE_SIZE); - mSelectionDrawer.setModel(mAlbumSetDataAdapter); - } - - private void initializeViews() { - Activity activity = mActivity; - - mSelectionManager = new SelectionManager(mActivity, true); - mSelectionManager.setSelectionListener(this); - - Config.ManageCachePage config = Config.ManageCachePage.get(activity); - mSlotView = new SlotView(mActivity, config.slotViewSpec); - mSelectionDrawer = new ManageCacheDrawer(mActivity, mSelectionManager, mSlotView, - config.labelSpec, config.cachePinSize, config.cachePinMargin); - mSlotView.setSlotRenderer(mSelectionDrawer); - mSlotView.setListener(new SlotView.SimpleListener() { - @Override - public void onDown(int index) { - ManageCachePage.this.onDown(index); - } - - @Override - public void onUp(boolean followedByLongPress) { - ManageCachePage.this.onUp(); - } - - @Override - public void onSingleTapUp(int slotIndex) { - ManageCachePage.this.onSingleTapUp(slotIndex); - } - }); - mRootPane.addComponent(mSlotView); - initializeFooterViews(); - } - - private void initializeFooterViews() { - Activity activity = mActivity; - - LayoutInflater inflater = activity.getLayoutInflater(); - mFooterContent = inflater.inflate(R.layout.manage_offline_bar, null); - - mFooterContent.findViewById(R.id.done).setOnClickListener(this); - refreshCacheStorageInfo(); - } - - @Override - public void onClick(View view) { - Utils.assertTrue(view.getId() == R.id.done); - GLRoot root = mActivity.getGLRoot(); - root.lockRenderThread(); - try { - ArrayList<Path> ids = mSelectionManager.getSelected(false); - if (ids.size() == 0) { - onBackPressed(); - return; - } - showToast(); - - MenuExecutor menuExecutor = new MenuExecutor(mActivity, mSelectionManager); - menuExecutor.startAction(R.id.action_toggle_full_caching, - R.string.process_caching_requests, this); - } finally { - root.unlockRenderThread(); - } - } - - private void showToast() { - if (mAlbumCountToMakeAvailableOffline > 0) { - Activity activity = mActivity; - Toast.makeText(activity, activity.getResources().getQuantityString( - R.plurals.make_albums_available_offline, - mAlbumCountToMakeAvailableOffline), - Toast.LENGTH_SHORT).show(); - } - } - - private void showToastForLocalAlbum() { - Activity activity = mActivity; - Toast.makeText(activity, activity.getResources().getString( - R.string.try_to_set_local_album_available_offline), - Toast.LENGTH_SHORT).show(); - } - - private void refreshCacheStorageInfo() { - ProgressBar progressBar = (ProgressBar) mFooterContent.findViewById(R.id.progress); - TextView status = (TextView) mFooterContent.findViewById(R.id.status); - progressBar.setMax(PROGRESS_BAR_MAX); - long totalBytes = mCacheStorageInfo.getTotalBytes(); - long usedBytes = mCacheStorageInfo.getUsedBytes(); - long expectedBytes = mCacheStorageInfo.getExpectedUsedBytes(); - long freeBytes = mCacheStorageInfo.getFreeBytes(); - - Activity activity = mActivity; - if (totalBytes == 0) { - progressBar.setProgress(0); - progressBar.setSecondaryProgress(0); - - // TODO: get the string translated - String label = activity.getString(R.string.free_space_format, "-"); - status.setText(label); - } else { - progressBar.setProgress((int) (usedBytes * PROGRESS_BAR_MAX / totalBytes)); - progressBar.setSecondaryProgress( - (int) (expectedBytes * PROGRESS_BAR_MAX / totalBytes)); - String label = activity.getString(R.string.free_space_format, - Formatter.formatFileSize(activity, freeBytes)); - status.setText(label); - } - } - - @Override - public void onProgressComplete(int result) { - onBackPressed(); - } - - @Override - public void onProgressUpdate(int index) { - } - - @Override - public void onSelectionModeChange(int mode) { - } - - @Override - public void onSelectionChange(Path path, boolean selected) { - } - - @Override - public void onConfirmDialogDismissed(boolean confirmed) { - } - - @Override - public void onConfirmDialogShown() { - } - - @Override - public void onProgressStart() { - } -} diff --git a/src/com/android/gallery3d/app/MovieActivity.java b/src/com/android/gallery3d/app/MovieActivity.java deleted file mode 100644 index 40edbbe4d..000000000 --- a/src/com/android/gallery3d/app/MovieActivity.java +++ /dev/null @@ -1,263 +0,0 @@ -/* - * Copyright (C) 2007 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.annotation.TargetApi; -import android.app.ActionBar; -import android.app.Activity; -import android.content.AsyncQueryHandler; -import android.content.ContentResolver; -import android.content.Intent; -import android.content.pm.ActivityInfo; -import android.database.Cursor; -import android.graphics.Bitmap; -import android.graphics.drawable.BitmapDrawable; -import android.media.AudioManager; -import android.net.Uri; -import android.os.Build; -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.android.gallery3d.R; -import com.android.gallery3d.common.ApiHelper; -import com.android.gallery3d.common.Utils; - -/** - * This activity plays a video from a specified URI. - * - * The client of this activity can pass a logo bitmap in the intent (KEY_LOGO_BITMAP) - * to set the action bar logo so the playback process looks more seamlessly integrated with - * the original activity. - */ -public class MovieActivity extends Activity { - @SuppressWarnings("unused") - private static final String TAG = "MovieActivity"; - public static final String KEY_LOGO_BITMAP = "logo-bitmap"; - public static final String KEY_TREAT_UP_AS_BACK = "treat-up-as-back"; - - private MoviePlayer mPlayer; - private boolean mFinishOnCompletion; - private Uri mUri; - private boolean mTreatUpAsBack; - - @TargetApi(Build.VERSION_CODES.JELLY_BEAN) - private void setSystemUiVisibility(View rootView) { - if (ApiHelper.HAS_VIEW_SYSTEM_UI_FLAG_LAYOUT_STABLE) { - rootView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE - | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN - | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION); - } - } - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - requestWindowFeature(Window.FEATURE_ACTION_BAR); - requestWindowFeature(Window.FEATURE_ACTION_BAR_OVERLAY); - - setContentView(R.layout.movie_view); - View rootView = findViewById(R.id.movie_view_root); - - setSystemUiVisibility(rootView); - - Intent intent = getIntent(); - initializeActionBar(intent); - mFinishOnCompletion = intent.getBooleanExtra( - MediaStore.EXTRA_FINISH_ON_COMPLETION, true); - mTreatUpAsBack = intent.getBooleanExtra(KEY_TREAT_UP_AS_BACK, false); - mPlayer = new MoviePlayer(rootView, this, intent.getData(), savedInstanceState, - !mFinishOnCompletion) { - @Override - public void onCompletion() { - if (mFinishOnCompletion) { - finish(); - } - } - }; - if (intent.hasExtra(MediaStore.EXTRA_SCREEN_ORIENTATION)) { - int orientation = intent.getIntExtra( - MediaStore.EXTRA_SCREEN_ORIENTATION, - ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED); - if (orientation != getRequestedOrientation()) { - setRequestedOrientation(orientation); - } - } - Window win = getWindow(); - WindowManager.LayoutParams winParams = win.getAttributes(); - winParams.buttonBrightness = WindowManager.LayoutParams.BRIGHTNESS_OVERRIDE_OFF; - winParams.flags |= WindowManager.LayoutParams.FLAG_FULLSCREEN; - win.setAttributes(winParams); - - // We set the background in the theme to have the launching animation. - // But for the performance (and battery), we remove the background here. - win.setBackgroundDrawable(null); - } - - private void setActionBarLogoFromIntent(Intent intent) { - Bitmap logo = intent.getParcelableExtra(KEY_LOGO_BITMAP); - if (logo != null) { - getActionBar().setLogo( - new BitmapDrawable(getResources(), logo)); - } - } - - private void initializeActionBar(Intent intent) { - mUri = intent.getData(); - final ActionBar actionBar = getActionBar(); - if (actionBar == null) { - return; - } - setActionBarLogoFromIntent(intent); - actionBar.setDisplayOptions( - ActionBar.DISPLAY_HOME_AS_UP, - ActionBar.DISPLAY_HOME_AS_UP); - - String title = intent.getStringExtra(Intent.EXTRA_TITLE); - if (title != null) { - actionBar.setTitle(title); - } else { - // Displays the filename as title, reading the filename from the - // interface: {@link android.provider.OpenableColumns#DISPLAY_NAME}. - AsyncQueryHandler queryHandler = - new AsyncQueryHandler(getContentResolver()) { - @Override - protected void onQueryComplete(int token, Object cookie, - Cursor cursor) { - try { - if ((cursor != null) && cursor.moveToFirst()) { - String displayName = cursor.getString(0); - - // Just show empty title if other apps don't set - // DISPLAY_NAME - actionBar.setTitle((displayName == null) ? "" : - displayName); - } - } finally { - Utils.closeSilently(cursor); - } - } - }; - queryHandler.startQuery(0, null, mUri, - new String[] {OpenableColumns.DISPLAY_NAME}, null, null, - null); - } - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - super.onCreateOptionsMenu(menu); - getMenuInflater().inflate(R.menu.movie, menu); - - // Document says EXTRA_STREAM should be a content: Uri - // So, we only share the video if it's "content:". - MenuItem shareItem = menu.findItem(R.id.action_share); - if (ContentResolver.SCHEME_CONTENT.equals(mUri.getScheme())) { - shareItem.setVisible(true); - ((ShareActionProvider) shareItem.getActionProvider()) - .setShareIntent(createShareIntent()); - } else { - shareItem.setVisible(false); - } - return true; - } - - private Intent createShareIntent() { - Intent intent = new Intent(Intent.ACTION_SEND); - intent.setType("video/*"); - intent.putExtra(Intent.EXTRA_STREAM, mUri); - return intent; - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - int id = item.getItemId(); - if (id == android.R.id.home) { - if (mTreatUpAsBack) { - finish(); - } else { - startActivity(new Intent(this, Gallery.class)); - finish(); - } - return true; - } else if (id == R.id.action_share) { - startActivity(Intent.createChooser(createShareIntent(), - getString(R.string.share))); - return true; - } - return false; - } - - @Override - public void onStart() { - ((AudioManager) getSystemService(AUDIO_SERVICE)) - .requestAudioFocus(null, AudioManager.STREAM_MUSIC, - AudioManager.AUDIOFOCUS_GAIN_TRANSIENT); - super.onStart(); - } - - @Override - protected void onStop() { - ((AudioManager) getSystemService(AUDIO_SERVICE)) - .abandonAudioFocus(null); - super.onStop(); - } - - @Override - public void onPause() { - mPlayer.onPause(); - super.onPause(); - } - - @Override - public void onResume() { - mPlayer.onResume(); - super.onResume(); - } - - @Override - public void onSaveInstanceState(Bundle outState) { - super.onSaveInstanceState(outState); - mPlayer.onSaveInstanceState(outState); - } - - @Override - public void onDestroy() { - mPlayer.onDestroy(); - super.onDestroy(); - } - - @Override - public boolean onKeyDown(int keyCode, KeyEvent event) { - return mPlayer.onKeyDown(keyCode, event) - || super.onKeyDown(keyCode, event); - } - - @Override - public boolean onKeyUp(int keyCode, KeyEvent event) { - return mPlayer.onKeyUp(keyCode, event) - || super.onKeyUp(keyCode, event); - } -} diff --git a/src/com/android/gallery3d/app/MovieControllerOverlay.java b/src/com/android/gallery3d/app/MovieControllerOverlay.java deleted file mode 100644 index f01e619c6..000000000 --- a/src/com/android/gallery3d/app/MovieControllerOverlay.java +++ /dev/null @@ -1,185 +0,0 @@ -/* - * Copyright (C) 2011 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.content.Context; -import android.os.Handler; -import android.view.KeyEvent; -import android.view.MotionEvent; -import android.view.View; -import android.view.animation.Animation; -import android.view.animation.Animation.AnimationListener; -import android.view.animation.AnimationUtils; -import com.android.gallery3d.R; - -/** - * The playback controller for the Movie Player. - */ -public class MovieControllerOverlay extends CommonControllerOverlay implements - AnimationListener { - - private boolean hidden; - - private final Handler handler; - private final Runnable startHidingRunnable; - private final Animation hideAnimation; - - public MovieControllerOverlay(Context context) { - super(context); - - handler = new Handler(); - startHidingRunnable = new Runnable() { - @Override - public void run() { - startHiding(); - } - }; - - hideAnimation = AnimationUtils.loadAnimation(context, R.anim.player_out); - hideAnimation.setAnimationListener(this); - - hide(); - } - - @Override - protected void createTimeBar(Context context) { - mTimeBar = new TimeBar(context, this); - } - - @Override - public void hide() { - boolean wasHidden = hidden; - hidden = true; - super.hide(); - if (mListener != null && wasHidden != hidden) { - mListener.onHidden(); - } - } - - - @Override - public void show() { - boolean wasHidden = hidden; - hidden = false; - super.show(); - if (mListener != null && wasHidden != hidden) { - mListener.onShown(); - } - maybeStartHiding(); - } - - private void maybeStartHiding() { - cancelHiding(); - if (mState == State.PLAYING) { - handler.postDelayed(startHidingRunnable, 2500); - } - } - - private void startHiding() { - startHideAnimation(mBackground); - startHideAnimation(mTimeBar); - startHideAnimation(mPlayPauseReplayView); - } - - private void startHideAnimation(View view) { - if (view.getVisibility() == View.VISIBLE) { - view.startAnimation(hideAnimation); - } - } - - private void cancelHiding() { - handler.removeCallbacks(startHidingRunnable); - mBackground.setAnimation(null); - mTimeBar.setAnimation(null); - mPlayPauseReplayView.setAnimation(null); - } - - @Override - public void onAnimationStart(Animation animation) { - // Do nothing. - } - - @Override - public void onAnimationRepeat(Animation animation) { - // Do nothing. - } - - @Override - public void onAnimationEnd(Animation animation) { - hide(); - } - - @Override - public boolean onKeyDown(int keyCode, KeyEvent event) { - if (hidden) { - show(); - } - return super.onKeyDown(keyCode, event); - } - - @Override - public boolean onTouchEvent(MotionEvent event) { - if (super.onTouchEvent(event)) { - return true; - } - - if (hidden) { - show(); - return true; - } - switch (event.getAction()) { - case MotionEvent.ACTION_DOWN: - cancelHiding(); - if (mState == State.PLAYING || mState == State.PAUSED) { - mListener.onPlayPause(); - } - break; - case MotionEvent.ACTION_UP: - maybeStartHiding(); - break; - } - return true; - } - - @Override - protected void updateViews() { - if (hidden) { - return; - } - super.updateViews(); - } - - // TimeBar listener - - @Override - public void onScrubbingStart() { - cancelHiding(); - super.onScrubbingStart(); - } - - @Override - public void onScrubbingMove(int time) { - cancelHiding(); - super.onScrubbingMove(time); - } - - @Override - public void onScrubbingEnd(int time, int trimStartTime, int trimEndTime) { - maybeStartHiding(); - super.onScrubbingEnd(time, trimStartTime, trimEndTime); - } -} diff --git a/src/com/android/gallery3d/app/MoviePlayer.java b/src/com/android/gallery3d/app/MoviePlayer.java deleted file mode 100644 index ce9183483..000000000 --- a/src/com/android/gallery3d/app/MoviePlayer.java +++ /dev/null @@ -1,525 +0,0 @@ -/* - * Copyright (C) 2009 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.annotation.TargetApi; -import android.app.AlertDialog; -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.DialogInterface; -import android.content.DialogInterface.OnCancelListener; -import android.content.DialogInterface.OnClickListener; -import android.content.Intent; -import android.content.IntentFilter; -import android.media.AudioManager; -import android.media.MediaPlayer; -import android.net.Uri; -import android.os.Build; -import android.os.Bundle; -import android.os.Handler; -import android.view.KeyEvent; -import android.view.MotionEvent; -import android.view.View; -import android.view.ViewGroup; -import android.widget.VideoView; - -import com.android.gallery3d.R; -import com.android.gallery3d.common.ApiHelper; -import com.android.gallery3d.common.BlobCache; -import com.android.gallery3d.util.CacheManager; -import com.android.gallery3d.util.GalleryUtils; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.DataInputStream; -import java.io.DataOutputStream; - -public class MoviePlayer implements - MediaPlayer.OnErrorListener, MediaPlayer.OnCompletionListener, - ControllerOverlay.Listener { - @SuppressWarnings("unused") - private static final String TAG = "MoviePlayer"; - - private static final String KEY_VIDEO_POSITION = "video-position"; - private static final String KEY_RESUMEABLE_TIME = "resumeable-timeout"; - - // These are constants in KeyEvent, appearing on API level 11. - private static final int KEYCODE_MEDIA_PLAY = 126; - private static final int KEYCODE_MEDIA_PAUSE = 127; - - // Copied from MediaPlaybackService in the Music Player app. - private static final String SERVICECMD = "com.android.music.musicservicecommand"; - private static final String CMDNAME = "command"; - private static final String CMDPAUSE = "pause"; - - private static final long BLACK_TIMEOUT = 500; - - // If we resume the acitivty with in RESUMEABLE_TIMEOUT, we will keep playing. - // Otherwise, we pause the player. - private static final long RESUMEABLE_TIMEOUT = 3 * 60 * 1000; // 3 mins - - private Context mContext; - private final VideoView mVideoView; - private final View mRootView; - private final Bookmarker mBookmarker; - private final Uri mUri; - private final Handler mHandler = new Handler(); - private final AudioBecomingNoisyReceiver mAudioBecomingNoisyReceiver; - private final MovieControllerOverlay mController; - - private long mResumeableTime = Long.MAX_VALUE; - private int mVideoPosition = 0; - private boolean mHasPaused = false; - private int mLastSystemUiVis = 0; - - // If the time bar is being dragged. - private boolean mDragging; - - // If the time bar is visible. - private boolean mShowing; - - private final Runnable mPlayingChecker = new Runnable() { - @Override - public void run() { - if (mVideoView.isPlaying()) { - mController.showPlaying(); - } else { - mHandler.postDelayed(mPlayingChecker, 250); - } - } - }; - - private final Runnable mProgressChecker = new Runnable() { - @Override - public void run() { - int pos = setProgress(); - mHandler.postDelayed(mProgressChecker, 1000 - (pos % 1000)); - } - }; - - public MoviePlayer(View rootView, final MovieActivity movieActivity, - Uri videoUri, Bundle savedInstance, boolean canReplay) { - mContext = movieActivity.getApplicationContext(); - mRootView = rootView; - mVideoView = (VideoView) rootView.findViewById(R.id.surface_view); - mBookmarker = new Bookmarker(movieActivity); - mUri = videoUri; - - mController = new MovieControllerOverlay(mContext); - ((ViewGroup)rootView).addView(mController.getView()); - mController.setListener(this); - mController.setCanReplay(canReplay); - - mVideoView.setOnErrorListener(this); - mVideoView.setOnCompletionListener(this); - mVideoView.setVideoURI(mUri); - mVideoView.setOnTouchListener(new View.OnTouchListener() { - @Override - public boolean onTouch(View v, MotionEvent event) { - mController.show(); - return true; - } - }); - mVideoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() { - @Override - public void onPrepared(MediaPlayer player) { - if (!mVideoView.canSeekForward() || !mVideoView.canSeekBackward()) { - mController.setSeekable(false); - } else { - mController.setSeekable(true); - } - setProgress(); - } - }); - - // The SurfaceView is transparent before drawing the first frame. - // This makes the UI flashing when open a video. (black -> old screen - // -> video) However, we have no way to know the timing of the first - // frame. So, we hide the VideoView for a while to make sure the - // video has been drawn on it. - mVideoView.postDelayed(new Runnable() { - @Override - public void run() { - mVideoView.setVisibility(View.VISIBLE); - } - }, BLACK_TIMEOUT); - - setOnSystemUiVisibilityChangeListener(); - // Hide system UI by default - showSystemUi(false); - - mAudioBecomingNoisyReceiver = new AudioBecomingNoisyReceiver(); - mAudioBecomingNoisyReceiver.register(); - - Intent i = new Intent(SERVICECMD); - i.putExtra(CMDNAME, CMDPAUSE); - movieActivity.sendBroadcast(i); - - if (savedInstance != null) { // this is a resumed activity - mVideoPosition = savedInstance.getInt(KEY_VIDEO_POSITION, 0); - mResumeableTime = savedInstance.getLong(KEY_RESUMEABLE_TIME, Long.MAX_VALUE); - mVideoView.start(); - mVideoView.suspend(); - mHasPaused = true; - } else { - final Integer bookmark = mBookmarker.getBookmark(mUri); - if (bookmark != null) { - showResumeDialog(movieActivity, bookmark); - } else { - startVideo(); - } - } - } - - @TargetApi(Build.VERSION_CODES.JELLY_BEAN) - private void setOnSystemUiVisibilityChangeListener() { - if (!ApiHelper.HAS_VIEW_SYSTEM_UI_FLAG_HIDE_NAVIGATION) return; - - // When the user touches the screen or uses some hard key, the framework - // will change system ui visibility from invisible to visible. We show - // the media control and enable system UI (e.g. ActionBar) to be visible at this point - mVideoView.setOnSystemUiVisibilityChangeListener( - new View.OnSystemUiVisibilityChangeListener() { - @Override - public void onSystemUiVisibilityChange(int visibility) { - int diff = mLastSystemUiVis ^ visibility; - mLastSystemUiVis = visibility; - if ((diff & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) != 0 - && (visibility & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0) { - mController.show(); - } - } - }); - } - - @SuppressWarnings("deprecation") - @TargetApi(Build.VERSION_CODES.JELLY_BEAN) - private void showSystemUi(boolean visible) { - if (!ApiHelper.HAS_VIEW_SYSTEM_UI_FLAG_LAYOUT_STABLE) return; - - int flag = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN - | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION - | View.SYSTEM_UI_FLAG_LAYOUT_STABLE; - if (!visible) { - // We used the deprecated "STATUS_BAR_HIDDEN" for unbundling - flag |= View.STATUS_BAR_HIDDEN | View.SYSTEM_UI_FLAG_FULLSCREEN - | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION; - } - mVideoView.setSystemUiVisibility(flag); - } - - public void onSaveInstanceState(Bundle outState) { - outState.putInt(KEY_VIDEO_POSITION, mVideoPosition); - outState.putLong(KEY_RESUMEABLE_TIME, mResumeableTime); - } - - private void showResumeDialog(Context context, final int bookmark) { - AlertDialog.Builder builder = new AlertDialog.Builder(context); - builder.setTitle(R.string.resume_playing_title); - builder.setMessage(String.format( - context.getString(R.string.resume_playing_message), - GalleryUtils.formatDuration(context, bookmark / 1000))); - builder.setOnCancelListener(new OnCancelListener() { - @Override - public void onCancel(DialogInterface dialog) { - onCompletion(); - } - }); - builder.setPositiveButton( - R.string.resume_playing_resume, new OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - mVideoView.seekTo(bookmark); - startVideo(); - } - }); - builder.setNegativeButton( - R.string.resume_playing_restart, new OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - startVideo(); - } - }); - builder.show(); - } - - public void onPause() { - mHasPaused = true; - mHandler.removeCallbacksAndMessages(null); - mVideoPosition = mVideoView.getCurrentPosition(); - mBookmarker.setBookmark(mUri, mVideoPosition, mVideoView.getDuration()); - mVideoView.suspend(); - mResumeableTime = System.currentTimeMillis() + RESUMEABLE_TIMEOUT; - } - - public void onResume() { - if (mHasPaused) { - mVideoView.seekTo(mVideoPosition); - mVideoView.resume(); - - // If we have slept for too long, pause the play - if (System.currentTimeMillis() > mResumeableTime) { - pauseVideo(); - } - } - mHandler.post(mProgressChecker); - } - - public void onDestroy() { - mVideoView.stopPlayback(); - mAudioBecomingNoisyReceiver.unregister(); - } - - // This updates the time bar display (if necessary). It is called every - // second by mProgressChecker and also from places where the time bar needs - // to be updated immediately. - private int setProgress() { - if (mDragging || !mShowing) { - return 0; - } - int position = mVideoView.getCurrentPosition(); - int duration = mVideoView.getDuration(); - mController.setTimes(position, duration, 0, 0); - return position; - } - - private void startVideo() { - // For streams that we expect to be slow to start up, show a - // progress spinner until playback starts. - String scheme = mUri.getScheme(); - if ("http".equalsIgnoreCase(scheme) || "rtsp".equalsIgnoreCase(scheme)) { - mController.showLoading(); - mHandler.removeCallbacks(mPlayingChecker); - mHandler.postDelayed(mPlayingChecker, 250); - } else { - mController.showPlaying(); - mController.hide(); - } - - mVideoView.start(); - setProgress(); - } - - private void playVideo() { - mVideoView.start(); - mController.showPlaying(); - setProgress(); - } - - private void pauseVideo() { - mVideoView.pause(); - mController.showPaused(); - } - - // Below are notifications from VideoView - @Override - public boolean onError(MediaPlayer player, int arg1, int arg2) { - mHandler.removeCallbacksAndMessages(null); - // VideoView will show an error dialog if we return false, so no need - // to show more message. - mController.showErrorMessage(""); - return false; - } - - @Override - public void onCompletion(MediaPlayer mp) { - mController.showEnded(); - onCompletion(); - } - - public void onCompletion() { - } - - // Below are notifications from ControllerOverlay - @Override - public void onPlayPause() { - if (mVideoView.isPlaying()) { - pauseVideo(); - } else { - playVideo(); - } - } - - @Override - public void onSeekStart() { - mDragging = true; - } - - @Override - public void onSeekMove(int time) { - mVideoView.seekTo(time); - } - - @Override - public void onSeekEnd(int time, int start, int end) { - mDragging = false; - mVideoView.seekTo(time); - setProgress(); - } - - @Override - public void onShown() { - mShowing = true; - setProgress(); - showSystemUi(true); - } - - @Override - public void onHidden() { - mShowing = false; - showSystemUi(false); - } - - @Override - public void onReplay() { - startVideo(); - } - - // Below are key events passed from MovieActivity. - public boolean onKeyDown(int keyCode, KeyEvent event) { - - // Some headsets will fire off 7-10 events on a single click - if (event.getRepeatCount() > 0) { - return isMediaKey(keyCode); - } - - switch (keyCode) { - case KeyEvent.KEYCODE_HEADSETHOOK: - case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE: - if (mVideoView.isPlaying()) { - pauseVideo(); - } else { - playVideo(); - } - return true; - case KEYCODE_MEDIA_PAUSE: - if (mVideoView.isPlaying()) { - pauseVideo(); - } - return true; - case KEYCODE_MEDIA_PLAY: - if (!mVideoView.isPlaying()) { - playVideo(); - } - return true; - case KeyEvent.KEYCODE_MEDIA_PREVIOUS: - case KeyEvent.KEYCODE_MEDIA_NEXT: - // TODO: Handle next / previous accordingly, for now we're - // just consuming the events. - return true; - } - return false; - } - - public boolean onKeyUp(int keyCode, KeyEvent event) { - return isMediaKey(keyCode); - } - - private static boolean isMediaKey(int keyCode) { - return keyCode == KeyEvent.KEYCODE_HEADSETHOOK - || keyCode == KeyEvent.KEYCODE_MEDIA_PREVIOUS - || keyCode == KeyEvent.KEYCODE_MEDIA_NEXT - || keyCode == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE - || keyCode == KeyEvent.KEYCODE_MEDIA_PLAY - || keyCode == KeyEvent.KEYCODE_MEDIA_PAUSE; - } - - // We want to pause when the headset is unplugged. - private class AudioBecomingNoisyReceiver extends BroadcastReceiver { - - public void register() { - mContext.registerReceiver(this, - new IntentFilter(AudioManager.ACTION_AUDIO_BECOMING_NOISY)); - } - - public void unregister() { - mContext.unregisterReceiver(this); - } - - @Override - public void onReceive(Context context, Intent intent) { - if (mVideoView.isPlaying()) pauseVideo(); - } - } -} - -class Bookmarker { - private static final String TAG = "Bookmarker"; - - private static final String BOOKMARK_CACHE_FILE = "bookmark"; - private static final int BOOKMARK_CACHE_MAX_ENTRIES = 100; - private static final int BOOKMARK_CACHE_MAX_BYTES = 10 * 1024; - private static final int BOOKMARK_CACHE_VERSION = 1; - - private static final int HALF_MINUTE = 30 * 1000; - private static final int TWO_MINUTES = 4 * HALF_MINUTE; - - private final Context mContext; - - public Bookmarker(Context context) { - mContext = context; - } - - public void setBookmark(Uri uri, int bookmark, int duration) { - try { - BlobCache cache = CacheManager.getCache(mContext, - BOOKMARK_CACHE_FILE, BOOKMARK_CACHE_MAX_ENTRIES, - BOOKMARK_CACHE_MAX_BYTES, BOOKMARK_CACHE_VERSION); - - ByteArrayOutputStream bos = new ByteArrayOutputStream(); - DataOutputStream dos = new DataOutputStream(bos); - dos.writeUTF(uri.toString()); - dos.writeInt(bookmark); - dos.writeInt(duration); - dos.flush(); - cache.insert(uri.hashCode(), bos.toByteArray()); - } catch (Throwable t) { - Log.w(TAG, "setBookmark failed", t); - } - } - - public Integer getBookmark(Uri uri) { - try { - BlobCache cache = CacheManager.getCache(mContext, - BOOKMARK_CACHE_FILE, BOOKMARK_CACHE_MAX_ENTRIES, - BOOKMARK_CACHE_MAX_BYTES, BOOKMARK_CACHE_VERSION); - - byte[] data = cache.lookup(uri.hashCode()); - if (data == null) return null; - - DataInputStream dis = new DataInputStream( - new ByteArrayInputStream(data)); - - String uriString = DataInputStream.readUTF(dis); - int bookmark = dis.readInt(); - int duration = dis.readInt(); - - if (!uriString.equals(uri.toString())) { - return null; - } - - if ((bookmark < HALF_MINUTE) || (duration < TWO_MINUTES) - || (bookmark > (duration - HALF_MINUTE))) { - return null; - } - return Integer.valueOf(bookmark); - } catch (Throwable t) { - Log.w(TAG, "getBookmark failed", t); - } - return null; - } -} diff --git a/src/com/android/gallery3d/app/MuteVideo.java b/src/com/android/gallery3d/app/MuteVideo.java deleted file mode 100644 index d3f3aa594..000000000 --- a/src/com/android/gallery3d/app/MuteVideo.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * 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 String mFilePath = 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(String filePath, Uri uri, Activity activity) { - mUri = uri; - mFilePath = filePath; - 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(mFilePath, 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/NotificationIds.java b/src/com/android/gallery3d/app/NotificationIds.java deleted file mode 100644 index d697d854b..000000000 --- a/src/com/android/gallery3d/app/NotificationIds.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright (C) 2013 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 NotificationIds { - public static final int INGEST_NOTIFICATION_SCANNING = 10; - public static final int INGEST_NOTIFICATION_IMPORTING = 11; -} diff --git a/src/com/android/gallery3d/app/OrientationManager.java b/src/com/android/gallery3d/app/OrientationManager.java deleted file mode 100644 index f2f632c9f..000000000 --- a/src/com/android/gallery3d/app/OrientationManager.java +++ /dev/null @@ -1,166 +0,0 @@ -/* - * 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.content.ContentResolver; -import android.content.Context; -import android.content.pm.ActivityInfo; -import android.content.res.Configuration; -import android.provider.Settings; -import android.view.OrientationEventListener; -import android.view.Surface; - -import com.android.gallery3d.common.ApiHelper; -import com.android.gallery3d.ui.OrientationSource; - -public class OrientationManager implements OrientationSource { - private static final String TAG = "OrientationManager"; - - // Orientation hysteresis amount used in rounding, in degrees - private static final int ORIENTATION_HYSTERESIS = 5; - - private Activity mActivity; - private MyOrientationEventListener mOrientationListener; - // If the framework orientation is locked. - private boolean mOrientationLocked = false; - - // This is true if "Settings -> Display -> Rotation Lock" is checked. We - // don't allow the orientation to be unlocked if the value is true. - private boolean mRotationLockedSetting = false; - - public OrientationManager(Activity activity) { - mActivity = activity; - mOrientationListener = new MyOrientationEventListener(activity); - } - - public void resume() { - ContentResolver resolver = mActivity.getContentResolver(); - mRotationLockedSetting = Settings.System.getInt( - resolver, Settings.System.ACCELEROMETER_ROTATION, 0) != 1; - mOrientationListener.enable(); - } - - public void pause() { - mOrientationListener.disable(); - } - - //////////////////////////////////////////////////////////////////////////// - // Orientation handling - // - // We can choose to lock the framework orientation or not. If we lock the - // framework orientation, we calculate a a compensation value according to - // current device orientation and send it to listeners. If we don't lock - // the framework orientation, we always set the compensation value to 0. - //////////////////////////////////////////////////////////////////////////// - - // Lock the framework orientation to the current device orientation - public void lockOrientation() { - if (mOrientationLocked) return; - mOrientationLocked = true; - if (ApiHelper.HAS_ORIENTATION_LOCK) { - mActivity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LOCKED); - } else { - mActivity.setRequestedOrientation(calculateCurrentScreenOrientation()); - } - } - - // Unlock the framework orientation, so it can change when the device - // rotates. - public void unlockOrientation() { - if (!mOrientationLocked) return; - mOrientationLocked = false; - Log.d(TAG, "unlock orientation"); - mActivity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR); - } - - private int calculateCurrentScreenOrientation() { - int displayRotation = getDisplayRotation(); - // Display rotation >= 180 means we need to use the REVERSE landscape/portrait - boolean standard = displayRotation < 180; - if (mActivity.getResources().getConfiguration().orientation - == Configuration.ORIENTATION_LANDSCAPE) { - return standard - ? ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE - : ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE; - } else { - if (displayRotation == 90 || displayRotation == 270) { - // If displayRotation = 90 or 270 then we are on a landscape - // device. On landscape devices, portrait is a 90 degree - // clockwise rotation from landscape, so we need - // to flip which portrait we pick as display rotation is counter clockwise - standard = !standard; - } - return standard - ? ActivityInfo.SCREEN_ORIENTATION_PORTRAIT - : ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT; - } - } - - // This listens to the device orientation, so we can update the compensation. - private class MyOrientationEventListener extends OrientationEventListener { - public MyOrientationEventListener(Context context) { - super(context); - } - - @Override - public void onOrientationChanged(int orientation) { - // We keep the last known orientation. So if the user first orient - // the camera then point the camera to floor or sky, we still have - // the correct orientation. - if (orientation == ORIENTATION_UNKNOWN) return; - orientation = roundOrientation(orientation, 0); - } - } - - @Override - public int getDisplayRotation() { - return getDisplayRotation(mActivity); - } - - @Override - public int getCompensation() { - return 0; - } - - private static int roundOrientation(int orientation, int orientationHistory) { - boolean changeOrientation = false; - if (orientationHistory == OrientationEventListener.ORIENTATION_UNKNOWN) { - changeOrientation = true; - } else { - int dist = Math.abs(orientation - orientationHistory); - dist = Math.min(dist, 360 - dist); - changeOrientation = (dist >= 45 + ORIENTATION_HYSTERESIS); - } - if (changeOrientation) { - return ((orientation + 45) / 90 * 90) % 360; - } - return orientationHistory; - } - - private static int getDisplayRotation(Activity activity) { - int rotation = activity.getWindowManager().getDefaultDisplay() - .getRotation(); - switch (rotation) { - case Surface.ROTATION_0: return 0; - case Surface.ROTATION_90: return 90; - case Surface.ROTATION_180: return 180; - case Surface.ROTATION_270: return 270; - } - return 0; - } -} diff --git a/src/com/android/gallery3d/app/PackagesMonitor.java b/src/com/android/gallery3d/app/PackagesMonitor.java deleted file mode 100644 index 9b2412f1b..000000000 --- a/src/com/android/gallery3d/app/PackagesMonitor.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright (C) 2010 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.IntentService; -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.SharedPreferences; -import android.preference.PreferenceManager; - -import com.android.gallery3d.picasasource.PicasaSource; -import com.android.gallery3d.util.LightCycleHelper; - -public class PackagesMonitor extends BroadcastReceiver { - public static final String KEY_PACKAGES_VERSION = "packages-version"; - - public synchronized static int getPackagesVersion(Context context) { - SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); - return prefs.getInt(KEY_PACKAGES_VERSION, 1); - } - - @Override - public void onReceive(final Context context, final Intent intent) { - intent.setClass(context, AsyncService.class); - context.startService(intent); - } - - public static class AsyncService extends IntentService { - public AsyncService() { - super("GalleryPackagesMonitorAsync"); - } - - @Override - protected void onHandleIntent(Intent intent) { - onReceiveAsync(this, intent); - } - } - - // Runs in a background thread. - private static void onReceiveAsync(Context context, Intent intent) { - SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); - - int version = prefs.getInt(KEY_PACKAGES_VERSION, 1); - prefs.edit().putInt(KEY_PACKAGES_VERSION, version + 1).commit(); - - String action = intent.getAction(); - String packageName = intent.getData().getSchemeSpecificPart(); - if (Intent.ACTION_PACKAGE_ADDED.equals(action)) { - PicasaSource.onPackageAdded(context, packageName); - } else if (Intent.ACTION_PACKAGE_REMOVED.equals(action)) { - PicasaSource.onPackageRemoved(context, packageName); - } else if (Intent.ACTION_PACKAGE_CHANGED.equals(action)) { - PicasaSource.onPackageChanged(context, packageName); - } - } -} diff --git a/src/com/android/gallery3d/app/PanoramaMetadataSupport.java b/src/com/android/gallery3d/app/PanoramaMetadataSupport.java deleted file mode 100644 index ba0c9e71a..000000000 --- a/src/com/android/gallery3d/app/PanoramaMetadataSupport.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * 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 com.android.gallery3d.data.MediaObject; -import com.android.gallery3d.data.MediaObject.PanoramaSupportCallback; -import com.android.gallery3d.data.PanoramaMetadataJob; -import com.android.gallery3d.util.Future; -import com.android.gallery3d.util.FutureListener; -import com.android.gallery3d.util.LightCycleHelper; -import com.android.gallery3d.util.LightCycleHelper.PanoramaMetadata; - -import java.util.ArrayList; - -/** - * This class breaks out the off-thread panorama support checks so that the - * complexity can be shared between UriImage and LocalImage, which need to - * support panoramas. - */ -public class PanoramaMetadataSupport implements FutureListener<PanoramaMetadata> { - private Object mLock = new Object(); - private Future<PanoramaMetadata> mGetPanoMetadataTask; - private PanoramaMetadata mPanoramaMetadata; - private ArrayList<PanoramaSupportCallback> mCallbacksWaiting; - private MediaObject mMediaObject; - - public PanoramaMetadataSupport(MediaObject mediaObject) { - mMediaObject = mediaObject; - } - - public void getPanoramaSupport(GalleryApp app, PanoramaSupportCallback callback) { - synchronized (mLock) { - if (mPanoramaMetadata != null) { - callback.panoramaInfoAvailable(mMediaObject, mPanoramaMetadata.mUsePanoramaViewer, - mPanoramaMetadata.mIsPanorama360); - } else { - if (mCallbacksWaiting == null) { - mCallbacksWaiting = new ArrayList<PanoramaSupportCallback>(); - mGetPanoMetadataTask = app.getThreadPool().submit( - new PanoramaMetadataJob(app.getAndroidContext(), - mMediaObject.getContentUri()), this); - - } - mCallbacksWaiting.add(callback); - } - } - } - - public void clearCachedValues() { - synchronized (mLock) { - if (mPanoramaMetadata != null) { - mPanoramaMetadata = null; - } else if (mGetPanoMetadataTask != null) { - mGetPanoMetadataTask.cancel(); - for (PanoramaSupportCallback cb : mCallbacksWaiting) { - cb.panoramaInfoAvailable(mMediaObject, false, false); - } - mGetPanoMetadataTask = null; - mCallbacksWaiting = null; - } - } - } - - @Override - public void onFutureDone(Future<PanoramaMetadata> future) { - synchronized (mLock) { - mPanoramaMetadata = future.get(); - if (mPanoramaMetadata == null) { - // Error getting panorama data from file. Treat as not panorama. - mPanoramaMetadata = LightCycleHelper.NOT_PANORAMA; - } - for (PanoramaSupportCallback cb : mCallbacksWaiting) { - cb.panoramaInfoAvailable(mMediaObject, mPanoramaMetadata.mUsePanoramaViewer, - mPanoramaMetadata.mIsPanorama360); - } - mGetPanoMetadataTask = null; - mCallbacksWaiting = null; - } - } -} diff --git a/src/com/android/gallery3d/app/PhotoDataAdapter.java b/src/com/android/gallery3d/app/PhotoDataAdapter.java deleted file mode 100644 index fd3a7cf73..000000000 --- a/src/com/android/gallery3d/app/PhotoDataAdapter.java +++ /dev/null @@ -1,1133 +0,0 @@ -/* - * Copyright (C) 2010 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.graphics.Bitmap; -import android.graphics.BitmapRegionDecoder; -import android.os.Handler; -import android.os.Message; - -import com.android.gallery3d.common.BitmapUtils; -import com.android.gallery3d.common.Utils; -import com.android.gallery3d.data.ContentListener; -import com.android.gallery3d.data.LocalMediaItem; -import com.android.gallery3d.data.MediaItem; -import com.android.gallery3d.data.MediaObject; -import com.android.gallery3d.data.MediaSet; -import com.android.gallery3d.data.Path; -import com.android.gallery3d.glrenderer.TiledTexture; -import com.android.gallery3d.ui.PhotoView; -import com.android.gallery3d.ui.ScreenNail; -import com.android.gallery3d.ui.SynchronizedHandler; -import com.android.gallery3d.ui.TileImageViewAdapter; -import com.android.gallery3d.ui.TiledScreenNail; -import com.android.gallery3d.util.Future; -import com.android.gallery3d.util.FutureListener; -import com.android.gallery3d.util.MediaSetUtils; -import com.android.gallery3d.util.ThreadPool; -import com.android.gallery3d.util.ThreadPool.Job; -import com.android.gallery3d.util.ThreadPool.JobContext; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.HashSet; -import java.util.concurrent.Callable; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.FutureTask; - -public class PhotoDataAdapter implements PhotoPage.Model { - @SuppressWarnings("unused") - private static final String TAG = "PhotoDataAdapter"; - - private static final int MSG_LOAD_START = 1; - private static final int MSG_LOAD_FINISH = 2; - private static final int MSG_RUN_OBJECT = 3; - private static final int MSG_UPDATE_IMAGE_REQUESTS = 4; - - private static final int MIN_LOAD_COUNT = 16; - private static final int DATA_CACHE_SIZE = 256; - private static final int SCREEN_NAIL_MAX = PhotoView.SCREEN_NAIL_MAX; - private static final int IMAGE_CACHE_SIZE = 2 * SCREEN_NAIL_MAX + 1; - - private static final int BIT_SCREEN_NAIL = 1; - private static final int BIT_FULL_IMAGE = 2; - - // sImageFetchSeq is the fetching sequence for images. - // We want to fetch the current screennail first (offset = 0), the next - // screennail (offset = +1), then the previous screennail (offset = -1) etc. - // After all the screennail are fetched, we fetch the full images (only some - // of them because of we don't want to use too much memory). - private static ImageFetch[] sImageFetchSeq; - - private static class ImageFetch { - int indexOffset; - int imageBit; - public ImageFetch(int offset, int bit) { - indexOffset = offset; - imageBit = bit; - } - } - - static { - int k = 0; - sImageFetchSeq = new ImageFetch[1 + (IMAGE_CACHE_SIZE - 1) * 2 + 3]; - sImageFetchSeq[k++] = new ImageFetch(0, BIT_SCREEN_NAIL); - - for (int i = 1; i < IMAGE_CACHE_SIZE; ++i) { - sImageFetchSeq[k++] = new ImageFetch(i, BIT_SCREEN_NAIL); - sImageFetchSeq[k++] = new ImageFetch(-i, BIT_SCREEN_NAIL); - } - - sImageFetchSeq[k++] = new ImageFetch(0, BIT_FULL_IMAGE); - sImageFetchSeq[k++] = new ImageFetch(1, BIT_FULL_IMAGE); - sImageFetchSeq[k++] = new ImageFetch(-1, BIT_FULL_IMAGE); - } - - private final TileImageViewAdapter mTileProvider = new TileImageViewAdapter(); - - // PhotoDataAdapter caches MediaItems (data) and ImageEntries (image). - // - // The MediaItems are stored in the mData array, which has DATA_CACHE_SIZE - // entries. The valid index range are [mContentStart, mContentEnd). We keep - // mContentEnd - mContentStart <= DATA_CACHE_SIZE, so we can use - // (i % DATA_CACHE_SIZE) as index to the array. - // - // The valid MediaItem window size (mContentEnd - mContentStart) may be - // smaller than DATA_CACHE_SIZE because we only update the window and reload - // the MediaItems when there are significant changes to the window position - // (>= MIN_LOAD_COUNT). - private final MediaItem mData[] = new MediaItem[DATA_CACHE_SIZE]; - private int mContentStart = 0; - private int mContentEnd = 0; - - // The ImageCache is a Path-to-ImageEntry map. It only holds the - // ImageEntries in the range of [mActiveStart, mActiveEnd). We also keep - // mActiveEnd - mActiveStart <= IMAGE_CACHE_SIZE. Besides, the - // [mActiveStart, mActiveEnd) range must be contained within - // the [mContentStart, mContentEnd) range. - private HashMap<Path, ImageEntry> mImageCache = - new HashMap<Path, ImageEntry>(); - private int mActiveStart = 0; - private int mActiveEnd = 0; - - // mCurrentIndex is the "center" image the user is viewing. The change of - // mCurrentIndex triggers the data loading and image loading. - private int mCurrentIndex; - - // mChanges keeps the version number (of MediaItem) about the images. If any - // of the version number changes, we notify the view. This is used after a - // database reload or mCurrentIndex changes. - private final long mChanges[] = new long[IMAGE_CACHE_SIZE]; - // mPaths keeps the corresponding Path (of MediaItem) for the images. This - // is used to determine the item movement. - private final Path mPaths[] = new Path[IMAGE_CACHE_SIZE]; - - private final Handler mMainHandler; - private final ThreadPool mThreadPool; - - private final PhotoView mPhotoView; - private final MediaSet mSource; - private ReloadTask mReloadTask; - - private long mSourceVersion = MediaObject.INVALID_DATA_VERSION; - private int mSize = 0; - private Path mItemPath; - private int mCameraIndex; - private boolean mIsPanorama; - private boolean mIsStaticCamera; - private boolean mIsActive; - private boolean mNeedFullImage; - private int mFocusHintDirection = FOCUS_HINT_NEXT; - private Path mFocusHintPath = null; - - public interface DataListener extends LoadingListener { - public void onPhotoChanged(int index, Path item); - } - - private DataListener mDataListener; - - private final SourceListener mSourceListener = new SourceListener(); - private final TiledTexture.Uploader mUploader; - - // The path of the current viewing item will be stored in mItemPath. - // If mItemPath is not null, mCurrentIndex is only a hint for where we - // can find the item. If mItemPath is null, then we use the mCurrentIndex to - // find the image being viewed. cameraIndex is the index of the camera - // preview. If cameraIndex < 0, there is no camera preview. - public PhotoDataAdapter(AbstractGalleryActivity activity, PhotoView view, - MediaSet mediaSet, Path itemPath, int indexHint, int cameraIndex, - boolean isPanorama, boolean isStaticCamera) { - mSource = Utils.checkNotNull(mediaSet); - mPhotoView = Utils.checkNotNull(view); - mItemPath = Utils.checkNotNull(itemPath); - mCurrentIndex = indexHint; - mCameraIndex = cameraIndex; - mIsPanorama = isPanorama; - mIsStaticCamera = isStaticCamera; - mThreadPool = activity.getThreadPool(); - mNeedFullImage = true; - - Arrays.fill(mChanges, MediaObject.INVALID_DATA_VERSION); - - mUploader = new TiledTexture.Uploader(activity.getGLRoot()); - - mMainHandler = new SynchronizedHandler(activity.getGLRoot()) { - @SuppressWarnings("unchecked") - @Override - public void handleMessage(Message message) { - switch (message.what) { - case MSG_RUN_OBJECT: - ((Runnable) message.obj).run(); - return; - case MSG_LOAD_START: { - if (mDataListener != null) { - mDataListener.onLoadingStarted(); - } - return; - } - case MSG_LOAD_FINISH: { - if (mDataListener != null) { - mDataListener.onLoadingFinished(false); - } - return; - } - case MSG_UPDATE_IMAGE_REQUESTS: { - updateImageRequests(); - return; - } - default: throw new AssertionError(); - } - } - }; - - updateSlidingWindow(); - } - - private MediaItem getItemInternal(int index) { - if (index < 0 || index >= mSize) return null; - if (index >= mContentStart && index < mContentEnd) { - return mData[index % DATA_CACHE_SIZE]; - } - return null; - } - - private long getVersion(int index) { - MediaItem item = getItemInternal(index); - if (item == null) return MediaObject.INVALID_DATA_VERSION; - return item.getDataVersion(); - } - - private Path getPath(int index) { - MediaItem item = getItemInternal(index); - if (item == null) return null; - return item.getPath(); - } - - private void fireDataChange() { - // First check if data actually changed. - boolean changed = false; - for (int i = -SCREEN_NAIL_MAX; i <= SCREEN_NAIL_MAX; ++i) { - long newVersion = getVersion(mCurrentIndex + i); - if (mChanges[i + SCREEN_NAIL_MAX] != newVersion) { - mChanges[i + SCREEN_NAIL_MAX] = newVersion; - changed = true; - } - } - - if (!changed) return; - - // Now calculate the fromIndex array. fromIndex represents the item - // movement. It records the index where the picture come from. The - // special value Integer.MAX_VALUE means it's a new picture. - final int N = IMAGE_CACHE_SIZE; - int fromIndex[] = new int[N]; - - // Remember the old path array. - Path oldPaths[] = new Path[N]; - System.arraycopy(mPaths, 0, oldPaths, 0, N); - - // Update the mPaths array. - for (int i = 0; i < N; ++i) { - mPaths[i] = getPath(mCurrentIndex + i - SCREEN_NAIL_MAX); - } - - // Calculate the fromIndex array. - for (int i = 0; i < N; i++) { - Path p = mPaths[i]; - if (p == null) { - fromIndex[i] = Integer.MAX_VALUE; - continue; - } - - // Try to find the same path in the old array - int j; - for (j = 0; j < N; j++) { - if (oldPaths[j] == p) { - break; - } - } - fromIndex[i] = (j < N) ? j - SCREEN_NAIL_MAX : Integer.MAX_VALUE; - } - - mPhotoView.notifyDataChange(fromIndex, -mCurrentIndex, - mSize - 1 - mCurrentIndex); - } - - public void setDataListener(DataListener listener) { - mDataListener = listener; - } - - private void updateScreenNail(Path path, Future<ScreenNail> future) { - ImageEntry entry = mImageCache.get(path); - ScreenNail screenNail = future.get(); - - if (entry == null || entry.screenNailTask != future) { - if (screenNail != null) screenNail.recycle(); - return; - } - - entry.screenNailTask = null; - - // Combine the ScreenNails if we already have a BitmapScreenNail - if (entry.screenNail instanceof TiledScreenNail) { - TiledScreenNail original = (TiledScreenNail) entry.screenNail; - screenNail = original.combine(screenNail); - } - - if (screenNail == null) { - entry.failToLoad = true; - } else { - entry.failToLoad = false; - entry.screenNail = screenNail; - } - - for (int i = -SCREEN_NAIL_MAX; i <= SCREEN_NAIL_MAX; ++i) { - if (path == getPath(mCurrentIndex + i)) { - if (i == 0) updateTileProvider(entry); - mPhotoView.notifyImageChange(i); - break; - } - } - updateImageRequests(); - updateScreenNailUploadQueue(); - } - - private void updateFullImage(Path path, Future<BitmapRegionDecoder> future) { - ImageEntry entry = mImageCache.get(path); - if (entry == null || entry.fullImageTask != future) { - BitmapRegionDecoder fullImage = future.get(); - if (fullImage != null) fullImage.recycle(); - return; - } - - entry.fullImageTask = null; - entry.fullImage = future.get(); - if (entry.fullImage != null) { - if (path == getPath(mCurrentIndex)) { - updateTileProvider(entry); - mPhotoView.notifyImageChange(0); - } - } - updateImageRequests(); - } - - @Override - public void resume() { - mIsActive = true; - TiledTexture.prepareResources(); - - mSource.addContentListener(mSourceListener); - updateImageCache(); - updateImageRequests(); - - mReloadTask = new ReloadTask(); - mReloadTask.start(); - - fireDataChange(); - } - - @Override - public void pause() { - mIsActive = false; - - mReloadTask.terminate(); - mReloadTask = null; - - mSource.removeContentListener(mSourceListener); - - for (ImageEntry entry : mImageCache.values()) { - if (entry.fullImageTask != null) entry.fullImageTask.cancel(); - if (entry.screenNailTask != null) entry.screenNailTask.cancel(); - if (entry.screenNail != null) entry.screenNail.recycle(); - } - mImageCache.clear(); - mTileProvider.clear(); - - mUploader.clear(); - TiledTexture.freeResources(); - } - - private MediaItem getItem(int index) { - if (index < 0 || index >= mSize || !mIsActive) return null; - Utils.assertTrue(index >= mActiveStart && index < mActiveEnd); - - if (index >= mContentStart && index < mContentEnd) { - return mData[index % DATA_CACHE_SIZE]; - } - return null; - } - - private void updateCurrentIndex(int index) { - if (mCurrentIndex == index) return; - mCurrentIndex = index; - updateSlidingWindow(); - - MediaItem item = mData[index % DATA_CACHE_SIZE]; - mItemPath = item == null ? null : item.getPath(); - - updateImageCache(); - updateImageRequests(); - updateTileProvider(); - - if (mDataListener != null) { - mDataListener.onPhotoChanged(index, mItemPath); - } - - fireDataChange(); - } - - private void uploadScreenNail(int offset) { - int index = mCurrentIndex + offset; - if (index < mActiveStart || index >= mActiveEnd) return; - - MediaItem item = getItem(index); - if (item == null) return; - - ImageEntry e = mImageCache.get(item.getPath()); - if (e == null) return; - - ScreenNail s = e.screenNail; - if (s instanceof TiledScreenNail) { - TiledTexture t = ((TiledScreenNail) s).getTexture(); - if (t != null && !t.isReady()) mUploader.addTexture(t); - } - } - - private void updateScreenNailUploadQueue() { - mUploader.clear(); - uploadScreenNail(0); - for (int i = 1; i < IMAGE_CACHE_SIZE; ++i) { - uploadScreenNail(i); - uploadScreenNail(-i); - } - } - - @Override - public void moveTo(int index) { - updateCurrentIndex(index); - } - - @Override - public ScreenNail getScreenNail(int offset) { - int index = mCurrentIndex + offset; - if (index < 0 || index >= mSize || !mIsActive) return null; - Utils.assertTrue(index >= mActiveStart && index < mActiveEnd); - - MediaItem item = getItem(index); - if (item == null) return null; - - ImageEntry entry = mImageCache.get(item.getPath()); - if (entry == null) return null; - - // Create a default ScreenNail if the real one is not available yet, - // except for camera that a black screen is better than a gray tile. - if (entry.screenNail == null && !isCamera(offset)) { - entry.screenNail = newPlaceholderScreenNail(item); - if (offset == 0) updateTileProvider(entry); - } - - return entry.screenNail; - } - - @Override - public void getImageSize(int offset, PhotoView.Size size) { - MediaItem item = getItem(mCurrentIndex + offset); - if (item == null) { - size.width = 0; - size.height = 0; - } else { - size.width = item.getWidth(); - size.height = item.getHeight(); - } - } - - @Override - public int getImageRotation(int offset) { - MediaItem item = getItem(mCurrentIndex + offset); - return (item == null) ? 0 : item.getFullImageRotation(); - } - - @Override - public void setNeedFullImage(boolean enabled) { - mNeedFullImage = enabled; - mMainHandler.sendEmptyMessage(MSG_UPDATE_IMAGE_REQUESTS); - } - - @Override - public boolean isCamera(int offset) { - return mCurrentIndex + offset == mCameraIndex; - } - - @Override - public boolean isPanorama(int offset) { - return isCamera(offset) && mIsPanorama; - } - - @Override - public boolean isStaticCamera(int offset) { - return isCamera(offset) && mIsStaticCamera; - } - - @Override - public boolean isVideo(int offset) { - MediaItem item = getItem(mCurrentIndex + offset); - return (item == null) - ? false - : item.getMediaType() == MediaItem.MEDIA_TYPE_VIDEO; - } - - @Override - public boolean isDeletable(int offset) { - MediaItem item = getItem(mCurrentIndex + offset); - return (item == null) - ? false - : (item.getSupportedOperations() & MediaItem.SUPPORT_DELETE) != 0; - } - - @Override - public int getLoadingState(int offset) { - ImageEntry entry = mImageCache.get(getPath(mCurrentIndex + offset)); - if (entry == null) return LOADING_INIT; - if (entry.failToLoad) return LOADING_FAIL; - if (entry.screenNail != null) return LOADING_COMPLETE; - return LOADING_INIT; - } - - @Override - public ScreenNail getScreenNail() { - return getScreenNail(0); - } - - @Override - public int getImageHeight() { - return mTileProvider.getImageHeight(); - } - - @Override - public int getImageWidth() { - return mTileProvider.getImageWidth(); - } - - @Override - public int getLevelCount() { - return mTileProvider.getLevelCount(); - } - - @Override - public Bitmap getTile(int level, int x, int y, int tileSize) { - return mTileProvider.getTile(level, x, y, tileSize); - } - - @Override - public boolean isEmpty() { - return mSize == 0; - } - - @Override - public int getCurrentIndex() { - return mCurrentIndex; - } - - @Override - public MediaItem getMediaItem(int offset) { - int index = mCurrentIndex + offset; - if (index >= mContentStart && index < mContentEnd) { - return mData[index % DATA_CACHE_SIZE]; - } - return null; - } - - @Override - public void setCurrentPhoto(Path path, int indexHint) { - if (mItemPath == path) return; - mItemPath = path; - mCurrentIndex = indexHint; - updateSlidingWindow(); - updateImageCache(); - fireDataChange(); - - // We need to reload content if the path doesn't match. - MediaItem item = getMediaItem(0); - if (item != null && item.getPath() != path) { - if (mReloadTask != null) mReloadTask.notifyDirty(); - } - } - - @Override - public void setFocusHintDirection(int direction) { - mFocusHintDirection = direction; - } - - @Override - public void setFocusHintPath(Path path) { - mFocusHintPath = path; - } - - private void updateTileProvider() { - ImageEntry entry = mImageCache.get(getPath(mCurrentIndex)); - if (entry == null) { // in loading - mTileProvider.clear(); - } else { - updateTileProvider(entry); - } - } - - private void updateTileProvider(ImageEntry entry) { - ScreenNail screenNail = entry.screenNail; - BitmapRegionDecoder fullImage = entry.fullImage; - if (screenNail != null) { - if (fullImage != null) { - mTileProvider.setScreenNail(screenNail, - fullImage.getWidth(), fullImage.getHeight()); - mTileProvider.setRegionDecoder(fullImage); - } else { - int width = screenNail.getWidth(); - int height = screenNail.getHeight(); - mTileProvider.setScreenNail(screenNail, width, height); - } - } else { - mTileProvider.clear(); - } - } - - private void updateSlidingWindow() { - // 1. Update the image window - int start = Utils.clamp(mCurrentIndex - IMAGE_CACHE_SIZE / 2, - 0, Math.max(0, mSize - IMAGE_CACHE_SIZE)); - int end = Math.min(mSize, start + IMAGE_CACHE_SIZE); - - if (mActiveStart == start && mActiveEnd == end) return; - - mActiveStart = start; - mActiveEnd = end; - - // 2. Update the data window - start = Utils.clamp(mCurrentIndex - DATA_CACHE_SIZE / 2, - 0, Math.max(0, mSize - DATA_CACHE_SIZE)); - end = Math.min(mSize, start + DATA_CACHE_SIZE); - if (mContentStart > mActiveStart || mContentEnd < mActiveEnd - || Math.abs(start - mContentStart) > MIN_LOAD_COUNT) { - for (int i = mContentStart; i < mContentEnd; ++i) { - if (i < start || i >= end) { - mData[i % DATA_CACHE_SIZE] = null; - } - } - mContentStart = start; - mContentEnd = end; - if (mReloadTask != null) mReloadTask.notifyDirty(); - } - } - - private void updateImageRequests() { - if (!mIsActive) return; - - int currentIndex = mCurrentIndex; - MediaItem item = mData[currentIndex % DATA_CACHE_SIZE]; - if (item == null || item.getPath() != mItemPath) { - // current item mismatch - don't request image - return; - } - - // 1. Find the most wanted request and start it (if not already started). - Future<?> task = null; - for (int i = 0; i < sImageFetchSeq.length; i++) { - int offset = sImageFetchSeq[i].indexOffset; - int bit = sImageFetchSeq[i].imageBit; - if (bit == BIT_FULL_IMAGE && !mNeedFullImage) continue; - task = startTaskIfNeeded(currentIndex + offset, bit); - if (task != null) break; - } - - // 2. Cancel everything else. - for (ImageEntry entry : mImageCache.values()) { - if (entry.screenNailTask != null && entry.screenNailTask != task) { - entry.screenNailTask.cancel(); - entry.screenNailTask = null; - entry.requestedScreenNail = MediaObject.INVALID_DATA_VERSION; - } - if (entry.fullImageTask != null && entry.fullImageTask != task) { - entry.fullImageTask.cancel(); - entry.fullImageTask = null; - entry.requestedFullImage = MediaObject.INVALID_DATA_VERSION; - } - } - } - - private class ScreenNailJob implements Job<ScreenNail> { - private MediaItem mItem; - - public ScreenNailJob(MediaItem item) { - mItem = item; - } - - @Override - public ScreenNail run(JobContext jc) { - // We try to get a ScreenNail first, if it fails, we fallback to get - // a Bitmap and then wrap it in a BitmapScreenNail instead. - ScreenNail s = mItem.getScreenNail(); - if (s != null) return s; - - // If this is a temporary item, don't try to get its bitmap because - // it won't be available. We will get its bitmap after a data reload. - if (isTemporaryItem(mItem)) { - return newPlaceholderScreenNail(mItem); - } - - Bitmap bitmap = mItem.requestImage(MediaItem.TYPE_THUMBNAIL).run(jc); - if (jc.isCancelled()) return null; - if (bitmap != null) { - bitmap = BitmapUtils.rotateBitmap(bitmap, - mItem.getRotation() - mItem.getFullImageRotation(), true); - } - return bitmap == null ? null : new TiledScreenNail(bitmap); - } - } - - private class FullImageJob implements Job<BitmapRegionDecoder> { - private MediaItem mItem; - - public FullImageJob(MediaItem item) { - mItem = item; - } - - @Override - public BitmapRegionDecoder run(JobContext jc) { - if (isTemporaryItem(mItem)) { - return null; - } - return mItem.requestLargeImage().run(jc); - } - } - - // Returns true if we think this is a temporary item created by Camera. A - // temporary item is an image or a video whose data is still being - // processed, but an incomplete entry is created first in MediaProvider, so - // we can display them (in grey tile) even if they are not saved to disk - // yet. When the image or video data is actually saved, we will get - // notification from MediaProvider, reload data, and show the actual image - // or video data. - private boolean isTemporaryItem(MediaItem mediaItem) { - // Must have camera to create a temporary item. - if (mCameraIndex < 0) return false; - // Must be an item in camera roll. - if (!(mediaItem instanceof LocalMediaItem)) return false; - LocalMediaItem item = (LocalMediaItem) mediaItem; - if (item.getBucketId() != MediaSetUtils.CAMERA_BUCKET_ID) return false; - // Must have no size, but must have width and height information - if (item.getSize() != 0) return false; - if (item.getWidth() == 0) return false; - if (item.getHeight() == 0) return false; - // Must be created in the last 10 seconds. - if (item.getDateInMs() - System.currentTimeMillis() > 10000) return false; - return true; - } - - // Create a default ScreenNail when a ScreenNail is needed, but we don't yet - // have one available (because the image data is still being saved, or the - // Bitmap is still being loaded. - private ScreenNail newPlaceholderScreenNail(MediaItem item) { - int width = item.getWidth(); - int height = item.getHeight(); - return new TiledScreenNail(width, height); - } - - // Returns the task if we started the task or the task is already started. - private Future<?> startTaskIfNeeded(int index, int which) { - if (index < mActiveStart || index >= mActiveEnd) return null; - - ImageEntry entry = mImageCache.get(getPath(index)); - if (entry == null) return null; - MediaItem item = mData[index % DATA_CACHE_SIZE]; - Utils.assertTrue(item != null); - long version = item.getDataVersion(); - - if (which == BIT_SCREEN_NAIL && entry.screenNailTask != null - && entry.requestedScreenNail == version) { - return entry.screenNailTask; - } else if (which == BIT_FULL_IMAGE && entry.fullImageTask != null - && entry.requestedFullImage == version) { - return entry.fullImageTask; - } - - if (which == BIT_SCREEN_NAIL && entry.requestedScreenNail != version) { - entry.requestedScreenNail = version; - entry.screenNailTask = mThreadPool.submit( - new ScreenNailJob(item), - new ScreenNailListener(item)); - // request screen nail - return entry.screenNailTask; - } - if (which == BIT_FULL_IMAGE && entry.requestedFullImage != version - && (item.getSupportedOperations() - & MediaItem.SUPPORT_FULL_IMAGE) != 0) { - entry.requestedFullImage = version; - entry.fullImageTask = mThreadPool.submit( - new FullImageJob(item), - new FullImageListener(item)); - // request full image - return entry.fullImageTask; - } - return null; - } - - private void updateImageCache() { - HashSet<Path> toBeRemoved = new HashSet<Path>(mImageCache.keySet()); - for (int i = mActiveStart; i < mActiveEnd; ++i) { - MediaItem item = mData[i % DATA_CACHE_SIZE]; - if (item == null) continue; - Path path = item.getPath(); - ImageEntry entry = mImageCache.get(path); - toBeRemoved.remove(path); - if (entry != null) { - if (Math.abs(i - mCurrentIndex) > 1) { - if (entry.fullImageTask != null) { - entry.fullImageTask.cancel(); - entry.fullImageTask = null; - } - entry.fullImage = null; - entry.requestedFullImage = MediaObject.INVALID_DATA_VERSION; - } - if (entry.requestedScreenNail != item.getDataVersion()) { - // This ScreenNail is outdated, we want to update it if it's - // still a placeholder. - if (entry.screenNail instanceof TiledScreenNail) { - TiledScreenNail s = (TiledScreenNail) entry.screenNail; - s.updatePlaceholderSize( - item.getWidth(), item.getHeight()); - } - } - } else { - entry = new ImageEntry(); - mImageCache.put(path, entry); - } - } - - // Clear the data and requests for ImageEntries outside the new window. - for (Path path : toBeRemoved) { - ImageEntry entry = mImageCache.remove(path); - if (entry.fullImageTask != null) entry.fullImageTask.cancel(); - if (entry.screenNailTask != null) entry.screenNailTask.cancel(); - if (entry.screenNail != null) entry.screenNail.recycle(); - } - - updateScreenNailUploadQueue(); - } - - private class FullImageListener - implements Runnable, FutureListener<BitmapRegionDecoder> { - private final Path mPath; - private Future<BitmapRegionDecoder> mFuture; - - public FullImageListener(MediaItem item) { - mPath = item.getPath(); - } - - @Override - public void onFutureDone(Future<BitmapRegionDecoder> future) { - mFuture = future; - mMainHandler.sendMessage( - mMainHandler.obtainMessage(MSG_RUN_OBJECT, this)); - } - - @Override - public void run() { - updateFullImage(mPath, mFuture); - } - } - - private class ScreenNailListener - implements Runnable, FutureListener<ScreenNail> { - private final Path mPath; - private Future<ScreenNail> mFuture; - - public ScreenNailListener(MediaItem item) { - mPath = item.getPath(); - } - - @Override - public void onFutureDone(Future<ScreenNail> future) { - mFuture = future; - mMainHandler.sendMessage( - mMainHandler.obtainMessage(MSG_RUN_OBJECT, this)); - } - - @Override - public void run() { - updateScreenNail(mPath, mFuture); - } - } - - private static class ImageEntry { - public BitmapRegionDecoder fullImage; - public ScreenNail screenNail; - public Future<ScreenNail> screenNailTask; - public Future<BitmapRegionDecoder> fullImageTask; - public long requestedScreenNail = MediaObject.INVALID_DATA_VERSION; - public long requestedFullImage = MediaObject.INVALID_DATA_VERSION; - public boolean failToLoad = false; - } - - private class SourceListener implements ContentListener { - @Override - public void onContentDirty() { - if (mReloadTask != null) mReloadTask.notifyDirty(); - } - } - - private <T> T executeAndWait(Callable<T> callable) { - FutureTask<T> task = new FutureTask<T>(callable); - mMainHandler.sendMessage( - mMainHandler.obtainMessage(MSG_RUN_OBJECT, task)); - try { - return task.get(); - } catch (InterruptedException e) { - return null; - } catch (ExecutionException e) { - throw new RuntimeException(e); - } - } - - private static class UpdateInfo { - public long version; - public boolean reloadContent; - public Path target; - public int indexHint; - public int contentStart; - public int contentEnd; - - public int size; - public ArrayList<MediaItem> items; - } - - private class GetUpdateInfo implements Callable<UpdateInfo> { - - private boolean needContentReload() { - for (int i = mContentStart, n = mContentEnd; i < n; ++i) { - if (mData[i % DATA_CACHE_SIZE] == null) return true; - } - MediaItem current = mData[mCurrentIndex % DATA_CACHE_SIZE]; - return current == null || current.getPath() != mItemPath; - } - - @Override - public UpdateInfo call() throws Exception { - // TODO: Try to load some data in first update - UpdateInfo info = new UpdateInfo(); - info.version = mSourceVersion; - info.reloadContent = needContentReload(); - info.target = mItemPath; - info.indexHint = mCurrentIndex; - info.contentStart = mContentStart; - info.contentEnd = mContentEnd; - info.size = mSize; - return info; - } - } - - private class UpdateContent implements Callable<Void> { - UpdateInfo mUpdateInfo; - - public UpdateContent(UpdateInfo updateInfo) { - mUpdateInfo = updateInfo; - } - - @Override - public Void call() throws Exception { - UpdateInfo info = mUpdateInfo; - mSourceVersion = info.version; - - if (info.size != mSize) { - mSize = info.size; - if (mContentEnd > mSize) mContentEnd = mSize; - if (mActiveEnd > mSize) mActiveEnd = mSize; - } - - mCurrentIndex = info.indexHint; - updateSlidingWindow(); - - if (info.items != null) { - int start = Math.max(info.contentStart, mContentStart); - int end = Math.min(info.contentStart + info.items.size(), mContentEnd); - int dataIndex = start % DATA_CACHE_SIZE; - for (int i = start; i < end; ++i) { - mData[dataIndex] = info.items.get(i - info.contentStart); - if (++dataIndex == DATA_CACHE_SIZE) dataIndex = 0; - } - } - - // update mItemPath - MediaItem current = mData[mCurrentIndex % DATA_CACHE_SIZE]; - mItemPath = current == null ? null : current.getPath(); - - updateImageCache(); - updateTileProvider(); - updateImageRequests(); - - if (mDataListener != null) { - mDataListener.onPhotoChanged(mCurrentIndex, mItemPath); - } - - fireDataChange(); - return null; - } - } - - private class ReloadTask extends Thread { - private volatile boolean mActive = true; - private volatile boolean mDirty = true; - - private boolean mIsLoading = false; - - private void updateLoading(boolean loading) { - if (mIsLoading == loading) return; - mIsLoading = loading; - mMainHandler.sendEmptyMessage(loading ? MSG_LOAD_START : MSG_LOAD_FINISH); - } - - @Override - public void run() { - while (mActive) { - synchronized (this) { - if (!mDirty && mActive) { - updateLoading(false); - Utils.waitWithoutInterrupt(this); - continue; - } - } - mDirty = false; - UpdateInfo info = executeAndWait(new GetUpdateInfo()); - updateLoading(true); - long version = mSource.reload(); - if (info.version != version) { - info.reloadContent = true; - info.size = mSource.getMediaItemCount(); - } - if (!info.reloadContent) continue; - info.items = mSource.getMediaItem( - info.contentStart, info.contentEnd); - - int index = MediaSet.INDEX_NOT_FOUND; - - // First try to focus on the given hint path if there is one. - if (mFocusHintPath != null) { - index = findIndexOfPathInCache(info, mFocusHintPath); - mFocusHintPath = null; - } - - // Otherwise try to see if the currently focused item can be found. - if (index == MediaSet.INDEX_NOT_FOUND) { - MediaItem item = findCurrentMediaItem(info); - if (item != null && item.getPath() == info.target) { - index = info.indexHint; - } else { - index = findIndexOfTarget(info); - } - } - - // The image has been deleted. Focus on the next image (keep - // mCurrentIndex unchanged) or the previous image (decrease - // mCurrentIndex by 1). In page mode we want to see the next - // image, so we focus on the next one. In film mode we want the - // later images to shift left to fill the empty space, so we - // focus on the previous image (so it will not move). In any - // case the index needs to be limited to [0, mSize). - if (index == MediaSet.INDEX_NOT_FOUND) { - index = info.indexHint; - int focusHintDirection = mFocusHintDirection; - if (index == (mCameraIndex + 1)) { - focusHintDirection = FOCUS_HINT_NEXT; - } - if (focusHintDirection == FOCUS_HINT_PREVIOUS - && index > 0) { - index--; - } - } - - // Don't change index if mSize == 0 - if (mSize > 0) { - if (index >= mSize) index = mSize - 1; - } - - info.indexHint = index; - - executeAndWait(new UpdateContent(info)); - } - } - - public synchronized void notifyDirty() { - mDirty = true; - notifyAll(); - } - - public synchronized void terminate() { - mActive = false; - notifyAll(); - } - - private MediaItem findCurrentMediaItem(UpdateInfo info) { - ArrayList<MediaItem> items = info.items; - int index = info.indexHint - info.contentStart; - return index < 0 || index >= items.size() ? null : items.get(index); - } - - private int findIndexOfTarget(UpdateInfo info) { - if (info.target == null) return info.indexHint; - ArrayList<MediaItem> items = info.items; - - // First, try to find the item in the data just loaded - if (items != null) { - int i = findIndexOfPathInCache(info, info.target); - if (i != MediaSet.INDEX_NOT_FOUND) return i; - } - - // Not found, find it in mSource. - return mSource.getIndexOfItem(info.target, info.indexHint); - } - - private int findIndexOfPathInCache(UpdateInfo info, Path path) { - ArrayList<MediaItem> items = info.items; - for (int i = 0, n = items.size(); i < n; ++i) { - MediaItem item = items.get(i); - if (item != null && item.getPath() == path) { - return i + info.contentStart; - } - } - return MediaSet.INDEX_NOT_FOUND; - } - } -} diff --git a/src/com/android/gallery3d/app/PhotoPage.java b/src/com/android/gallery3d/app/PhotoPage.java deleted file mode 100644 index 7a71e9109..000000000 --- a/src/com/android/gallery3d/app/PhotoPage.java +++ /dev/null @@ -1,1571 +0,0 @@ -/* - * Copyright (C) 2010 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.annotation.TargetApi; -import android.app.ActionBar.OnMenuVisibilityListener; -import android.app.Activity; -import android.content.ActivityNotFoundException; -import android.content.Context; -import android.content.Intent; -import android.content.pm.PackageManager; -import android.content.res.Configuration; -import android.graphics.Rect; -import android.net.Uri; -import android.nfc.NfcAdapter; -import android.nfc.NfcAdapter.CreateBeamUrisCallback; -import android.nfc.NfcEvent; -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.ShareActionProvider; -import android.widget.Toast; - -import com.android.camera.CameraActivity; -import com.android.camera.ProxyLauncher; -import com.android.gallery3d.R; -import com.android.gallery3d.common.ApiHelper; -import com.android.gallery3d.data.ComboAlbum; -import com.android.gallery3d.data.DataManager; -import com.android.gallery3d.data.FilterDeleteSet; -import com.android.gallery3d.data.FilterSource; -import com.android.gallery3d.data.LocalImage; -import com.android.gallery3d.data.MediaDetails; -import com.android.gallery3d.data.MediaItem; -import com.android.gallery3d.data.MediaObject; -import com.android.gallery3d.data.MediaObject.PanoramaSupportCallback; -import com.android.gallery3d.data.MediaSet; -import com.android.gallery3d.data.Path; -import com.android.gallery3d.data.SecureAlbum; -import com.android.gallery3d.data.SecureSource; -import com.android.gallery3d.data.SnailAlbum; -import com.android.gallery3d.data.SnailItem; -import com.android.gallery3d.data.SnailSource; -import com.android.gallery3d.filtershow.FilterShowActivity; -import com.android.gallery3d.filtershow.crop.CropActivity; -import com.android.gallery3d.picasasource.PicasaSource; -import com.android.gallery3d.ui.DetailsHelper; -import com.android.gallery3d.ui.DetailsHelper.CloseListener; -import com.android.gallery3d.ui.DetailsHelper.DetailsSource; -import com.android.gallery3d.ui.GLView; -import com.android.gallery3d.ui.MenuExecutor; -import com.android.gallery3d.ui.PhotoView; -import com.android.gallery3d.ui.SelectionManager; -import com.android.gallery3d.ui.SynchronizedHandler; -import com.android.gallery3d.util.GalleryUtils; -import com.android.gallery3d.util.UsageStatistics; - -public abstract class PhotoPage extends ActivityState implements - PhotoView.Listener, AppBridge.Server, ShareActionProvider.OnShareTargetSelectedListener, - PhotoPageBottomControls.Delegate, GalleryActionBar.OnAlbumModeSelectedListener { - private static final String TAG = "PhotoPage"; - - private static final int MSG_HIDE_BARS = 1; - private static final int MSG_ON_FULL_SCREEN_CHANGED = 4; - private static final int MSG_UPDATE_ACTION_BAR = 5; - private static final int MSG_UNFREEZE_GLROOT = 6; - private static final int MSG_WANT_BARS = 7; - private static final int MSG_REFRESH_BOTTOM_CONTROLS = 8; - private static final int MSG_ON_CAMERA_CENTER = 9; - private static final int MSG_ON_PICTURE_CENTER = 10; - private static final int MSG_REFRESH_IMAGE = 11; - private static final int MSG_UPDATE_PHOTO_UI = 12; - private static final int MSG_UPDATE_PROGRESS = 13; - private static final int MSG_UPDATE_DEFERRED = 14; - private static final int MSG_UPDATE_SHARE_URI = 15; - private static final int MSG_UPDATE_PANORAMA_UI = 16; - - private static final int HIDE_BARS_TIMEOUT = 3500; - private static final int UNFREEZE_GLROOT_TIMEOUT = 250; - - private static final int REQUEST_SLIDESHOW = 1; - private static final int REQUEST_CROP = 2; - private static final int REQUEST_CROP_PICASA = 3; - private static final int REQUEST_EDIT = 4; - private static final int REQUEST_PLAY_VIDEO = 5; - private static final int REQUEST_TRIM = 6; - - public static final String KEY_MEDIA_SET_PATH = "media-set-path"; - public static final String KEY_MEDIA_ITEM_PATH = "media-item-path"; - public static final String KEY_INDEX_HINT = "index-hint"; - public static final String KEY_OPEN_ANIMATION_RECT = "open-animation-rect"; - public static final String KEY_APP_BRIDGE = "app-bridge"; - public static final String KEY_TREAT_BACK_AS_UP = "treat-back-as-up"; - public static final String KEY_START_IN_FILMSTRIP = "start-in-filmstrip"; - public static final String KEY_RETURN_INDEX_HINT = "return-index-hint"; - public static final String KEY_SHOW_WHEN_LOCKED = "show_when_locked"; - public static final String KEY_IN_CAMERA_ROLL = "in_camera_roll"; - - public static final String KEY_ALBUMPAGE_TRANSITION = "albumpage-transition"; - public static final int MSG_ALBUMPAGE_NONE = 0; - public static final int MSG_ALBUMPAGE_STARTED = 1; - public static final int MSG_ALBUMPAGE_RESUMED = 2; - public static final int MSG_ALBUMPAGE_PICKED = 4; - - public static final String ACTION_NEXTGEN_EDIT = "action_nextgen_edit"; - public static final String ACTION_SIMPLE_EDIT = "action_simple_edit"; - - private GalleryApp mApplication; - private SelectionManager mSelectionManager; - - private PhotoView mPhotoView; - private PhotoPage.Model mModel; - private DetailsHelper mDetailsHelper; - private boolean mShowDetails; - - // mMediaSet could be null if there is no KEY_MEDIA_SET_PATH supplied. - // E.g., viewing a photo in gmail attachment - private FilterDeleteSet mMediaSet; - - // The mediaset used by camera launched from secure lock screen. - private SecureAlbum mSecureAlbum; - - private int mCurrentIndex = 0; - private Handler mHandler; - private boolean mShowBars = true; - private volatile boolean mActionBarAllowed = true; - private GalleryActionBar mActionBar; - private boolean mIsMenuVisible; - private boolean mHaveImageEditor; - private PhotoPageBottomControls mBottomControls; - private PhotoPageProgressBar mProgressBar; - private MediaItem mCurrentPhoto = null; - private MenuExecutor mMenuExecutor; - private boolean mIsActive; - private boolean mShowSpinner; - private String mSetPathString; - // This is the original mSetPathString before adding the camera preview item. - private String mOriginalSetPathString; - private AppBridge mAppBridge; - private SnailItem mScreenNailItem; - private SnailAlbum mScreenNailSet; - private OrientationManager mOrientationManager; - private boolean mTreatBackAsUp; - private boolean mStartInFilmstrip; - private boolean mHasCameraScreennailOrPlaceholder = false; - private boolean mRecenterCameraOnResume = true; - - // These are only valid after the panorama callback - private boolean mIsPanorama; - private boolean mIsPanorama360; - - private long mCameraSwitchCutoff = 0; - private boolean mSkipUpdateCurrentPhoto = false; - private static final long CAMERA_SWITCH_CUTOFF_THRESHOLD_MS = 300; - - private static final long DEFERRED_UPDATE_MS = 250; - private boolean mDeferredUpdateWaiting = false; - private long mDeferUpdateUntil = Long.MAX_VALUE; - - // The item that is deleted (but it can still be undeleted before commiting) - private Path mDeletePath; - private boolean mDeleteIsFocus; // whether the deleted item was in focus - - private Uri[] mNfcPushUris = new Uri[1]; - - private final MyMenuVisibilityListener mMenuVisibilityListener = - new MyMenuVisibilityListener(); - private UpdateProgressListener mProgressListener; - - private final PanoramaSupportCallback mUpdatePanoramaMenuItemsCallback = new PanoramaSupportCallback() { - @Override - public void panoramaInfoAvailable(MediaObject mediaObject, boolean isPanorama, - boolean isPanorama360) { - if (mediaObject == mCurrentPhoto) { - mHandler.obtainMessage(MSG_UPDATE_PANORAMA_UI, isPanorama360 ? 1 : 0, 0, - mediaObject).sendToTarget(); - } - } - }; - - private final PanoramaSupportCallback mRefreshBottomControlsCallback = new PanoramaSupportCallback() { - @Override - public void panoramaInfoAvailable(MediaObject mediaObject, boolean isPanorama, - boolean isPanorama360) { - if (mediaObject == mCurrentPhoto) { - mHandler.obtainMessage(MSG_REFRESH_BOTTOM_CONTROLS, isPanorama ? 1 : 0, isPanorama360 ? 1 : 0, - mediaObject).sendToTarget(); - } - } - }; - - private final PanoramaSupportCallback mUpdateShareURICallback = new PanoramaSupportCallback() { - @Override - public void panoramaInfoAvailable(MediaObject mediaObject, boolean isPanorama, - boolean isPanorama360) { - if (mediaObject == mCurrentPhoto) { - mHandler.obtainMessage(MSG_UPDATE_SHARE_URI, isPanorama360 ? 1 : 0, 0, mediaObject) - .sendToTarget(); - } - } - }; - - public static interface Model extends PhotoView.Model { - public void resume(); - public void pause(); - public boolean isEmpty(); - public void setCurrentPhoto(Path path, int indexHint); - } - - private class MyMenuVisibilityListener implements OnMenuVisibilityListener { - @Override - public void onMenuVisibilityChanged(boolean isVisible) { - mIsMenuVisible = isVisible; - refreshHidingMessage(); - } - } - - private class UpdateProgressListener implements StitchingChangeListener { - - @Override - public void onStitchingResult(Uri uri) { - sendUpdate(uri, MSG_REFRESH_IMAGE); - } - - @Override - public void onStitchingQueued(Uri uri) { - sendUpdate(uri, MSG_UPDATE_PROGRESS); - } - - @Override - public void onStitchingProgress(Uri uri, final int progress) { - sendUpdate(uri, MSG_UPDATE_PROGRESS); - } - - private void sendUpdate(Uri uri, int message) { - MediaObject currentPhoto = mCurrentPhoto; - boolean isCurrentPhoto = currentPhoto instanceof LocalImage - && currentPhoto.getContentUri().equals(uri); - if (isCurrentPhoto) { - mHandler.sendEmptyMessage(message); - } - } - }; - - @Override - protected int getBackgroundColorId() { - return R.color.photo_background; - } - - private final GLView mRootPane = new GLView() { - @Override - protected void onLayout( - boolean changed, int left, int top, int right, int bottom) { - mPhotoView.layout(0, 0, right - left, bottom - top); - if (mShowDetails) { - mDetailsHelper.layout(left, mActionBar.getHeight(), right, bottom); - } - } - }; - - @Override - public void onCreate(Bundle data, Bundle restoreState) { - super.onCreate(data, restoreState); - mActionBar = mActivity.getGalleryActionBar(); - mSelectionManager = new SelectionManager(mActivity, false); - mMenuExecutor = new MenuExecutor(mActivity, mSelectionManager); - - mPhotoView = new PhotoView(mActivity); - mPhotoView.setListener(this); - mRootPane.addComponent(mPhotoView); - mApplication = (GalleryApp) ((Activity) mActivity).getApplication(); - mOrientationManager = mActivity.getOrientationManager(); - mActivity.getGLRoot().setOrientationSource(mOrientationManager); - - mHandler = new SynchronizedHandler(mActivity.getGLRoot()) { - @Override - public void handleMessage(Message message) { - switch (message.what) { - case MSG_HIDE_BARS: { - hideBars(); - break; - } - case MSG_REFRESH_BOTTOM_CONTROLS: { - if (mCurrentPhoto == message.obj && mBottomControls != null) { - mIsPanorama = message.arg1 == 1; - mIsPanorama360 = message.arg2 == 1; - mBottomControls.refresh(); - } - break; - } - case MSG_ON_FULL_SCREEN_CHANGED: { - if (mAppBridge != null) { - mAppBridge.onFullScreenChanged(message.arg1 == 1); - } - break; - } - case MSG_UPDATE_ACTION_BAR: { - updateBars(); - break; - } - case MSG_WANT_BARS: { - wantBars(); - break; - } - case MSG_UNFREEZE_GLROOT: { - mActivity.getGLRoot().unfreeze(); - break; - } - case MSG_UPDATE_DEFERRED: { - long nextUpdate = mDeferUpdateUntil - SystemClock.uptimeMillis(); - if (nextUpdate <= 0) { - mDeferredUpdateWaiting = false; - updateUIForCurrentPhoto(); - } else { - mHandler.sendEmptyMessageDelayed(MSG_UPDATE_DEFERRED, nextUpdate); - } - break; - } - case MSG_ON_CAMERA_CENTER: { - mSkipUpdateCurrentPhoto = false; - boolean stayedOnCamera = false; - if (!mPhotoView.getFilmMode()) { - stayedOnCamera = true; - } else if (SystemClock.uptimeMillis() < mCameraSwitchCutoff && - mMediaSet.getMediaItemCount() > 1) { - mPhotoView.switchToImage(1); - } else { - if (mAppBridge != null) mPhotoView.setFilmMode(false); - stayedOnCamera = true; - } - - if (stayedOnCamera) { - if (mAppBridge == null && mMediaSet.getTotalMediaItemCount() > 1) { - launchCamera(); - /* We got here by swiping from photo 1 to the - placeholder, so make it be the thing that - is in focus when the user presses back from - the camera app */ - mPhotoView.switchToImage(1); - } else { - updateBars(); - updateCurrentPhoto(mModel.getMediaItem(0)); - } - } - break; - } - case MSG_ON_PICTURE_CENTER: { - if (!mPhotoView.getFilmMode() && mCurrentPhoto != null - && (mCurrentPhoto.getSupportedOperations() & MediaObject.SUPPORT_ACTION) != 0) { - mPhotoView.setFilmMode(true); - } - break; - } - case MSG_REFRESH_IMAGE: { - final MediaItem photo = mCurrentPhoto; - mCurrentPhoto = null; - updateCurrentPhoto(photo); - break; - } - case MSG_UPDATE_PHOTO_UI: { - updateUIForCurrentPhoto(); - break; - } - case MSG_UPDATE_PROGRESS: { - updateProgressBar(); - break; - } - case MSG_UPDATE_SHARE_URI: { - if (mCurrentPhoto == message.obj) { - boolean isPanorama360 = message.arg1 != 0; - Uri contentUri = mCurrentPhoto.getContentUri(); - Intent panoramaIntent = null; - if (isPanorama360) { - panoramaIntent = createSharePanoramaIntent(contentUri); - } - Intent shareIntent = createShareIntent(mCurrentPhoto); - - mActionBar.setShareIntents(panoramaIntent, shareIntent, PhotoPage.this); - setNfcBeamPushUri(contentUri); - } - break; - } - case MSG_UPDATE_PANORAMA_UI: { - if (mCurrentPhoto == message.obj) { - boolean isPanorama360 = message.arg1 != 0; - updatePanoramaUI(isPanorama360); - } - break; - } - default: throw new AssertionError(message.what); - } - } - }; - - mSetPathString = data.getString(KEY_MEDIA_SET_PATH); - mOriginalSetPathString = mSetPathString; - setupNfcBeamPush(); - String itemPathString = data.getString(KEY_MEDIA_ITEM_PATH); - Path itemPath = itemPathString != null ? - Path.fromString(data.getString(KEY_MEDIA_ITEM_PATH)) : - null; - mTreatBackAsUp = data.getBoolean(KEY_TREAT_BACK_AS_UP, false); - mStartInFilmstrip = data.getBoolean(KEY_START_IN_FILMSTRIP, false); - boolean inCameraRoll = data.getBoolean(KEY_IN_CAMERA_ROLL, false); - mCurrentIndex = data.getInt(KEY_INDEX_HINT, 0); - if (mSetPathString != null) { - mShowSpinner = true; - mAppBridge = (AppBridge) data.getParcelable(KEY_APP_BRIDGE); - if (mAppBridge != null) { - mShowBars = false; - mHasCameraScreennailOrPlaceholder = true; - mAppBridge.setServer(this); - - // Get the ScreenNail from AppBridge and register it. - int id = SnailSource.newId(); - Path screenNailSetPath = SnailSource.getSetPath(id); - Path screenNailItemPath = SnailSource.getItemPath(id); - mScreenNailSet = (SnailAlbum) mActivity.getDataManager() - .getMediaObject(screenNailSetPath); - mScreenNailItem = (SnailItem) mActivity.getDataManager() - .getMediaObject(screenNailItemPath); - mScreenNailItem.setScreenNail(mAppBridge.attachScreenNail()); - - if (data.getBoolean(KEY_SHOW_WHEN_LOCKED, false)) { - // Set the flag to be on top of the lock screen. - mFlags |= FLAG_SHOW_WHEN_LOCKED; - } - - // Don't display "empty album" action item for capture intents. - if (!mSetPathString.equals("/local/all/0")) { - // Check if the path is a secure album. - if (SecureSource.isSecurePath(mSetPathString)) { - mSecureAlbum = (SecureAlbum) mActivity.getDataManager() - .getMediaSet(mSetPathString); - mShowSpinner = false; - } - mSetPathString = "/filter/empty/{"+mSetPathString+"}"; - } - - // Combine the original MediaSet with the one for ScreenNail - // from AppBridge. - mSetPathString = "/combo/item/{" + screenNailSetPath + - "," + mSetPathString + "}"; - - // Start from the screen nail. - itemPath = screenNailItemPath; - } else if (inCameraRoll && GalleryUtils.isCameraAvailable(mActivity)) { - mSetPathString = "/combo/item/{" + FilterSource.FILTER_CAMERA_SHORTCUT + - "," + mSetPathString + "}"; - mCurrentIndex++; - mHasCameraScreennailOrPlaceholder = true; - } - - MediaSet originalSet = mActivity.getDataManager() - .getMediaSet(mSetPathString); - if (mHasCameraScreennailOrPlaceholder && originalSet instanceof ComboAlbum) { - // Use the name of the camera album rather than the default - // ComboAlbum behavior - ((ComboAlbum) originalSet).useNameOfChild(1); - } - mSelectionManager.setSourceMediaSet(originalSet); - mSetPathString = "/filter/delete/{" + mSetPathString + "}"; - mMediaSet = (FilterDeleteSet) mActivity.getDataManager() - .getMediaSet(mSetPathString); - if (mMediaSet == null) { - Log.w(TAG, "failed to restore " + mSetPathString); - } - if (itemPath == null) { - int mediaItemCount = mMediaSet.getMediaItemCount(); - if (mediaItemCount > 0) { - if (mCurrentIndex >= mediaItemCount) mCurrentIndex = 0; - itemPath = mMediaSet.getMediaItem(mCurrentIndex, 1) - .get(0).getPath(); - } else { - // Bail out, PhotoPage can't load on an empty album - return; - } - } - PhotoDataAdapter pda = new PhotoDataAdapter( - mActivity, mPhotoView, mMediaSet, itemPath, mCurrentIndex, - mAppBridge == null ? -1 : 0, - mAppBridge == null ? false : mAppBridge.isPanorama(), - mAppBridge == null ? false : mAppBridge.isStaticCamera()); - mModel = pda; - mPhotoView.setModel(mModel); - - pda.setDataListener(new PhotoDataAdapter.DataListener() { - - @Override - public void onPhotoChanged(int index, Path item) { - int oldIndex = mCurrentIndex; - mCurrentIndex = index; - - if (mHasCameraScreennailOrPlaceholder) { - if (mCurrentIndex > 0) { - mSkipUpdateCurrentPhoto = false; - } - - if (oldIndex == 0 && mCurrentIndex > 0 - && !mPhotoView.getFilmMode()) { - mPhotoView.setFilmMode(true); - if (mAppBridge != null) { - UsageStatistics.onEvent("CameraToFilmstrip", - UsageStatistics.TRANSITION_SWIPE, null); - } - } else if (oldIndex == 2 && mCurrentIndex == 1) { - mCameraSwitchCutoff = SystemClock.uptimeMillis() + - CAMERA_SWITCH_CUTOFF_THRESHOLD_MS; - mPhotoView.stopScrolling(); - } else if (oldIndex >= 1 && mCurrentIndex == 0) { - mPhotoView.setWantPictureCenterCallbacks(true); - mSkipUpdateCurrentPhoto = true; - } - } - if (!mSkipUpdateCurrentPhoto) { - if (item != null) { - MediaItem photo = mModel.getMediaItem(0); - if (photo != null) updateCurrentPhoto(photo); - } - updateBars(); - } - // Reset the timeout for the bars after a swipe - refreshHidingMessage(); - } - - @Override - public void onLoadingFinished(boolean loadingFailed) { - if (!mModel.isEmpty()) { - MediaItem photo = mModel.getMediaItem(0); - if (photo != null) updateCurrentPhoto(photo); - } else if (mIsActive) { - // We only want to finish the PhotoPage if there is no - // deletion that the user can undo. - if (mMediaSet.getNumberOfDeletions() == 0) { - mActivity.getStateManager().finishState( - PhotoPage.this); - } - } - } - - @Override - public void onLoadingStarted() { - } - }); - } else { - // Get default media set by the URI - MediaItem mediaItem = (MediaItem) - mActivity.getDataManager().getMediaObject(itemPath); - mModel = new SinglePhotoDataAdapter(mActivity, mPhotoView, mediaItem); - mPhotoView.setModel(mModel); - updateCurrentPhoto(mediaItem); - mShowSpinner = false; - } - - mPhotoView.setFilmMode(mStartInFilmstrip && mMediaSet.getMediaItemCount() > 1); - RelativeLayout galleryRoot = (RelativeLayout) ((Activity) mActivity) - .findViewById(mAppBridge != null ? R.id.content : R.id.gallery_root); - if (galleryRoot != null) { - if (mSecureAlbum == null) { - mBottomControls = new PhotoPageBottomControls(this, mActivity, galleryRoot); - } - StitchingProgressManager progressManager = mApplication.getStitchingProgressManager(); - if (progressManager != null) { - mProgressBar = new PhotoPageProgressBar(mActivity, galleryRoot); - mProgressListener = new UpdateProgressListener(); - progressManager.addChangeListener(mProgressListener); - if (mSecureAlbum != null) { - progressManager.addChangeListener(mSecureAlbum); - } - } - } - } - - @Override - public void onPictureCenter(boolean isCamera) { - isCamera = isCamera || (mHasCameraScreennailOrPlaceholder && mAppBridge == null); - mPhotoView.setWantPictureCenterCallbacks(false); - mHandler.removeMessages(MSG_ON_CAMERA_CENTER); - mHandler.removeMessages(MSG_ON_PICTURE_CENTER); - mHandler.sendEmptyMessage(isCamera ? MSG_ON_CAMERA_CENTER : MSG_ON_PICTURE_CENTER); - } - - @Override - public boolean canDisplayBottomControls() { - return mIsActive && !mPhotoView.canUndo(); - } - - @Override - public boolean canDisplayBottomControl(int control) { - if (mCurrentPhoto == null) { - return false; - } - switch(control) { - case R.id.photopage_bottom_control_edit: - return mHaveImageEditor && mShowBars - && !mPhotoView.getFilmMode() - && (mCurrentPhoto.getSupportedOperations() & MediaItem.SUPPORT_EDIT) != 0 - && mCurrentPhoto.getMediaType() == MediaObject.MEDIA_TYPE_IMAGE; - case R.id.photopage_bottom_control_panorama: - return mIsPanorama; - case R.id.photopage_bottom_control_tiny_planet: - return mHaveImageEditor && mShowBars - && mIsPanorama360 && !mPhotoView.getFilmMode(); - default: - return false; - } - } - - @Override - public void onBottomControlClicked(int control) { - switch(control) { - case R.id.photopage_bottom_control_edit: - launchPhotoEditor(); - return; - case R.id.photopage_bottom_control_panorama: - mActivity.getPanoramaViewHelper() - .showPanorama(mCurrentPhoto.getContentUri()); - return; - case R.id.photopage_bottom_control_tiny_planet: - launchTinyPlanet(); - return; - default: - return; - } - } - - @TargetApi(ApiHelper.VERSION_CODES.JELLY_BEAN) - private void setupNfcBeamPush() { - if (!ApiHelper.HAS_SET_BEAM_PUSH_URIS) return; - - NfcAdapter adapter = NfcAdapter.getDefaultAdapter(mActivity); - if (adapter != null) { - adapter.setBeamPushUris(null, mActivity); - adapter.setBeamPushUrisCallback(new CreateBeamUrisCallback() { - @Override - public Uri[] createBeamUris(NfcEvent event) { - return mNfcPushUris; - } - }, mActivity); - } - } - - private void setNfcBeamPushUri(Uri uri) { - mNfcPushUris[0] = uri; - } - - private static Intent createShareIntent(MediaObject mediaObject) { - int type = mediaObject.getMediaType(); - return new Intent(Intent.ACTION_SEND) - .setType(MenuExecutor.getMimeType(type)) - .putExtra(Intent.EXTRA_STREAM, mediaObject.getContentUri()) - .addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); - } - - private static Intent createSharePanoramaIntent(Uri contentUri) { - return new Intent(Intent.ACTION_SEND) - .setType(GalleryUtils.MIME_TYPE_PANORAMA360) - .putExtra(Intent.EXTRA_STREAM, contentUri) - .addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); - } - - private void overrideTransitionToEditor() { - ((Activity) mActivity).overridePendingTransition(android.R.anim.fade_in, - android.R.anim.fade_out); - } - - private void launchTinyPlanet() { - // Deep link into tiny planet - MediaItem current = mModel.getMediaItem(0); - Intent intent = new Intent(FilterShowActivity.TINY_PLANET_ACTION); - intent.setClass(mActivity, FilterShowActivity.class); - intent.setDataAndType(current.getContentUri(), current.getMimeType()) - .setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); - intent.putExtra(FilterShowActivity.LAUNCH_FULLSCREEN, - mActivity.isFullscreen()); - mActivity.startActivityForResult(intent, REQUEST_EDIT); - overrideTransitionToEditor(); - } - - private void launchCamera() { - Intent intent = new Intent(mActivity, CameraActivity.class) - .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - mRecenterCameraOnResume = false; - mActivity.startActivity(intent); - } - - private void launchPhotoEditor() { - MediaItem current = mModel.getMediaItem(0); - if (current == null || (current.getSupportedOperations() - & MediaObject.SUPPORT_EDIT) == 0) { - return; - } - - Intent intent = new Intent(ACTION_NEXTGEN_EDIT); - - intent.setDataAndType(current.getContentUri(), current.getMimeType()) - .setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); - if (mActivity.getPackageManager() - .queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY).size() == 0) { - intent.setAction(Intent.ACTION_EDIT); - } - intent.putExtra(FilterShowActivity.LAUNCH_FULLSCREEN, - mActivity.isFullscreen()); - ((Activity) mActivity).startActivityForResult(Intent.createChooser(intent, null), - REQUEST_EDIT); - overrideTransitionToEditor(); - } - - private void launchSimpleEditor() { - MediaItem current = mModel.getMediaItem(0); - if (current == null || (current.getSupportedOperations() - & MediaObject.SUPPORT_EDIT) == 0) { - return; - } - - Intent intent = new Intent(ACTION_SIMPLE_EDIT); - - intent.setDataAndType(current.getContentUri(), current.getMimeType()) - .setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); - if (mActivity.getPackageManager() - .queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY).size() == 0) { - intent.setAction(Intent.ACTION_EDIT); - } - intent.putExtra(FilterShowActivity.LAUNCH_FULLSCREEN, - mActivity.isFullscreen()); - ((Activity) mActivity).startActivityForResult(Intent.createChooser(intent, null), - REQUEST_EDIT); - overrideTransitionToEditor(); - } - - private void requestDeferredUpdate() { - mDeferUpdateUntil = SystemClock.uptimeMillis() + DEFERRED_UPDATE_MS; - if (!mDeferredUpdateWaiting) { - mDeferredUpdateWaiting = true; - mHandler.sendEmptyMessageDelayed(MSG_UPDATE_DEFERRED, DEFERRED_UPDATE_MS); - } - } - - private void updateUIForCurrentPhoto() { - if (mCurrentPhoto == null) return; - - // If by swiping or deletion the user ends up on an action item - // and zoomed in, zoom out so that the context of the action is - // more clear - if ((mCurrentPhoto.getSupportedOperations() & MediaObject.SUPPORT_ACTION) != 0 - && !mPhotoView.getFilmMode()) { - mPhotoView.setWantPictureCenterCallbacks(true); - } - - updateMenuOperations(); - refreshBottomControlsWhenReady(); - if (mShowDetails) { - mDetailsHelper.reloadDetails(); - } - if ((mSecureAlbum == null) - && (mCurrentPhoto.getSupportedOperations() & MediaItem.SUPPORT_SHARE) != 0) { - mCurrentPhoto.getPanoramaSupport(mUpdateShareURICallback); - } - updateProgressBar(); - } - - private void updateCurrentPhoto(MediaItem photo) { - if (mCurrentPhoto == photo) return; - mCurrentPhoto = photo; - if (mPhotoView.getFilmMode()) { - requestDeferredUpdate(); - } else { - updateUIForCurrentPhoto(); - } - } - - private void updateProgressBar() { - if (mProgressBar != null) { - mProgressBar.hideProgress(); - StitchingProgressManager progressManager = mApplication.getStitchingProgressManager(); - if (progressManager != null && mCurrentPhoto instanceof LocalImage) { - Integer progress = progressManager.getProgress(mCurrentPhoto.getContentUri()); - if (progress != null) { - mProgressBar.setProgress(progress); - } - } - } - } - - private void updateMenuOperations() { - Menu menu = mActionBar.getMenu(); - - // it could be null if onCreateActionBar has not been called yet - if (menu == null) return; - - MenuItem item = menu.findItem(R.id.action_slideshow); - if (item != null) { - item.setVisible((mSecureAlbum == null) && canDoSlideShow()); - } - if (mCurrentPhoto == null) return; - - int supportedOperations = mCurrentPhoto.getSupportedOperations(); - if (mSecureAlbum != null) { - supportedOperations &= MediaObject.SUPPORT_DELETE; - } else { - mCurrentPhoto.getPanoramaSupport(mUpdatePanoramaMenuItemsCallback); - if (!mHaveImageEditor) { - supportedOperations &= ~MediaObject.SUPPORT_EDIT; - } - } - MenuExecutor.updateMenuOperation(menu, supportedOperations); - } - - private boolean canDoSlideShow() { - if (mMediaSet == null || mCurrentPhoto == null) { - return false; - } - if (mCurrentPhoto.getMediaType() != MediaObject.MEDIA_TYPE_IMAGE) { - return false; - } - return true; - } - - ////////////////////////////////////////////////////////////////////////// - // Action Bar show/hide management - ////////////////////////////////////////////////////////////////////////// - - private void showBars() { - if (mShowBars) return; - mShowBars = true; - mOrientationManager.unlockOrientation(); - mActionBar.show(); - mActivity.getGLRoot().setLightsOutMode(false); - refreshHidingMessage(); - refreshBottomControlsWhenReady(); - } - - private void hideBars() { - if (!mShowBars) return; - mShowBars = false; - mActionBar.hide(); - mActivity.getGLRoot().setLightsOutMode(true); - mHandler.removeMessages(MSG_HIDE_BARS); - refreshBottomControlsWhenReady(); - } - - private void refreshHidingMessage() { - mHandler.removeMessages(MSG_HIDE_BARS); - if (!mIsMenuVisible && !mPhotoView.getFilmMode()) { - mHandler.sendEmptyMessageDelayed(MSG_HIDE_BARS, HIDE_BARS_TIMEOUT); - } - } - - private boolean canShowBars() { - // No bars if we are showing camera preview. - if (mAppBridge != null && mCurrentIndex == 0 - && !mPhotoView.getFilmMode()) return false; - - // No bars if it's not allowed. - if (!mActionBarAllowed) return false; - - Configuration config = mActivity.getResources().getConfiguration(); - if (config.touchscreen == Configuration.TOUCHSCREEN_NOTOUCH) { - return false; - } - - return true; - } - - private void wantBars() { - if (canShowBars()) showBars(); - } - - private void toggleBars() { - if (mShowBars) { - hideBars(); - } else { - if (canShowBars()) showBars(); - } - } - - private void updateBars() { - if (!canShowBars()) { - hideBars(); - } - } - - @Override - protected void onBackPressed() { - if (mShowDetails) { - hideDetails(); - } else if (mAppBridge == null || !switchWithCaptureAnimation(-1)) { - // We are leaving this page. Set the result now. - setResult(); - if (mStartInFilmstrip && !mPhotoView.getFilmMode()) { - mPhotoView.setFilmMode(true); - } else if (mTreatBackAsUp) { - onUpPressed(); - } else { - super.onBackPressed(); - } - } - } - - private void onUpPressed() { - if ((mStartInFilmstrip || mAppBridge != null) - && !mPhotoView.getFilmMode()) { - mPhotoView.setFilmMode(true); - return; - } - - if (mActivity.getStateManager().getStateCount() > 1) { - setResult(); - super.onBackPressed(); - return; - } - - if (mOriginalSetPathString == null) return; - - if (mAppBridge == null) { - // We're in view mode so set up the stacks on our own. - Bundle data = new Bundle(getData()); - data.putString(AlbumPage.KEY_MEDIA_PATH, mOriginalSetPathString); - data.putString(AlbumPage.KEY_PARENT_MEDIA_PATH, - mActivity.getDataManager().getTopSetPath( - DataManager.INCLUDE_ALL)); - mActivity.getStateManager().switchState(this, AlbumPage.class, data); - } else { - GalleryUtils.startGalleryActivity(mActivity); - } - } - - private void setResult() { - Intent result = null; - result = new Intent(); - result.putExtra(KEY_RETURN_INDEX_HINT, mCurrentIndex); - setStateResult(Activity.RESULT_OK, result); - } - - ////////////////////////////////////////////////////////////////////////// - // AppBridge.Server interface - ////////////////////////////////////////////////////////////////////////// - - @Override - public void setCameraRelativeFrame(Rect frame) { - mPhotoView.setCameraRelativeFrame(frame); - } - - @Override - public boolean switchWithCaptureAnimation(int offset) { - return mPhotoView.switchWithCaptureAnimation(offset); - } - - @Override - public void setSwipingEnabled(boolean enabled) { - mPhotoView.setSwipingEnabled(enabled); - } - - @Override - public void notifyScreenNailChanged() { - mScreenNailItem.setScreenNail(mAppBridge.attachScreenNail()); - mScreenNailSet.notifyChange(); - } - - @Override - public void addSecureAlbumItem(boolean isVideo, int id) { - mSecureAlbum.addMediaItem(isVideo, id); - } - - @Override - protected boolean onCreateActionBar(Menu menu) { - mActionBar.createActionBarMenu(R.menu.photo, menu); - mHaveImageEditor = GalleryUtils.isEditorAvailable(mActivity, "image/*"); - updateMenuOperations(); - mActionBar.setTitle(mMediaSet != null ? mMediaSet.getName() : ""); - return true; - } - - private MenuExecutor.ProgressListener mConfirmDialogListener = - new MenuExecutor.ProgressListener() { - @Override - public void onProgressUpdate(int index) {} - - @Override - public void onProgressComplete(int result) {} - - @Override - public void onConfirmDialogShown() { - mHandler.removeMessages(MSG_HIDE_BARS); - } - - @Override - public void onConfirmDialogDismissed(boolean confirmed) { - refreshHidingMessage(); - } - - @Override - public void onProgressStart() {} - }; - - private void switchToGrid() { - if (mActivity.getStateManager().hasStateClass(AlbumPage.class)) { - onUpPressed(); - } else { - if (mOriginalSetPathString == null) return; - if (mProgressBar != null) { - updateCurrentPhoto(null); - mProgressBar.hideProgress(); - } - Bundle data = new Bundle(getData()); - data.putString(AlbumPage.KEY_MEDIA_PATH, mOriginalSetPathString); - data.putString(AlbumPage.KEY_PARENT_MEDIA_PATH, - mActivity.getDataManager().getTopSetPath( - DataManager.INCLUDE_ALL)); - - // We only show cluster menu in the first AlbumPage in stack - // TODO: Enable this when running from the camera app - boolean inAlbum = mActivity.getStateManager().hasStateClass(AlbumPage.class); - data.putBoolean(AlbumPage.KEY_SHOW_CLUSTER_MENU, !inAlbum - && mAppBridge == null); - - data.putBoolean(PhotoPage.KEY_APP_BRIDGE, mAppBridge != null); - - // Account for live preview being first item - mActivity.getTransitionStore().put(KEY_RETURN_INDEX_HINT, - mAppBridge != null ? mCurrentIndex - 1 : mCurrentIndex); - - if (mHasCameraScreennailOrPlaceholder && mAppBridge != null) { - mActivity.getStateManager().startState(AlbumPage.class, data); - } else { - mActivity.getStateManager().switchState(this, AlbumPage.class, data); - } - } - } - - @Override - protected boolean onItemSelected(MenuItem item) { - if (mModel == null) return true; - 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(); - - DataManager manager = mActivity.getDataManager(); - int action = item.getItemId(); - String confirmMsg = null; - switch (action) { - case android.R.id.home: { - onUpPressed(); - return true; - } - case R.id.action_slideshow: { - Bundle data = new Bundle(); - data.putString(SlideshowPage.KEY_SET_PATH, mMediaSet.getPath().toString()); - data.putString(SlideshowPage.KEY_ITEM_PATH, path.toString()); - data.putInt(SlideshowPage.KEY_PHOTO_INDEX, currentIndex); - data.putBoolean(SlideshowPage.KEY_REPEAT, true); - mActivity.getStateManager().startStateForResult( - SlideshowPage.class, REQUEST_SLIDESHOW, data); - return true; - } - case R.id.action_crop: { - Activity activity = mActivity; - Intent intent = new Intent(CropActivity.CROP_ACTION); - intent.setClass(activity, CropActivity.class); - intent.setDataAndType(manager.getContentUri(path), current.getMimeType()) - .setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); - activity.startActivityForResult(intent, PicasaSource.isPicasaImage(current) - ? REQUEST_CROP_PICASA - : REQUEST_CROP); - return true; - } - case R.id.action_trim: { - Intent intent = new Intent(mActivity, TrimVideo.class); - intent.setData(manager.getContentUri(path)); - // We need the file path to wrap this into a RandomAccessFile. - intent.putExtra(KEY_MEDIA_ITEM_PATH, current.getFilePath()); - mActivity.startActivityForResult(intent, REQUEST_TRIM); - return true; - } - case R.id.action_mute: { - MuteVideo muteVideo = new MuteVideo(current.getFilePath(), - manager.getContentUri(path), mActivity); - muteVideo.muteInBackground(); - return true; - } - case R.id.action_edit: { - launchPhotoEditor(); - return true; - } - case R.id.action_simple_edit: { - launchSimpleEditor(); - return true; - } - case R.id.action_details: { - if (mShowDetails) { - hideDetails(); - } else { - showDetails(); - } - return true; - } - case R.id.action_delete: - confirmMsg = mActivity.getResources().getQuantityString( - R.plurals.delete_selection, 1); - case R.id.action_setas: - case R.id.action_rotate_ccw: - case R.id.action_rotate_cw: - case R.id.action_show_on_map: - mSelectionManager.deSelectAll(); - mSelectionManager.toggle(path); - mMenuExecutor.onMenuClicked(item, confirmMsg, mConfirmDialogListener); - return true; - default : - return false; - } - } - - private void hideDetails() { - mShowDetails = false; - mDetailsHelper.hide(); - } - - private void showDetails() { - mShowDetails = true; - if (mDetailsHelper == null) { - mDetailsHelper = new DetailsHelper(mActivity, mRootPane, new MyDetailsSource()); - mDetailsHelper.setCloseListener(new CloseListener() { - @Override - public void onClose() { - hideDetails(); - } - }); - } - mDetailsHelper.show(); - } - - //////////////////////////////////////////////////////////////////////////// - // Callbacks from PhotoView - //////////////////////////////////////////////////////////////////////////// - @Override - public void onSingleTapUp(int x, int y) { - if (mAppBridge != null) { - if (mAppBridge.onSingleTapUp(x, y)) return; - } - - MediaItem item = mModel.getMediaItem(0); - if (item == null || item == mScreenNailItem) { - // item is not ready or it is camera preview, ignore - return; - } - - int supported = item.getSupportedOperations(); - boolean playVideo = ((supported & MediaItem.SUPPORT_PLAY) != 0); - boolean unlock = ((supported & MediaItem.SUPPORT_UNLOCK) != 0); - boolean goBack = ((supported & MediaItem.SUPPORT_BACK) != 0); - boolean launchCamera = ((supported & MediaItem.SUPPORT_CAMERA_SHORTCUT) != 0); - - if (playVideo) { - // determine if the point is at center (1/6) of the photo view. - // (The position of the "play" icon is at center (1/6) of the photo) - int w = mPhotoView.getWidth(); - int h = mPhotoView.getHeight(); - playVideo = (Math.abs(x - w / 2) * 12 <= w) - && (Math.abs(y - h / 2) * 12 <= h); - } - - if (playVideo) { - if (mSecureAlbum == null) { - playVideo(mActivity, item.getPlayUri(), item.getName()); - } else { - mActivity.getStateManager().finishState(this); - } - } else if (goBack) { - onBackPressed(); - } else if (unlock) { - Intent intent = new Intent(mActivity, Gallery.class); - intent.putExtra(Gallery.KEY_DISMISS_KEYGUARD, true); - mActivity.startActivity(intent); - } else if (launchCamera) { - launchCamera(); - } else { - toggleBars(); - } - } - - @Override - public void onActionBarAllowed(boolean allowed) { - mActionBarAllowed = allowed; - mHandler.sendEmptyMessage(MSG_UPDATE_ACTION_BAR); - } - - @Override - public void onActionBarWanted() { - mHandler.sendEmptyMessage(MSG_WANT_BARS); - } - - @Override - public void onFullScreenChanged(boolean full) { - Message m = mHandler.obtainMessage( - MSG_ON_FULL_SCREEN_CHANGED, full ? 1 : 0, 0); - m.sendToTarget(); - } - - // How we do delete/undo: - // - // When the user choose to delete a media item, we just tell the - // FilterDeleteSet to hide that item. If the user choose to undo it, we - // again tell FilterDeleteSet not to hide it. If the user choose to commit - // the deletion, we then actually delete the media item. - @Override - public void onDeleteImage(Path path, int offset) { - onCommitDeleteImage(); // commit the previous deletion - mDeletePath = path; - mDeleteIsFocus = (offset == 0); - mMediaSet.addDeletion(path, mCurrentIndex + offset); - } - - @Override - public void onUndoDeleteImage() { - if (mDeletePath == null) return; - // If the deletion was done on the focused item, we want the model to - // focus on it when it is undeleted. - if (mDeleteIsFocus) mModel.setFocusHintPath(mDeletePath); - mMediaSet.removeDeletion(mDeletePath); - mDeletePath = null; - } - - @Override - public void onCommitDeleteImage() { - if (mDeletePath == null) return; - mMenuExecutor.startSingleItemAction(R.id.action_delete, mDeletePath); - mDeletePath = null; - } - - public void playVideo(Activity activity, Uri uri, String title) { - try { - Intent intent = new Intent(Intent.ACTION_VIEW) - .setDataAndType(uri, "video/*") - .putExtra(Intent.EXTRA_TITLE, title) - .putExtra(MovieActivity.KEY_TREAT_UP_AS_BACK, true); - activity.startActivityForResult(intent, REQUEST_PLAY_VIDEO); - } catch (ActivityNotFoundException e) { - Toast.makeText(activity, activity.getString(R.string.video_err), - Toast.LENGTH_SHORT).show(); - } - } - - private void setCurrentPhotoByIntent(Intent intent) { - if (intent == null) return; - Path path = mApplication.getDataManager() - .findPathByUri(intent.getData(), intent.getType()); - if (path != null) { - Path albumPath = mApplication.getDataManager().getDefaultSetOf(path); - if (!albumPath.equalsIgnoreCase(mOriginalSetPathString)) { - // If the edited image is stored in a different album, we need - // to start a new activity state to show the new image - 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(SinglePhotoPage.class, data); - return; - } - mModel.setCurrentPhoto(path, mCurrentIndex); - } - } - - @Override - protected void onStateResult(int requestCode, int resultCode, Intent data) { - if (resultCode == Activity.RESULT_CANCELED) { - // This is a reset, not a canceled - return; - } - if (resultCode == ProxyLauncher.RESULT_USER_CANCELED) { - // Unmap reset vs. canceled - resultCode = Activity.RESULT_CANCELED; - } - mRecenterCameraOnResume = false; - switch (requestCode) { - case REQUEST_EDIT: - setCurrentPhotoByIntent(data); - break; - case REQUEST_CROP: - if (resultCode == Activity.RESULT_OK) { - setCurrentPhotoByIntent(data); - } - break; - case REQUEST_CROP_PICASA: { - if (resultCode == Activity.RESULT_OK) { - Context context = mActivity.getAndroidContext(); - String message = context.getString(R.string.crop_saved, - context.getString(R.string.folder_edited_online_photos)); - Toast.makeText(context, message, Toast.LENGTH_SHORT).show(); - } - break; - } - case REQUEST_SLIDESHOW: { - if (data == null) break; - String path = data.getStringExtra(SlideshowPage.KEY_ITEM_PATH); - int index = data.getIntExtra(SlideshowPage.KEY_PHOTO_INDEX, 0); - if (path != null) { - mModel.setCurrentPhoto(Path.fromString(path), index); - } - } - } - } - - @Override - public void onPause() { - super.onPause(); - mIsActive = false; - - mActivity.getGLRoot().unfreeze(); - mHandler.removeMessages(MSG_UNFREEZE_GLROOT); - - DetailsHelper.pause(); - // Hide the detail dialog on exit - if (mShowDetails) hideDetails(); - if (mModel != null) { - mModel.pause(); - } - mPhotoView.pause(); - mHandler.removeMessages(MSG_HIDE_BARS); - mHandler.removeMessages(MSG_REFRESH_BOTTOM_CONTROLS); - refreshBottomControlsWhenReady(); - mActionBar.removeOnMenuVisibilityListener(mMenuVisibilityListener); - if (mShowSpinner) { - mActionBar.disableAlbumModeMenu(true); - } - onCommitDeleteImage(); - mMenuExecutor.pause(); - if (mMediaSet != null) mMediaSet.clearDeletion(); - } - - @Override - public void onCurrentImageUpdated() { - mActivity.getGLRoot().unfreeze(); - } - - @Override - public void onFilmModeChanged(boolean enabled) { - refreshBottomControlsWhenReady(); - if (mShowSpinner) { - if (enabled) { - mActionBar.enableAlbumModeMenu( - GalleryActionBar.ALBUM_FILMSTRIP_MODE_SELECTED, this); - } else { - mActionBar.disableAlbumModeMenu(true); - } - } - if (enabled) { - mHandler.removeMessages(MSG_HIDE_BARS); - UsageStatistics.onContentViewChanged( - UsageStatistics.COMPONENT_GALLERY, "FilmstripPage"); - } else { - refreshHidingMessage(); - if (mAppBridge == null || mCurrentIndex > 0) { - UsageStatistics.onContentViewChanged( - UsageStatistics.COMPONENT_GALLERY, "SinglePhotoPage"); - } else { - UsageStatistics.onContentViewChanged( - UsageStatistics.COMPONENT_CAMERA, "Unknown"); // TODO - } - } - } - - private void transitionFromAlbumPageIfNeeded() { - TransitionStore transitions = mActivity.getTransitionStore(); - - int albumPageTransition = transitions.get( - KEY_ALBUMPAGE_TRANSITION, MSG_ALBUMPAGE_NONE); - - if (albumPageTransition == MSG_ALBUMPAGE_NONE && mAppBridge != null - && mRecenterCameraOnResume) { - // Generally, resuming the PhotoPage when in Camera should - // reset to the capture mode to allow quick photo taking - mCurrentIndex = 0; - mPhotoView.resetToFirstPicture(); - } else { - int resumeIndex = transitions.get(KEY_INDEX_HINT, -1); - if (resumeIndex >= 0) { - if (mHasCameraScreennailOrPlaceholder) { - // Account for preview/placeholder being the first item - resumeIndex++; - } - if (resumeIndex < mMediaSet.getMediaItemCount()) { - mCurrentIndex = resumeIndex; - mModel.moveTo(mCurrentIndex); - } - } - } - - if (albumPageTransition == MSG_ALBUMPAGE_RESUMED) { - mPhotoView.setFilmMode(mStartInFilmstrip || mAppBridge != null); - } else if (albumPageTransition == MSG_ALBUMPAGE_PICKED) { - mPhotoView.setFilmMode(false); - } - } - - @Override - protected void onResume() { - super.onResume(); - - if (mModel == null) { - mActivity.getStateManager().finishState(this); - return; - } - transitionFromAlbumPageIfNeeded(); - - mActivity.getGLRoot().freeze(); - mIsActive = true; - setContentPane(mRootPane); - - mModel.resume(); - mPhotoView.resume(); - mActionBar.setDisplayOptions( - ((mSecureAlbum == null) && (mSetPathString != null)), false); - mActionBar.addOnMenuVisibilityListener(mMenuVisibilityListener); - refreshBottomControlsWhenReady(); - if (mShowSpinner && mPhotoView.getFilmMode()) { - mActionBar.enableAlbumModeMenu( - GalleryActionBar.ALBUM_FILMSTRIP_MODE_SELECTED, this); - } - if (!mShowBars) { - mActionBar.hide(); - mActivity.getGLRoot().setLightsOutMode(true); - } - boolean haveImageEditor = GalleryUtils.isEditorAvailable(mActivity, "image/*"); - if (haveImageEditor != mHaveImageEditor) { - mHaveImageEditor = haveImageEditor; - updateMenuOperations(); - } - - mRecenterCameraOnResume = true; - mHandler.sendEmptyMessageDelayed(MSG_UNFREEZE_GLROOT, UNFREEZE_GLROOT_TIMEOUT); - } - - @Override - protected void onDestroy() { - if (mAppBridge != null) { - mAppBridge.setServer(null); - mScreenNailItem.setScreenNail(null); - mAppBridge.detachScreenNail(); - mAppBridge = null; - mScreenNailSet = null; - mScreenNailItem = null; - } - mActivity.getGLRoot().setOrientationSource(null); - if (mBottomControls != null) mBottomControls.cleanup(); - - // Remove all pending messages. - mHandler.removeCallbacksAndMessages(null); - super.onDestroy(); - } - - private class MyDetailsSource implements DetailsSource { - - @Override - public MediaDetails getDetails() { - return mModel.getMediaItem(0).getDetails(); - } - - @Override - public int size() { - return mMediaSet != null ? mMediaSet.getMediaItemCount() : 1; - } - - @Override - public int setIndex() { - return mModel.getCurrentIndex(); - } - } - - @Override - public void onAlbumModeSelected(int mode) { - if (mode == GalleryActionBar.ALBUM_GRID_MODE_SELECTED) { - switchToGrid(); - } - } - - @Override - public void refreshBottomControlsWhenReady() { - if (mBottomControls == null) { - return; - } - MediaObject currentPhoto = mCurrentPhoto; - if (currentPhoto == null) { - mHandler.obtainMessage(MSG_REFRESH_BOTTOM_CONTROLS, 0, 0, currentPhoto).sendToTarget(); - } else { - currentPhoto.getPanoramaSupport(mRefreshBottomControlsCallback); - } - } - - private void updatePanoramaUI(boolean isPanorama360) { - Menu menu = mActionBar.getMenu(); - - // it could be null if onCreateActionBar has not been called yet - if (menu == null) { - return; - } - - MenuExecutor.updateMenuForPanorama(menu, isPanorama360, isPanorama360); - - if (isPanorama360) { - MenuItem item = menu.findItem(R.id.action_share); - if (item != null) { - item.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER); - item.setTitle(mActivity.getResources().getString(R.string.share_as_photo)); - } - } else if ((mCurrentPhoto.getSupportedOperations() & MediaObject.SUPPORT_SHARE) != 0) { - MenuItem item = menu.findItem(R.id.action_share); - if (item != null) { - item.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM); - item.setTitle(mActivity.getResources().getString(R.string.share)); - } - } - } - - @Override - public void onUndoBarVisibilityChanged(boolean visible) { - refreshBottomControlsWhenReady(); - } - - @Override - public boolean onShareTargetSelected(ShareActionProvider source, Intent intent) { - final long timestampMillis = mCurrentPhoto.getDateInMs(); - final String mediaType = getMediaTypeString(mCurrentPhoto); - UsageStatistics.onEvent(UsageStatistics.COMPONENT_GALLERY, - UsageStatistics.ACTION_SHARE, - mediaType, - timestampMillis > 0 - ? System.currentTimeMillis() - timestampMillis - : -1); - return false; - } - - private static String getMediaTypeString(MediaItem item) { - if (item.getMediaType() == MediaObject.MEDIA_TYPE_VIDEO) { - return "Video"; - } else if (item.getMediaType() == MediaObject.MEDIA_TYPE_IMAGE) { - return "Photo"; - } else { - return "Unknown:" + item.getMediaType(); - } - } - -} diff --git a/src/com/android/gallery3d/app/PhotoPageBottomControls.java b/src/com/android/gallery3d/app/PhotoPageBottomControls.java deleted file mode 100644 index 24b8ceb7e..000000000 --- a/src/com/android/gallery3d/app/PhotoPageBottomControls.java +++ /dev/null @@ -1,137 +0,0 @@ -/* - * 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.content.Context; -import android.view.LayoutInflater; -import android.view.View; -import android.view.View.OnClickListener; -import android.view.ViewGroup; -import android.view.animation.AlphaAnimation; -import android.view.animation.Animation; -import android.widget.RelativeLayout; - -import com.android.gallery3d.R; - -import java.util.HashMap; -import java.util.Map; - -public class PhotoPageBottomControls implements OnClickListener { - public interface Delegate { - public boolean canDisplayBottomControls(); - public boolean canDisplayBottomControl(int control); - public void onBottomControlClicked(int control); - public void refreshBottomControlsWhenReady(); - } - - private Delegate mDelegate; - private ViewGroup mParentLayout; - private ViewGroup mContainer; - - private boolean mContainerVisible = false; - private Map<View, Boolean> mControlsVisible = new HashMap<View, Boolean>(); - - private Animation mContainerAnimIn = new AlphaAnimation(0f, 1f); - private Animation mContainerAnimOut = new AlphaAnimation(1f, 0f); - private static final int CONTAINER_ANIM_DURATION_MS = 200; - - private static final int CONTROL_ANIM_DURATION_MS = 150; - private static Animation getControlAnimForVisibility(boolean visible) { - Animation anim = visible ? new AlphaAnimation(0f, 1f) - : new AlphaAnimation(1f, 0f); - anim.setDuration(CONTROL_ANIM_DURATION_MS); - return anim; - } - - public PhotoPageBottomControls(Delegate delegate, Context context, RelativeLayout layout) { - mDelegate = delegate; - mParentLayout = layout; - - LayoutInflater inflater = (LayoutInflater) context - .getSystemService(Context.LAYOUT_INFLATER_SERVICE); - mContainer = (ViewGroup) inflater - .inflate(R.layout.photopage_bottom_controls, mParentLayout, false); - mParentLayout.addView(mContainer); - - for (int i = mContainer.getChildCount() - 1; i >= 0; i--) { - View child = mContainer.getChildAt(i); - child.setOnClickListener(this); - mControlsVisible.put(child, false); - } - - mContainerAnimIn.setDuration(CONTAINER_ANIM_DURATION_MS); - mContainerAnimOut.setDuration(CONTAINER_ANIM_DURATION_MS); - - mDelegate.refreshBottomControlsWhenReady(); - } - - private void hide() { - mContainer.clearAnimation(); - mContainerAnimOut.reset(); - mContainer.startAnimation(mContainerAnimOut); - mContainer.setVisibility(View.INVISIBLE); - } - - private void show() { - mContainer.clearAnimation(); - mContainerAnimIn.reset(); - mContainer.startAnimation(mContainerAnimIn); - mContainer.setVisibility(View.VISIBLE); - } - - public void refresh() { - boolean visible = mDelegate.canDisplayBottomControls(); - boolean containerVisibilityChanged = (visible != mContainerVisible); - if (containerVisibilityChanged) { - if (visible) { - show(); - } else { - hide(); - } - mContainerVisible = visible; - } - if (!mContainerVisible) { - return; - } - for (View control : mControlsVisible.keySet()) { - Boolean prevVisibility = mControlsVisible.get(control); - boolean curVisibility = mDelegate.canDisplayBottomControl(control.getId()); - if (prevVisibility.booleanValue() != curVisibility) { - if (!containerVisibilityChanged) { - control.clearAnimation(); - control.startAnimation(getControlAnimForVisibility(curVisibility)); - } - control.setVisibility(curVisibility ? View.VISIBLE : View.INVISIBLE); - mControlsVisible.put(control, curVisibility); - } - } - // Force a layout change - mContainer.requestLayout(); // Kick framework to draw the control. - } - - public void cleanup() { - mParentLayout.removeView(mContainer); - mControlsVisible.clear(); - } - - @Override - public void onClick(View view) { - if (mContainerVisible && mControlsVisible.get(view).booleanValue()) { - mDelegate.onBottomControlClicked(view.getId()); - } - } -} diff --git a/src/com/android/gallery3d/app/PhotoPageProgressBar.java b/src/com/android/gallery3d/app/PhotoPageProgressBar.java deleted file mode 100644 index 141fea698..000000000 --- a/src/com/android/gallery3d/app/PhotoPageProgressBar.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * 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.content.Context; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.view.ViewGroup.LayoutParams; -import android.widget.RelativeLayout; - -import com.android.gallery3d.R; - -public class PhotoPageProgressBar { - private ViewGroup mContainer; - private View mProgress; - - public PhotoPageProgressBar(Context context, RelativeLayout parentLayout) { - LayoutInflater inflater = (LayoutInflater) context - .getSystemService(Context.LAYOUT_INFLATER_SERVICE); - mContainer = (ViewGroup) inflater.inflate(R.layout.photopage_progress_bar, parentLayout, - false); - parentLayout.addView(mContainer); - mProgress = mContainer.findViewById(R.id.photopage_progress_foreground); - } - - public void setProgress(int progressPercent) { - mContainer.setVisibility(View.VISIBLE); - LayoutParams layoutParams = mProgress.getLayoutParams(); - layoutParams.width = mContainer.getWidth() * progressPercent / 100; - mProgress.setLayoutParams(layoutParams); - } - - public void hideProgress() { - mContainer.setVisibility(View.INVISIBLE); - } -} diff --git a/src/com/android/gallery3d/app/PickerActivity.java b/src/com/android/gallery3d/app/PickerActivity.java deleted file mode 100644 index d5bb218ea..000000000 --- a/src/com/android/gallery3d/app/PickerActivity.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright (C) 2011 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.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.android.gallery3d.R; -import com.android.gallery3d.ui.GLRootView; - -public class PickerActivity extends AbstractGalleryActivity - implements OnClickListener { - - public static final String KEY_ALBUM_PATH = "album-path"; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - // We show the picker in two ways. One smaller screen we use a full - // screen window with an action bar. On larger screen we use a dialog. - boolean isDialog = getResources().getBoolean(R.bool.picker_is_dialog); - - if (!isDialog) { - requestWindowFeature(Window.FEATURE_ACTION_BAR); - requestWindowFeature(Window.FEATURE_ACTION_BAR_OVERLAY); - } - - setContentView(R.layout.dialog_picker); - - if (isDialog) { - // In dialog mode, we don't have the action bar to show the - // "cancel" action, so we show an additional "cancel" button. - View view = findViewById(R.id.cancel); - view.setOnClickListener(this); - view.setVisibility(View.VISIBLE); - - // We need this, otherwise the view will be dimmed because it - // is "behind" the dialog. - ((GLRootView) findViewById(R.id.gl_root_view)).setZOrderOnTop(true); - } - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - MenuInflater inflater = getMenuInflater(); - inflater.inflate(R.menu.pickup, menu); - return true; - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - if (item.getItemId() == R.id.action_cancel) { - finish(); - return true; - } - return super.onOptionsItemSelected(item); - } - - @Override - public void onClick(View v) { - if (v.getId() == R.id.cancel) finish(); - } -} diff --git a/src/com/android/gallery3d/app/SinglePhotoDataAdapter.java b/src/com/android/gallery3d/app/SinglePhotoDataAdapter.java deleted file mode 100644 index 00f2fe78f..000000000 --- a/src/com/android/gallery3d/app/SinglePhotoDataAdapter.java +++ /dev/null @@ -1,263 +0,0 @@ -/* - * Copyright (C) 2010 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.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.graphics.BitmapRegionDecoder; -import android.graphics.Rect; -import android.os.Handler; -import android.os.Message; - -import com.android.gallery3d.common.BitmapUtils; -import com.android.gallery3d.common.Utils; -import com.android.gallery3d.data.MediaItem; -import com.android.gallery3d.data.Path; -import com.android.gallery3d.ui.BitmapScreenNail; -import com.android.gallery3d.ui.PhotoView; -import com.android.gallery3d.ui.ScreenNail; -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.ThreadPool; - -public class SinglePhotoDataAdapter extends TileImageViewAdapter - implements PhotoPage.Model { - - private static final String TAG = "SinglePhotoDataAdapter"; - private static final int SIZE_BACKUP = 1024; - private static final int MSG_UPDATE_IMAGE = 1; - - private MediaItem mItem; - private boolean mHasFullImage; - private Future<?> mTask; - private Handler mHandler; - - private PhotoView mPhotoView; - private ThreadPool mThreadPool; - private int mLoadingState = LOADING_INIT; - private BitmapScreenNail mBitmapScreenNail; - - public SinglePhotoDataAdapter( - AbstractGalleryActivity activity, PhotoView view, MediaItem item) { - mItem = Utils.checkNotNull(item); - mHasFullImage = (item.getSupportedOperations() & - MediaItem.SUPPORT_FULL_IMAGE) != 0; - mPhotoView = Utils.checkNotNull(view); - mHandler = new SynchronizedHandler(activity.getGLRoot()) { - @Override - @SuppressWarnings("unchecked") - public void handleMessage(Message message) { - Utils.assertTrue(message.what == MSG_UPDATE_IMAGE); - if (mHasFullImage) { - onDecodeLargeComplete((ImageBundle) message.obj); - } else { - onDecodeThumbComplete((Future<Bitmap>) message.obj); - } - } - }; - mThreadPool = activity.getThreadPool(); - } - - private static class ImageBundle { - public final BitmapRegionDecoder decoder; - public final Bitmap backupImage; - - public ImageBundle(BitmapRegionDecoder decoder, Bitmap backupImage) { - this.decoder = decoder; - this.backupImage = backupImage; - } - } - - private FutureListener<BitmapRegionDecoder> mLargeListener = - new FutureListener<BitmapRegionDecoder>() { - @Override - public void onFutureDone(Future<BitmapRegionDecoder> future) { - BitmapRegionDecoder decoder = future.get(); - if (decoder == null) return; - int width = decoder.getWidth(); - int height = decoder.getHeight(); - BitmapFactory.Options options = new BitmapFactory.Options(); - options.inSampleSize = BitmapUtils.computeSampleSize( - (float) SIZE_BACKUP / Math.max(width, height)); - Bitmap bitmap = decoder.decodeRegion(new Rect(0, 0, width, height), options); - mHandler.sendMessage(mHandler.obtainMessage( - MSG_UPDATE_IMAGE, new ImageBundle(decoder, bitmap))); - } - }; - - private FutureListener<Bitmap> mThumbListener = - new FutureListener<Bitmap>() { - @Override - public void onFutureDone(Future<Bitmap> future) { - mHandler.sendMessage( - mHandler.obtainMessage(MSG_UPDATE_IMAGE, future)); - } - }; - - @Override - public boolean isEmpty() { - return false; - } - - private void setScreenNail(Bitmap bitmap, int width, int height) { - mBitmapScreenNail = new BitmapScreenNail(bitmap); - setScreenNail(mBitmapScreenNail, width, height); - } - - private void onDecodeLargeComplete(ImageBundle bundle) { - try { - setScreenNail(bundle.backupImage, - bundle.decoder.getWidth(), bundle.decoder.getHeight()); - setRegionDecoder(bundle.decoder); - mPhotoView.notifyImageChange(0); - } catch (Throwable t) { - Log.w(TAG, "fail to decode large", t); - } - } - - private void onDecodeThumbComplete(Future<Bitmap> future) { - try { - Bitmap backup = future.get(); - if (backup == null) { - mLoadingState = LOADING_FAIL; - return; - } else { - mLoadingState = LOADING_COMPLETE; - } - setScreenNail(backup, backup.getWidth(), backup.getHeight()); - mPhotoView.notifyImageChange(0); - } catch (Throwable t) { - Log.w(TAG, "fail to decode thumb", t); - } - } - - @Override - public void resume() { - if (mTask == null) { - if (mHasFullImage) { - mTask = mThreadPool.submit( - mItem.requestLargeImage(), mLargeListener); - } else { - mTask = mThreadPool.submit( - mItem.requestImage(MediaItem.TYPE_THUMBNAIL), - mThumbListener); - } - } - } - - @Override - public void pause() { - Future<?> task = mTask; - task.cancel(); - task.waitDone(); - if (task.get() == null) { - mTask = null; - } - if (mBitmapScreenNail != null) { - mBitmapScreenNail.recycle(); - mBitmapScreenNail = null; - } - } - - @Override - public void moveTo(int index) { - throw new UnsupportedOperationException(); - } - - @Override - public void getImageSize(int offset, PhotoView.Size size) { - if (offset == 0) { - size.width = mItem.getWidth(); - size.height = mItem.getHeight(); - } else { - size.width = 0; - size.height = 0; - } - } - - @Override - public int getImageRotation(int offset) { - return (offset == 0) ? mItem.getFullImageRotation() : 0; - } - - @Override - public ScreenNail getScreenNail(int offset) { - return (offset == 0) ? getScreenNail() : null; - } - - @Override - public void setNeedFullImage(boolean enabled) { - // currently not necessary. - } - - @Override - public boolean isCamera(int offset) { - return false; - } - - @Override - public boolean isPanorama(int offset) { - return false; - } - - @Override - public boolean isStaticCamera(int offset) { - return false; - } - - @Override - public boolean isVideo(int offset) { - return mItem.getMediaType() == MediaItem.MEDIA_TYPE_VIDEO; - } - - @Override - public boolean isDeletable(int offset) { - return (mItem.getSupportedOperations() & MediaItem.SUPPORT_DELETE) != 0; - } - - @Override - public MediaItem getMediaItem(int offset) { - return offset == 0 ? mItem : null; - } - - @Override - public int getCurrentIndex() { - return 0; - } - - @Override - public void setCurrentPhoto(Path path, int indexHint) { - // ignore - } - - @Override - public void setFocusHintDirection(int direction) { - // ignore - } - - @Override - public void setFocusHintPath(Path path) { - // ignore - } - - @Override - public int getLoadingState(int offset) { - return mLoadingState; - } -} diff --git a/src/com/android/gallery3d/app/SinglePhotoPage.java b/src/com/android/gallery3d/app/SinglePhotoPage.java deleted file mode 100644 index beb87d358..000000000 --- a/src/com/android/gallery3d/app/SinglePhotoPage.java +++ /dev/null @@ -1,21 +0,0 @@ -/* - * 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/SlideshowDataAdapter.java b/src/com/android/gallery3d/app/SlideshowDataAdapter.java deleted file mode 100644 index 7a0fba5fb..000000000 --- a/src/com/android/gallery3d/app/SlideshowDataAdapter.java +++ /dev/null @@ -1,204 +0,0 @@ -/* - * Copyright (C) 2010 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.graphics.Bitmap; - -import com.android.gallery3d.app.SlideshowPage.Slide; -import com.android.gallery3d.data.ContentListener; -import com.android.gallery3d.data.MediaItem; -import com.android.gallery3d.data.MediaObject; -import com.android.gallery3d.data.Path; -import com.android.gallery3d.util.Future; -import com.android.gallery3d.util.FutureListener; -import com.android.gallery3d.util.ThreadPool; -import com.android.gallery3d.util.ThreadPool.Job; -import com.android.gallery3d.util.ThreadPool.JobContext; - -import java.util.LinkedList; -import java.util.concurrent.atomic.AtomicBoolean; - -public class SlideshowDataAdapter implements SlideshowPage.Model { - @SuppressWarnings("unused") - private static final String TAG = "SlideshowDataAdapter"; - - private static final int IMAGE_QUEUE_CAPACITY = 3; - - public interface SlideshowSource { - public void addContentListener(ContentListener listener); - public void removeContentListener(ContentListener listener); - public long reload(); - public MediaItem getMediaItem(int index); - public int findItemIndex(Path path, int hint); - } - - private final SlideshowSource mSource; - - private int mLoadIndex = 0; - private int mNextOutput = 0; - private boolean mIsActive = false; - private boolean mNeedReset; - private boolean mDataReady; - private Path mInitialPath; - - private final LinkedList<Slide> mImageQueue = new LinkedList<Slide>(); - - private Future<Void> mReloadTask; - private final ThreadPool mThreadPool; - - private long mDataVersion = MediaObject.INVALID_DATA_VERSION; - private final AtomicBoolean mNeedReload = new AtomicBoolean(false); - private final SourceListener mSourceListener = new SourceListener(); - - // The index is just a hint if initialPath is set - public SlideshowDataAdapter(GalleryContext context, SlideshowSource source, int index, - Path initialPath) { - mSource = source; - mInitialPath = initialPath; - mLoadIndex = index; - mNextOutput = index; - mThreadPool = context.getThreadPool(); - } - - private MediaItem loadItem() { - if (mNeedReload.compareAndSet(true, false)) { - long v = mSource.reload(); - if (v != mDataVersion) { - mDataVersion = v; - mNeedReset = true; - return null; - } - } - int index = mLoadIndex; - if (mInitialPath != null) { - index = mSource.findItemIndex(mInitialPath, index); - mInitialPath = null; - } - return mSource.getMediaItem(index); - } - - private class ReloadTask implements Job<Void> { - @Override - public Void run(JobContext jc) { - while (true) { - synchronized (SlideshowDataAdapter.this) { - while (mIsActive && (!mDataReady - || mImageQueue.size() >= IMAGE_QUEUE_CAPACITY)) { - try { - SlideshowDataAdapter.this.wait(); - } catch (InterruptedException ex) { - // ignored. - } - continue; - } - } - if (!mIsActive) return null; - mNeedReset = false; - - MediaItem item = loadItem(); - - if (mNeedReset) { - synchronized (SlideshowDataAdapter.this) { - mImageQueue.clear(); - mLoadIndex = mNextOutput; - } - continue; - } - - if (item == null) { - synchronized (SlideshowDataAdapter.this) { - if (!mNeedReload.get()) mDataReady = false; - SlideshowDataAdapter.this.notifyAll(); - } - continue; - } - - Bitmap bitmap = item - .requestImage(MediaItem.TYPE_THUMBNAIL) - .run(jc); - - if (bitmap != null) { - synchronized (SlideshowDataAdapter.this) { - mImageQueue.addLast( - new Slide(item, mLoadIndex, bitmap)); - if (mImageQueue.size() == 1) { - SlideshowDataAdapter.this.notifyAll(); - } - } - } - ++mLoadIndex; - } - } - } - - private class SourceListener implements ContentListener { - @Override - public void onContentDirty() { - synchronized (SlideshowDataAdapter.this) { - mNeedReload.set(true); - mDataReady = true; - SlideshowDataAdapter.this.notifyAll(); - } - } - } - - private synchronized Slide innerNextBitmap() { - while (mIsActive && mDataReady && mImageQueue.isEmpty()) { - try { - wait(); - } catch (InterruptedException t) { - throw new AssertionError(); - } - } - if (mImageQueue.isEmpty()) return null; - mNextOutput++; - this.notifyAll(); - return mImageQueue.removeFirst(); - } - - @Override - public Future<Slide> nextSlide(FutureListener<Slide> listener) { - return mThreadPool.submit(new Job<Slide>() { - @Override - public Slide run(JobContext jc) { - jc.setMode(ThreadPool.MODE_NONE); - return innerNextBitmap(); - } - }, listener); - } - - @Override - public void pause() { - synchronized (this) { - mIsActive = false; - notifyAll(); - } - mSource.removeContentListener(mSourceListener); - mReloadTask.cancel(); - mReloadTask.waitDone(); - mReloadTask = null; - } - - @Override - public synchronized void resume() { - mIsActive = true; - mSource.addContentListener(mSourceListener); - mNeedReload.set(true); - mDataReady = true; - mReloadTask = mThreadPool.submit(new ReloadTask()); - } -} diff --git a/src/com/android/gallery3d/app/SlideshowPage.java b/src/com/android/gallery3d/app/SlideshowPage.java deleted file mode 100644 index 174058dc8..000000000 --- a/src/com/android/gallery3d/app/SlideshowPage.java +++ /dev/null @@ -1,366 +0,0 @@ -/* - * Copyright (C) 2010 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.content.Intent; -import android.graphics.Bitmap; -import android.os.Bundle; -import android.os.Handler; -import android.os.Message; -import android.view.MotionEvent; - -import com.android.gallery3d.R; -import com.android.gallery3d.common.Utils; -import com.android.gallery3d.data.ContentListener; -import com.android.gallery3d.data.MediaItem; -import com.android.gallery3d.data.MediaObject; -import com.android.gallery3d.data.MediaSet; -import com.android.gallery3d.data.Path; -import com.android.gallery3d.glrenderer.GLCanvas; -import com.android.gallery3d.ui.GLView; -import com.android.gallery3d.ui.SlideshowView; -import com.android.gallery3d.ui.SynchronizedHandler; -import com.android.gallery3d.util.Future; -import com.android.gallery3d.util.FutureListener; - -import java.util.ArrayList; -import java.util.Random; - -public class SlideshowPage extends ActivityState { - private static final String TAG = "SlideshowPage"; - - public static final String KEY_SET_PATH = "media-set-path"; - public static final String KEY_ITEM_PATH = "media-item-path"; - public static final String KEY_PHOTO_INDEX = "photo-index"; - public static final String KEY_RANDOM_ORDER = "random-order"; - public static final String KEY_REPEAT = "repeat"; - public static final String KEY_DREAM = "dream"; - - private static final long SLIDESHOW_DELAY = 3000; // 3 seconds - - private static final int MSG_LOAD_NEXT_BITMAP = 1; - private static final int MSG_SHOW_PENDING_BITMAP = 2; - - public static interface Model { - public void pause(); - - public void resume(); - - public Future<Slide> nextSlide(FutureListener<Slide> listener); - } - - public static class Slide { - public Bitmap bitmap; - public MediaItem item; - public int index; - - public Slide(MediaItem item, int index, Bitmap bitmap) { - this.bitmap = bitmap; - this.item = item; - this.index = index; - } - } - - private Handler mHandler; - private Model mModel; - private SlideshowView mSlideshowView; - - private Slide mPendingSlide = null; - private boolean mIsActive = false; - private final Intent mResultIntent = new Intent(); - - @Override - protected int getBackgroundColorId() { - return R.color.slideshow_background; - } - - private final GLView mRootPane = new GLView() { - @Override - protected void onLayout(boolean changed, int left, int top, int right, int bottom) { - mSlideshowView.layout(0, 0, right - left, bottom - top); - } - - @Override - protected boolean onTouch(MotionEvent event) { - if (event.getAction() == MotionEvent.ACTION_UP) { - onBackPressed(); - } - return true; - } - - @Override - protected void renderBackground(GLCanvas canvas) { - canvas.clearBuffer(getBackgroundColor()); - } - }; - - @Override - public void onCreate(Bundle data, Bundle restoreState) { - super.onCreate(data, restoreState); - mFlags |= (FLAG_HIDE_ACTION_BAR | FLAG_HIDE_STATUS_BAR); - if (data.getBoolean(KEY_DREAM)) { - // Dream screensaver only keeps screen on for plugged devices. - mFlags |= FLAG_SCREEN_ON_WHEN_PLUGGED | FLAG_SHOW_WHEN_LOCKED; - } else { - // User-initiated slideshow would always keep screen on. - mFlags |= FLAG_SCREEN_ON_ALWAYS; - } - - mHandler = new SynchronizedHandler(mActivity.getGLRoot()) { - @Override - public void handleMessage(Message message) { - switch (message.what) { - case MSG_SHOW_PENDING_BITMAP: - showPendingBitmap(); - break; - case MSG_LOAD_NEXT_BITMAP: - loadNextBitmap(); - break; - default: throw new AssertionError(); - } - } - }; - initializeViews(); - initializeData(data); - } - - private void loadNextBitmap() { - mModel.nextSlide(new FutureListener<Slide>() { - @Override - public void onFutureDone(Future<Slide> future) { - mPendingSlide = future.get(); - mHandler.sendEmptyMessage(MSG_SHOW_PENDING_BITMAP); - } - }); - } - - private void showPendingBitmap() { - // mPendingBitmap could be null, if - // 1.) there is no more items - // 2.) mModel is paused - Slide slide = mPendingSlide; - if (slide == null) { - if (mIsActive) { - mActivity.getStateManager().finishState(SlideshowPage.this); - } - return; - } - - mSlideshowView.next(slide.bitmap, slide.item.getRotation()); - - setStateResult(Activity.RESULT_OK, mResultIntent - .putExtra(KEY_ITEM_PATH, slide.item.getPath().toString()) - .putExtra(KEY_PHOTO_INDEX, slide.index)); - mHandler.sendEmptyMessageDelayed(MSG_LOAD_NEXT_BITMAP, SLIDESHOW_DELAY); - } - - @Override - public void onPause() { - super.onPause(); - mIsActive = false; - mModel.pause(); - mSlideshowView.release(); - - mHandler.removeMessages(MSG_LOAD_NEXT_BITMAP); - mHandler.removeMessages(MSG_SHOW_PENDING_BITMAP); - } - - @Override - public void onResume() { - super.onResume(); - mIsActive = true; - mModel.resume(); - - if (mPendingSlide != null) { - showPendingBitmap(); - } else { - loadNextBitmap(); - } - } - - private void initializeData(Bundle data) { - boolean random = data.getBoolean(KEY_RANDOM_ORDER, false); - - // We only want to show slideshow for images only, not videos. - String mediaPath = data.getString(KEY_SET_PATH); - mediaPath = FilterUtils.newFilterPath(mediaPath, FilterUtils.FILTER_IMAGE_ONLY); - MediaSet mediaSet = mActivity.getDataManager().getMediaSet(mediaPath); - - if (random) { - boolean repeat = data.getBoolean(KEY_REPEAT); - mModel = new SlideshowDataAdapter(mActivity, - new ShuffleSource(mediaSet, repeat), 0, null); - setStateResult(Activity.RESULT_OK, mResultIntent.putExtra(KEY_PHOTO_INDEX, 0)); - } else { - int index = data.getInt(KEY_PHOTO_INDEX); - String itemPath = data.getString(KEY_ITEM_PATH); - Path path = itemPath != null ? Path.fromString(itemPath) : null; - boolean repeat = data.getBoolean(KEY_REPEAT); - mModel = new SlideshowDataAdapter(mActivity, new SequentialSource(mediaSet, repeat), - index, path); - setStateResult(Activity.RESULT_OK, mResultIntent.putExtra(KEY_PHOTO_INDEX, index)); - } - } - - private void initializeViews() { - mSlideshowView = new SlideshowView(); - mRootPane.addComponent(mSlideshowView); - setContentPane(mRootPane); - } - - private static MediaItem findMediaItem(MediaSet mediaSet, int index) { - for (int i = 0, n = mediaSet.getSubMediaSetCount(); i < n; ++i) { - MediaSet subset = mediaSet.getSubMediaSet(i); - int count = subset.getTotalMediaItemCount(); - if (index < count) { - return findMediaItem(subset, index); - } - index -= count; - } - ArrayList<MediaItem> list = mediaSet.getMediaItem(index, 1); - return list.isEmpty() ? null : list.get(0); - } - - private static class ShuffleSource implements SlideshowDataAdapter.SlideshowSource { - private static final int RETRY_COUNT = 5; - private final MediaSet mMediaSet; - private final Random mRandom = new Random(); - private int mOrder[] = new int[0]; - private final boolean mRepeat; - private long mSourceVersion = MediaSet.INVALID_DATA_VERSION; - private int mLastIndex = -1; - - public ShuffleSource(MediaSet mediaSet, boolean repeat) { - mMediaSet = Utils.checkNotNull(mediaSet); - mRepeat = repeat; - } - - @Override - public int findItemIndex(Path path, int hint) { - return hint; - } - - @Override - public MediaItem getMediaItem(int index) { - if (!mRepeat && index >= mOrder.length) return null; - if (mOrder.length == 0) return null; - mLastIndex = mOrder[index % mOrder.length]; - MediaItem item = findMediaItem(mMediaSet, mLastIndex); - for (int i = 0; i < RETRY_COUNT && item == null; ++i) { - Log.w(TAG, "fail to find image: " + mLastIndex); - mLastIndex = mRandom.nextInt(mOrder.length); - item = findMediaItem(mMediaSet, mLastIndex); - } - return item; - } - - @Override - public long reload() { - long version = mMediaSet.reload(); - if (version != mSourceVersion) { - mSourceVersion = version; - int count = mMediaSet.getTotalMediaItemCount(); - if (count != mOrder.length) generateOrderArray(count); - } - return version; - } - - private void generateOrderArray(int totalCount) { - if (mOrder.length != totalCount) { - mOrder = new int[totalCount]; - for (int i = 0; i < totalCount; ++i) { - mOrder[i] = i; - } - } - for (int i = totalCount - 1; i > 0; --i) { - Utils.swap(mOrder, i, mRandom.nextInt(i + 1)); - } - if (mOrder[0] == mLastIndex && totalCount > 1) { - Utils.swap(mOrder, 0, mRandom.nextInt(totalCount - 1) + 1); - } - } - - @Override - public void addContentListener(ContentListener listener) { - mMediaSet.addContentListener(listener); - } - - @Override - public void removeContentListener(ContentListener listener) { - mMediaSet.removeContentListener(listener); - } - } - - private static class SequentialSource implements SlideshowDataAdapter.SlideshowSource { - private static final int DATA_SIZE = 32; - - private ArrayList<MediaItem> mData = new ArrayList<MediaItem>(); - private int mDataStart = 0; - private long mDataVersion = MediaObject.INVALID_DATA_VERSION; - private final MediaSet mMediaSet; - private final boolean mRepeat; - - public SequentialSource(MediaSet mediaSet, boolean repeat) { - mMediaSet = mediaSet; - mRepeat = repeat; - } - - @Override - public int findItemIndex(Path path, int hint) { - return mMediaSet.getIndexOfItem(path, hint); - } - - @Override - public MediaItem getMediaItem(int index) { - int dataEnd = mDataStart + mData.size(); - - if (mRepeat) { - int count = mMediaSet.getMediaItemCount(); - if (count == 0) return null; - index = index % count; - } - if (index < mDataStart || index >= dataEnd) { - mData = mMediaSet.getMediaItem(index, DATA_SIZE); - mDataStart = index; - dataEnd = index + mData.size(); - } - - return (index < mDataStart || index >= dataEnd) ? null : mData.get(index - mDataStart); - } - - @Override - public long reload() { - long version = mMediaSet.reload(); - if (version != mDataVersion) { - mDataVersion = version; - mData.clear(); - } - return mDataVersion; - } - - @Override - public void addContentListener(ContentListener listener) { - mMediaSet.addContentListener(listener); - } - - @Override - public void removeContentListener(ContentListener listener) { - mMediaSet.removeContentListener(listener); - } - } -} diff --git a/src/com/android/gallery3d/app/StateManager.java b/src/com/android/gallery3d/app/StateManager.java deleted file mode 100644 index 53c3fc228..000000000 --- a/src/com/android/gallery3d/app/StateManager.java +++ /dev/null @@ -1,339 +0,0 @@ -/* - * Copyright (C) 2010 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.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.camera.CameraActivity; -import com.android.gallery3d.anim.StateTransitionAnimation; -import com.android.gallery3d.common.Utils; -import com.android.gallery3d.util.UsageStatistics; - -import java.util.Stack; - -public class StateManager { - @SuppressWarnings("unused") - private static final String TAG = "StateManager"; - private boolean mIsResumed = false; - - private static final String KEY_MAIN = "activity-state"; - private static final String KEY_DATA = "data"; - private static final String KEY_STATE = "bundle"; - private static final String KEY_CLASS = "class"; - - private AbstractGalleryActivity mActivity; - private Stack<StateEntry> mStack = new Stack<StateEntry>(); - private ActivityState.ResultEntry mResult; - - public StateManager(AbstractGalleryActivity activity) { - mActivity = activity; - } - - public void startState(Class<? extends ActivityState> klass, - Bundle data) { - Log.v(TAG, "startState " + klass); - ActivityState state = null; - try { - state = klass.newInstance(); - } catch (Exception e) { - throw new AssertionError(e); - } - if (!mStack.isEmpty()) { - ActivityState top = getTopState(); - top.transitionOnNextPause(top.getClass(), klass, - StateTransitionAnimation.Transition.Incoming); - if (mIsResumed) top.onPause(); - } - - UsageStatistics.onContentViewChanged( - UsageStatistics.COMPONENT_GALLERY, - klass.getSimpleName()); - state.initialize(mActivity, data); - - mStack.push(new StateEntry(data, state)); - state.onCreate(data, null); - if (mIsResumed) state.resume(); - } - - public void startStateForResult(Class<? extends ActivityState> klass, - int requestCode, Bundle data) { - Log.v(TAG, "startStateForResult " + klass + ", " + requestCode); - ActivityState state = null; - try { - state = klass.newInstance(); - } catch (Exception e) { - throw new AssertionError(e); - } - state.initialize(mActivity, data); - state.mResult = new ActivityState.ResultEntry(); - state.mResult.requestCode = requestCode; - - if (!mStack.isEmpty()) { - ActivityState as = getTopState(); - as.transitionOnNextPause(as.getClass(), klass, - StateTransitionAnimation.Transition.Incoming); - as.mReceivedResults = state.mResult; - if (mIsResumed) as.onPause(); - } else { - mResult = state.mResult; - } - UsageStatistics.onContentViewChanged(UsageStatistics.COMPONENT_GALLERY, - klass.getSimpleName()); - mStack.push(new StateEntry(data, state)); - state.onCreate(data, null); - if (mIsResumed) state.resume(); - } - - public boolean createOptionsMenu(Menu menu) { - if (mStack.isEmpty()) { - return false; - } else { - return getTopState().onCreateActionBar(menu); - } - } - - public void onConfigurationChange(Configuration config) { - for (StateEntry entry : mStack) { - entry.activityState.onConfigurationChanged(config); - } - } - - public void resume() { - if (mIsResumed) return; - mIsResumed = true; - if (!mStack.isEmpty()) getTopState().resume(); - } - - public void pause() { - if (!mIsResumed) return; - mIsResumed = false; - if (!mStack.isEmpty()) getTopState().onPause(); - } - - public void notifyActivityResult(int requestCode, int resultCode, Intent data) { - getTopState().onStateResult(requestCode, resultCode, data); - } - - public void clearActivityResult() { - if (!mStack.isEmpty()) { - getTopState().clearStateResult(); - } - } - - public int getStateCount() { - return mStack.size(); - } - - public boolean itemSelected(MenuItem item) { - if (!mStack.isEmpty()) { - if (getTopState().onItemSelected(item)) return true; - if (item.getItemId() == android.R.id.home) { - if (mStack.size() > 1) { - getTopState().onBackPressed(); - } - return true; - } - } - return false; - } - - public void onBackPressed() { - if (!mStack.isEmpty()) { - getTopState().onBackPressed(); - } - } - - void finishState(ActivityState state) { - finishState(state, true); - } - - public void clearTasks() { - // Remove all the states that are on top of the bottom PhotoPage state - while (mStack.size() > 1) { - mStack.pop().activityState.onDestroy(); - } - } - - void finishState(ActivityState state, boolean fireOnPause) { - // The finish() request could be rejected (only happens under Monkey), - // If it is rejected, we won't close the last page. - if (mStack.size() == 1) { - Activity activity = (Activity) mActivity.getAndroidContext(); - if (mResult != null) { - activity.setResult(mResult.resultCode, mResult.resultData); - } - activity.finish(); - if (!activity.isFinishing()) { - Log.w(TAG, "finish is rejected, keep the last state"); - return; - } - Log.v(TAG, "no more state, finish activity"); - } - - Log.v(TAG, "finishState " + state); - if (state != mStack.peek().activityState) { - if (state.isDestroyed()) { - Log.d(TAG, "The state is already destroyed"); - return; - } else { - throw new IllegalArgumentException("The stateview to be finished" - + " is not at the top of the stack: " + state + ", " - + mStack.peek().activityState); - } - } - - // Remove the top state. - mStack.pop(); - state.mIsFinishing = true; - ActivityState top = !mStack.isEmpty() ? mStack.peek().activityState : null; - if (mIsResumed && fireOnPause) { - if (top != null) { - state.transitionOnNextPause(state.getClass(), top.getClass(), - StateTransitionAnimation.Transition.Outgoing); - } - state.onPause(); - } - mActivity.getGLRoot().setContentPane(null); - state.onDestroy(); - - if (top != null && mIsResumed) top.resume(); - if (top != null) { - UsageStatistics.onContentViewChanged(UsageStatistics.COMPONENT_GALLERY, - top.getClass().getSimpleName()); - } - } - - public void switchState(ActivityState oldState, - Class<? extends ActivityState> klass, Bundle data) { - Log.v(TAG, "switchState " + oldState + ", " + klass); - if (oldState != mStack.peek().activityState) { - throw new IllegalArgumentException("The stateview to be finished" - + " is not at the top of the stack: " + oldState + ", " - + mStack.peek().activityState); - } - // Remove the top state. - mStack.pop(); - if (!data.containsKey(PhotoPage.KEY_APP_BRIDGE)) { - // Do not do the fade out stuff when we are switching camera modes - oldState.transitionOnNextPause(oldState.getClass(), klass, - StateTransitionAnimation.Transition.Incoming); - } - if (mIsResumed) oldState.onPause(); - oldState.onDestroy(); - - // Create new state. - ActivityState state = null; - try { - state = klass.newInstance(); - } catch (Exception e) { - throw new AssertionError(e); - } - state.initialize(mActivity, data); - mStack.push(new StateEntry(data, state)); - state.onCreate(data, null); - if (mIsResumed) state.resume(); - UsageStatistics.onContentViewChanged(UsageStatistics.COMPONENT_GALLERY, - klass.getSimpleName()); - } - - public void destroy() { - Log.v(TAG, "destroy"); - while (!mStack.isEmpty()) { - mStack.pop().activityState.onDestroy(); - } - mStack.clear(); - } - - @SuppressWarnings("unchecked") - public void restoreFromState(Bundle inState) { - Log.v(TAG, "restoreFromState"); - Parcelable list[] = inState.getParcelableArray(KEY_MAIN); - ActivityState topState = null; - for (Parcelable parcelable : list) { - Bundle bundle = (Bundle) parcelable; - Class<? extends ActivityState> klass = - (Class<? extends ActivityState>) bundle.getSerializable(KEY_CLASS); - - Bundle data = bundle.getBundle(KEY_DATA); - Bundle state = bundle.getBundle(KEY_STATE); - - ActivityState activityState; - try { - Log.v(TAG, "restoreFromState " + klass); - activityState = klass.newInstance(); - } catch (Exception e) { - throw new AssertionError(e); - } - activityState.initialize(mActivity, data); - activityState.onCreate(data, state); - mStack.push(new StateEntry(data, activityState)); - topState = activityState; - } - if (topState != null) { - UsageStatistics.onContentViewChanged(UsageStatistics.COMPONENT_GALLERY, - topState.getClass().getSimpleName()); - } - } - - public void saveState(Bundle outState) { - Log.v(TAG, "saveState"); - - Parcelable list[] = new Parcelable[mStack.size()]; - int i = 0; - for (StateEntry entry : mStack) { - Bundle bundle = new Bundle(); - bundle.putSerializable(KEY_CLASS, entry.activityState.getClass()); - bundle.putBundle(KEY_DATA, entry.data); - Bundle state = new Bundle(); - entry.activityState.onSaveState(state); - bundle.putBundle(KEY_STATE, state); - Log.v(TAG, "saveState " + entry.activityState.getClass()); - list[i++] = bundle; - } - outState.putParcelableArray(KEY_MAIN, list); - } - - public boolean hasStateClass(Class<? extends ActivityState> klass) { - for (StateEntry entry : mStack) { - if (klass.isInstance(entry.activityState)) { - return true; - } - } - return false; - } - - public ActivityState getTopState() { - Utils.assertTrue(!mStack.isEmpty()); - return mStack.peek().activityState; - } - - private static class StateEntry { - public Bundle data; - public ActivityState activityState; - - public StateEntry(Bundle data, ActivityState state) { - this.data = data; - this.activityState = state; - } - } -} diff --git a/src/com/android/gallery3d/app/StitchingChangeListener.java b/src/com/android/gallery3d/app/StitchingChangeListener.java deleted file mode 100644 index 0b8c2d6d6..000000000 --- a/src/com/android/gallery3d/app/StitchingChangeListener.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * 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.net.Uri; - -public interface StitchingChangeListener { - public void onStitchingQueued(Uri uri); - - public void onStitchingResult(Uri uri); - - public void onStitchingProgress(Uri uri, int progress); -} diff --git a/src/com/android/gallery3d/app/TimeBar.java b/src/com/android/gallery3d/app/TimeBar.java deleted file mode 100644 index 246346a56..000000000 --- a/src/com/android/gallery3d/app/TimeBar.java +++ /dev/null @@ -1,266 +0,0 @@ -/* - * Copyright (C) 2011 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.content.Context; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.graphics.Canvas; -import android.graphics.Paint; -import android.graphics.Rect; -import android.util.DisplayMetrics; -import android.view.MotionEvent; -import android.view.View; - -import com.android.gallery3d.R; -import com.android.gallery3d.common.Utils; - -/** - * The time bar view, which includes the current and total time, the progress - * bar, and the scrubber. - */ -public class TimeBar extends View { - - public interface Listener { - void onScrubbingStart(); - - void onScrubbingMove(int time); - - void onScrubbingEnd(int time, int start, int end); - } - - // Padding around the scrubber to increase its touch target - private static final int SCRUBBER_PADDING_IN_DP = 10; - - // The total padding, top plus bottom - private static final int V_PADDING_IN_DP = 30; - - private static final int TEXT_SIZE_IN_DP = 14; - - protected final Listener mListener; - - // the bars we use for displaying the progress - protected final Rect mProgressBar; - protected final Rect mPlayedBar; - - protected final Paint mProgressPaint; - protected final Paint mPlayedPaint; - protected final Paint mTimeTextPaint; - - protected final Bitmap mScrubber; - protected int mScrubberPadding; // adds some touch tolerance around the - // scrubber - - protected int mScrubberLeft; - protected int mScrubberTop; - protected int mScrubberCorrection; - protected boolean mScrubbing; - protected boolean mShowTimes; - protected boolean mShowScrubber; - - protected int mTotalTime; - protected int mCurrentTime; - - protected final Rect mTimeBounds; - - protected int mVPaddingInPx; - - public TimeBar(Context context, Listener listener) { - super(context); - mListener = Utils.checkNotNull(listener); - - mShowTimes = true; - mShowScrubber = true; - - mProgressBar = new Rect(); - mPlayedBar = new Rect(); - - mProgressPaint = new Paint(); - mProgressPaint.setColor(0xFF808080); - mPlayedPaint = new Paint(); - mPlayedPaint.setColor(0xFFFFFFFF); - - DisplayMetrics metrics = context.getResources().getDisplayMetrics(); - float textSizeInPx = metrics.density * TEXT_SIZE_IN_DP; - mTimeTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG); - mTimeTextPaint.setColor(0xFFCECECE); - mTimeTextPaint.setTextSize(textSizeInPx); - mTimeTextPaint.setTextAlign(Paint.Align.CENTER); - - mTimeBounds = new Rect(); - mTimeTextPaint.getTextBounds("0:00:00", 0, 7, mTimeBounds); - - mScrubber = BitmapFactory.decodeResource(getResources(), R.drawable.scrubber_knob); - mScrubberPadding = (int) (metrics.density * SCRUBBER_PADDING_IN_DP); - - mVPaddingInPx = (int) (metrics.density * V_PADDING_IN_DP); - } - - private void update() { - mPlayedBar.set(mProgressBar); - - if (mTotalTime > 0) { - mPlayedBar.right = - mPlayedBar.left + (int) ((mProgressBar.width() * (long) mCurrentTime) / mTotalTime); - } else { - mPlayedBar.right = mProgressBar.left; - } - - if (!mScrubbing) { - mScrubberLeft = mPlayedBar.right - mScrubber.getWidth() / 2; - } - invalidate(); - } - - /** - * @return the preferred height of this view, including invisible padding - */ - public int getPreferredHeight() { - return mTimeBounds.height() + mVPaddingInPx + mScrubberPadding; - } - - /** - * @return the height of the time bar, excluding invisible padding - */ - public int getBarHeight() { - return mTimeBounds.height() + mVPaddingInPx; - } - - public void setTime(int currentTime, int totalTime, - int trimStartTime, int trimEndTime) { - if (mCurrentTime == currentTime && mTotalTime == totalTime) { - return; - } - mCurrentTime = currentTime; - mTotalTime = totalTime; - update(); - } - - private boolean inScrubber(float x, float y) { - int scrubberRight = mScrubberLeft + mScrubber.getWidth(); - int scrubberBottom = mScrubberTop + mScrubber.getHeight(); - return mScrubberLeft - mScrubberPadding < x && x < scrubberRight + mScrubberPadding - && mScrubberTop - mScrubberPadding < y && y < scrubberBottom + mScrubberPadding; - } - - private void clampScrubber() { - int half = mScrubber.getWidth() / 2; - int max = mProgressBar.right - half; - int min = mProgressBar.left - half; - mScrubberLeft = Math.min(max, Math.max(min, mScrubberLeft)); - } - - private int getScrubberTime() { - return (int) ((long) (mScrubberLeft + mScrubber.getWidth() / 2 - mProgressBar.left) - * mTotalTime / mProgressBar.width()); - } - - @Override - protected void onLayout(boolean changed, int l, int t, int r, int b) { - int w = r - l; - int h = b - t; - if (!mShowTimes && !mShowScrubber) { - mProgressBar.set(0, 0, w, h); - } else { - int margin = mScrubber.getWidth() / 3; - if (mShowTimes) { - margin += mTimeBounds.width(); - } - int progressY = (h + mScrubberPadding) / 2; - mScrubberTop = progressY - mScrubber.getHeight() / 2 + 1; - mProgressBar.set( - getPaddingLeft() + margin, progressY, - w - getPaddingRight() - margin, progressY + 4); - } - update(); - } - - @Override - protected void onDraw(Canvas canvas) { - // draw progress bars - canvas.drawRect(mProgressBar, mProgressPaint); - canvas.drawRect(mPlayedBar, mPlayedPaint); - - // draw scrubber and timers - if (mShowScrubber) { - canvas.drawBitmap(mScrubber, mScrubberLeft, mScrubberTop, null); - } - if (mShowTimes) { - canvas.drawText( - stringForTime(mCurrentTime), - mTimeBounds.width() / 2 + getPaddingLeft(), - mTimeBounds.height() + mVPaddingInPx / 2 + mScrubberPadding + 1, - mTimeTextPaint); - canvas.drawText( - stringForTime(mTotalTime), - getWidth() - getPaddingRight() - mTimeBounds.width() / 2, - mTimeBounds.height() + mVPaddingInPx / 2 + mScrubberPadding + 1, - mTimeTextPaint); - } - } - - @Override - public boolean onTouchEvent(MotionEvent event) { - if (mShowScrubber) { - int x = (int) event.getX(); - int y = (int) event.getY(); - - switch (event.getAction()) { - case MotionEvent.ACTION_DOWN: { - mScrubberCorrection = inScrubber(x, y) - ? x - mScrubberLeft - : mScrubber.getWidth() / 2; - mScrubbing = true; - mListener.onScrubbingStart(); - } - // fall-through - case MotionEvent.ACTION_MOVE: { - mScrubberLeft = x - mScrubberCorrection; - clampScrubber(); - mCurrentTime = getScrubberTime(); - mListener.onScrubbingMove(mCurrentTime); - invalidate(); - return true; - } - case MotionEvent.ACTION_CANCEL: - case MotionEvent.ACTION_UP: { - mListener.onScrubbingEnd(getScrubberTime(), 0, 0); - mScrubbing = false; - return true; - } - } - } - return false; - } - - protected String stringForTime(long millis) { - int totalSeconds = (int) millis / 1000; - int seconds = totalSeconds % 60; - int minutes = (totalSeconds / 60) % 60; - int hours = totalSeconds / 3600; - if (hours > 0) { - return String.format("%d:%02d:%02d", hours, minutes, seconds).toString(); - } else { - return String.format("%02d:%02d", minutes, seconds).toString(); - } - } - - public void setSeekable(boolean canSeek) { - mShowScrubber = canSeek; - } - -} diff --git a/src/com/android/gallery3d/app/TransitionStore.java b/src/com/android/gallery3d/app/TransitionStore.java deleted file mode 100644 index aa38ed77e..000000000 --- a/src/com/android/gallery3d/app/TransitionStore.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * 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 java.util.HashMap; - -public class TransitionStore { - private HashMap<Object, Object> mStorage = new HashMap<Object, Object>(); - - public void put(Object key, Object value) { - mStorage.put(key, value); - } - - public <T> void putIfNotPresent(Object key, T valueIfNull) { - mStorage.put(key, get(key, valueIfNull)); - } - - @SuppressWarnings("unchecked") - public <T> T get(Object key) { - return (T) mStorage.get(key); - } - - @SuppressWarnings("unchecked") - public <T> T get(Object key, T valueIfNull) { - T value = (T) mStorage.get(key); - return value == null ? valueIfNull : value; - } - - public void clear() { - mStorage.clear(); - } -} diff --git a/src/com/android/gallery3d/app/TrimControllerOverlay.java b/src/com/android/gallery3d/app/TrimControllerOverlay.java deleted file mode 100644 index cae016626..000000000 --- a/src/com/android/gallery3d/app/TrimControllerOverlay.java +++ /dev/null @@ -1,111 +0,0 @@ -/* - * 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.animation.Animator; -import android.animation.Animator.AnimatorListener; -import android.animation.ObjectAnimator; -import android.content.Context; -import android.view.MotionEvent; -import android.view.View; - -import com.android.gallery3d.common.ApiHelper; - -/** - * The controller for the Trimming Video. - */ -public class TrimControllerOverlay extends CommonControllerOverlay { - - public TrimControllerOverlay(Context context) { - super(context); - } - - @Override - protected void createTimeBar(Context context) { - mTimeBar = new TrimTimeBar(context, this); - } - - private void hidePlayButtonIfPlaying() { - if (mState == State.PLAYING) { - mPlayPauseReplayView.setVisibility(View.INVISIBLE); - } - 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) { - } - - @Override - public void onAnimationEnd(Animator animation) { - hidePlayButtonIfPlaying(); - } - - @Override - public void onAnimationCancel(Animator animation) { - hidePlayButtonIfPlaying(); - } - - @Override - public void onAnimationRepeat(Animator animation) { - } - }); - } else { - hidePlayButtonIfPlaying(); - } - } - - @Override - public void setTimes(int currentTime, int totalTime, int trimStartTime, int trimEndTime) { - mTimeBar.setTime(currentTime, totalTime, trimStartTime, trimEndTime); - } - - @Override - public boolean onTouchEvent(MotionEvent event) { - if (super.onTouchEvent(event)) { - return true; - } - - // The special thing here is that the State.ENDED include both cases of - // the video completed and current == trimEnd. Both request a replay. - switch (event.getAction()) { - case MotionEvent.ACTION_DOWN: - if (mState == State.PLAYING || mState == State.PAUSED) { - mListener.onPlayPause(); - } else if (mState == State.ENDED) { - if (mCanReplay) { - mListener.onReplay(); - } - } - break; - case MotionEvent.ACTION_UP: - break; - } - return true; - } -} diff --git a/src/com/android/gallery3d/app/TrimTimeBar.java b/src/com/android/gallery3d/app/TrimTimeBar.java deleted file mode 100644 index f8dbc749e..000000000 --- a/src/com/android/gallery3d/app/TrimTimeBar.java +++ /dev/null @@ -1,339 +0,0 @@ -/* - * 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.content.Context; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.graphics.Canvas; -import android.view.MotionEvent; - -import com.android.gallery3d.R; - -/** - * The trim time bar view, which includes the current and total time, the progress - * bar, and the scrubbers for current time, start and end time for trimming. - */ -public class TrimTimeBar extends TimeBar { - - public static final int SCRUBBER_NONE = 0; - public static final int SCRUBBER_START = 1; - public static final int SCRUBBER_CURRENT = 2; - public static final int SCRUBBER_END = 3; - - private int mPressedThumb = SCRUBBER_NONE; - - // On touch event, the setting order is Scrubber Position -> Time -> - // PlayedBar. At the setTimes(), activity can update the Time directly, then - // PlayedBar will be updated too. - private int mTrimStartScrubberLeft; - private int mTrimEndScrubberLeft; - - private int mTrimStartScrubberTop; - private int mTrimEndScrubberTop; - - private int mTrimStartTime; - private int mTrimEndTime; - - private final Bitmap mTrimStartScrubber; - private final Bitmap mTrimEndScrubber; - public TrimTimeBar(Context context, Listener listener) { - super(context, listener); - - mTrimStartTime = 0; - mTrimEndTime = 0; - mTrimStartScrubberLeft = 0; - mTrimEndScrubberLeft = 0; - mTrimStartScrubberTop = 0; - mTrimEndScrubberTop = 0; - - mTrimStartScrubber = BitmapFactory.decodeResource(getResources(), - R.drawable.text_select_handle_left); - mTrimEndScrubber = BitmapFactory.decodeResource(getResources(), - R.drawable.text_select_handle_right); - // Increase the size of this trimTimeBar, but minimize the scrubber - // touch padding since we have 3 scrubbers now. - mScrubberPadding = 0; - mVPaddingInPx = mVPaddingInPx * 3 / 2; - } - - private int getBarPosFromTime(int time) { - return mProgressBar.left + - (int) ((mProgressBar.width() * (long) time) / mTotalTime); - } - - private int trimStartScrubberTipOffset() { - return mTrimStartScrubber.getWidth() * 3 / 4; - } - - private int trimEndScrubberTipOffset() { - return mTrimEndScrubber.getWidth() / 4; - } - - // Based on all the time info (current, total, trimStart, trimEnd), we - // decide the playedBar size. - private void updatePlayedBarAndScrubberFromTime() { - // According to the Time, update the Played Bar - mPlayedBar.set(mProgressBar); - if (mTotalTime > 0) { - // set playedBar according to the trim time. - mPlayedBar.left = getBarPosFromTime(mTrimStartTime); - mPlayedBar.right = getBarPosFromTime(mCurrentTime); - if (!mScrubbing) { - mScrubberLeft = mPlayedBar.right - mScrubber.getWidth() / 2; - mTrimStartScrubberLeft = mPlayedBar.left - trimStartScrubberTipOffset(); - mTrimEndScrubberLeft = getBarPosFromTime(mTrimEndTime) - - trimEndScrubberTipOffset(); - } - } else { - // If the video is not prepared, just show the scrubber at the end - // of progressBar - mPlayedBar.right = mProgressBar.left; - mScrubberLeft = mProgressBar.left - mScrubber.getWidth() / 2; - mTrimStartScrubberLeft = mProgressBar.left - trimStartScrubberTipOffset(); - mTrimEndScrubberLeft = mProgressBar.right - trimEndScrubberTipOffset(); - } - } - - private void initTrimTimeIfNeeded() { - if (mTotalTime > 0 && mTrimEndTime == 0) { - mTrimEndTime = mTotalTime; - } - } - - private void update() { - initTrimTimeIfNeeded(); - updatePlayedBarAndScrubberFromTime(); - invalidate(); - } - - @Override - public void setTime(int currentTime, int totalTime, - int trimStartTime, int trimEndTime) { - if (mCurrentTime == currentTime && mTotalTime == totalTime - && mTrimStartTime == trimStartTime && mTrimEndTime == trimEndTime) { - return; - } - mCurrentTime = currentTime; - mTotalTime = totalTime; - mTrimStartTime = trimStartTime; - mTrimEndTime = trimEndTime; - update(); - } - - private int whichScrubber(float x, float y) { - if (inScrubber(x, y, mTrimStartScrubberLeft, mTrimStartScrubberTop, mTrimStartScrubber)) { - return SCRUBBER_START; - } else if (inScrubber(x, y, mTrimEndScrubberLeft, mTrimEndScrubberTop, mTrimEndScrubber)) { - return SCRUBBER_END; - } else if (inScrubber(x, y, mScrubberLeft, mScrubberTop, mScrubber)) { - return SCRUBBER_CURRENT; - } - return SCRUBBER_NONE; - } - - private boolean inScrubber(float x, float y, int startX, int startY, Bitmap scrubber) { - int scrubberRight = startX + scrubber.getWidth(); - int scrubberBottom = startY + scrubber.getHeight(); - return startX < x && x < scrubberRight && startY < y && y < scrubberBottom; - } - - private int clampScrubber(int scrubberLeft, int offset, int lowerBound, int upperBound) { - int max = upperBound - offset; - int min = lowerBound - offset; - return Math.min(max, Math.max(min, scrubberLeft)); - } - - private int getScrubberTime(int scrubberLeft, int offset) { - return (int) ((long) (scrubberLeft + offset - mProgressBar.left) - * mTotalTime / mProgressBar.width()); - } - - @Override - protected void onLayout(boolean changed, int l, int t, int r, int b) { - int w = r - l; - int h = b - t; - if (!mShowTimes && !mShowScrubber) { - mProgressBar.set(0, 0, w, h); - } else { - int margin = mScrubber.getWidth() / 3; - if (mShowTimes) { - margin += mTimeBounds.width(); - } - int progressY = h / 4; - int scrubberY = progressY - mScrubber.getHeight() / 2 + 1; - mScrubberTop = scrubberY; - mTrimStartScrubberTop = progressY; - mTrimEndScrubberTop = progressY; - mProgressBar.set( - getPaddingLeft() + margin, progressY, - w - getPaddingRight() - margin, progressY + 4); - } - update(); - } - - @Override - protected void onDraw(Canvas canvas) { - // draw progress bars - canvas.drawRect(mProgressBar, mProgressPaint); - canvas.drawRect(mPlayedBar, mPlayedPaint); - - if (mShowTimes) { - canvas.drawText( - stringForTime(mCurrentTime), - mTimeBounds.width() / 2 + getPaddingLeft(), - mTimeBounds.height() / 2 + mTrimStartScrubberTop, - mTimeTextPaint); - canvas.drawText( - stringForTime(mTotalTime), - getWidth() - getPaddingRight() - mTimeBounds.width() / 2, - mTimeBounds.height() / 2 + mTrimStartScrubberTop, - mTimeTextPaint); - } - - // draw extra scrubbers - if (mShowScrubber) { - canvas.drawBitmap(mScrubber, mScrubberLeft, mScrubberTop, null); - canvas.drawBitmap(mTrimStartScrubber, mTrimStartScrubberLeft, - mTrimStartScrubberTop, null); - canvas.drawBitmap(mTrimEndScrubber, mTrimEndScrubberLeft, - mTrimEndScrubberTop, null); - } - } - - private void updateTimeFromPos() { - mCurrentTime = getScrubberTime(mScrubberLeft, mScrubber.getWidth() / 2); - mTrimStartTime = getScrubberTime(mTrimStartScrubberLeft, trimStartScrubberTipOffset()); - mTrimEndTime = getScrubberTime(mTrimEndScrubberLeft, trimEndScrubberTipOffset()); - } - - @Override - public boolean onTouchEvent(MotionEvent event) { - if (mShowScrubber) { - int x = (int) event.getX(); - int y = (int) event.getY(); - - switch (event.getAction()) { - case MotionEvent.ACTION_DOWN: - mPressedThumb = whichScrubber(x, y); - switch (mPressedThumb) { - case SCRUBBER_NONE: - break; - case SCRUBBER_CURRENT: - mScrubbing = true; - mScrubberCorrection = x - mScrubberLeft; - break; - case SCRUBBER_START: - mScrubbing = true; - mScrubberCorrection = x - mTrimStartScrubberLeft; - break; - case SCRUBBER_END: - mScrubbing = true; - mScrubberCorrection = x - mTrimEndScrubberLeft; - break; - } - if (mScrubbing == true) { - mListener.onScrubbingStart(); - return true; - } - break; - case MotionEvent.ACTION_MOVE: - if (mScrubbing) { - int seekToTime = -1; - int lowerBound = mTrimStartScrubberLeft + trimStartScrubberTipOffset(); - int upperBound = mTrimEndScrubberLeft + trimEndScrubberTipOffset(); - switch (mPressedThumb) { - case SCRUBBER_CURRENT: - mScrubberLeft = x - mScrubberCorrection; - mScrubberLeft = - clampScrubber(mScrubberLeft, - mScrubber.getWidth() / 2, - lowerBound, upperBound); - seekToTime = getScrubberTime(mScrubberLeft, - mScrubber.getWidth() / 2); - break; - case SCRUBBER_START: - mTrimStartScrubberLeft = x - mScrubberCorrection; - // Limit start <= end - if (mTrimStartScrubberLeft > mTrimEndScrubberLeft) { - mTrimStartScrubberLeft = mTrimEndScrubberLeft; - } - lowerBound = mProgressBar.left; - mTrimStartScrubberLeft = - clampScrubber(mTrimStartScrubberLeft, - trimStartScrubberTipOffset(), - lowerBound, upperBound); - seekToTime = getScrubberTime(mTrimStartScrubberLeft, - trimStartScrubberTipOffset()); - break; - case SCRUBBER_END: - mTrimEndScrubberLeft = x - mScrubberCorrection; - upperBound = mProgressBar.right; - mTrimEndScrubberLeft = - clampScrubber(mTrimEndScrubberLeft, - trimEndScrubberTipOffset(), - lowerBound, upperBound); - seekToTime = getScrubberTime(mTrimEndScrubberLeft, - trimEndScrubberTipOffset()); - break; - } - updateTimeFromPos(); - updatePlayedBarAndScrubberFromTime(); - if (seekToTime != -1) { - mListener.onScrubbingMove(seekToTime); - } - invalidate(); - return true; - } - break; - case MotionEvent.ACTION_CANCEL: - case MotionEvent.ACTION_UP: - if (mScrubbing) { - int seekToTime = 0; - switch (mPressedThumb) { - case SCRUBBER_CURRENT: - seekToTime = getScrubberTime(mScrubberLeft, - mScrubber.getWidth() / 2); - break; - case SCRUBBER_START: - seekToTime = getScrubberTime(mTrimStartScrubberLeft, - trimStartScrubberTipOffset()); - mScrubberLeft = mTrimStartScrubberLeft + - trimStartScrubberTipOffset() - mScrubber.getWidth() / 2; - break; - case SCRUBBER_END: - seekToTime = getScrubberTime(mTrimEndScrubberLeft, - trimEndScrubberTipOffset()); - mScrubberLeft = mTrimEndScrubberLeft + - trimEndScrubberTipOffset() - mScrubber.getWidth() / 2; - break; - } - updateTimeFromPos(); - mListener.onScrubbingEnd(seekToTime, - getScrubberTime(mTrimStartScrubberLeft, - trimStartScrubberTipOffset()), - getScrubberTime(mTrimEndScrubberLeft, trimEndScrubberTipOffset())); - mScrubbing = false; - mPressedThumb = SCRUBBER_NONE; - return true; - } - break; - } - } - return false; - } -} diff --git a/src/com/android/gallery3d/app/TrimVideo.java b/src/com/android/gallery3d/app/TrimVideo.java deleted file mode 100644 index 1e7728162..000000000 --- a/src/com/android/gallery3d/app/TrimVideo.java +++ /dev/null @@ -1,337 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.gallery3d.app; - -import android.app.ActionBar; -import android.app.Activity; -import android.app.ProgressDialog; -import android.content.Context; -import android.content.Intent; -import android.media.MediaPlayer; -import android.net.Uri; -import android.os.Bundle; -import android.os.Handler; -import android.provider.MediaStore; -import android.view.View; -import android.view.ViewGroup; -import android.view.Window; -import android.widget.TextView; -import android.widget.Toast; -import android.widget.VideoView; - -import com.android.gallery3d.R; -import com.android.gallery3d.util.SaveVideoFileInfo; -import com.android.gallery3d.util.SaveVideoFileUtils; - -import java.io.File; -import java.io.IOException; - -public class TrimVideo extends Activity implements - MediaPlayer.OnErrorListener, - MediaPlayer.OnCompletionListener, - ControllerOverlay.Listener { - - private VideoView mVideoView; - private TextView mSaveVideoTextView; - private TrimControllerOverlay mController; - private Context mContext; - private Uri mUri; - private final Handler mHandler = new Handler(); - public static final String TRIM_ACTION = "com.android.camera.action.TRIM"; - - public ProgressDialog mProgress; - - private int mTrimStartTime = 0; - private int mTrimEndTime = 0; - private int mVideoPosition = 0; - public static final String KEY_TRIM_START = "trim_start"; - public static final String KEY_TRIM_END = "trim_end"; - public static final String KEY_VIDEO_POSITION = "video_pos"; - private boolean mHasPaused = false; - - private String mSrcVideoPath = null; - private static final String TIME_STAMP_NAME = "'TRIM'_yyyyMMdd_HHmmss"; - private SaveVideoFileInfo mDstFileInfo = null; - - @Override - public void onCreate(Bundle savedInstanceState) { - mContext = getApplicationContext(); - super.onCreate(savedInstanceState); - - requestWindowFeature(Window.FEATURE_ACTION_BAR); - requestWindowFeature(Window.FEATURE_ACTION_BAR_OVERLAY); - - ActionBar actionBar = getActionBar(); - int displayOptions = ActionBar.DISPLAY_SHOW_HOME; - actionBar.setDisplayOptions(0, displayOptions); - displayOptions = ActionBar.DISPLAY_SHOW_CUSTOM; - actionBar.setDisplayOptions(displayOptions, displayOptions); - actionBar.setCustomView(R.layout.trim_menu); - - mSaveVideoTextView = (TextView) findViewById(R.id.start_trim); - mSaveVideoTextView.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View arg0) { - trimVideo(); - } - }); - mSaveVideoTextView.setEnabled(false); - - Intent intent = getIntent(); - mUri = intent.getData(); - mSrcVideoPath = intent.getStringExtra(PhotoPage.KEY_MEDIA_ITEM_PATH); - setContentView(R.layout.trim_view); - View rootView = findViewById(R.id.trim_view_root); - - mVideoView = (VideoView) rootView.findViewById(R.id.surface_view); - - mController = new TrimControllerOverlay(mContext); - ((ViewGroup) rootView).addView(mController.getView()); - mController.setListener(this); - mController.setCanReplay(true); - - mVideoView.setOnErrorListener(this); - mVideoView.setOnCompletionListener(this); - mVideoView.setVideoURI(mUri); - - playVideo(); - } - - @Override - public void onResume() { - super.onResume(); - if (mHasPaused) { - mVideoView.seekTo(mVideoPosition); - mVideoView.resume(); - mHasPaused = false; - } - mHandler.post(mProgressChecker); - } - - @Override - public void onPause() { - mHasPaused = true; - mHandler.removeCallbacksAndMessages(null); - mVideoPosition = mVideoView.getCurrentPosition(); - mVideoView.suspend(); - super.onPause(); - } - - @Override - public void onStop() { - if (mProgress != null) { - mProgress.dismiss(); - mProgress = null; - } - super.onStop(); - } - - @Override - public void onDestroy() { - mVideoView.stopPlayback(); - super.onDestroy(); - } - - private final Runnable mProgressChecker = new Runnable() { - @Override - public void run() { - int pos = setProgress(); - mHandler.postDelayed(mProgressChecker, 200 - (pos % 200)); - } - }; - - @Override - public void onSaveInstanceState(Bundle savedInstanceState) { - savedInstanceState.putInt(KEY_TRIM_START, mTrimStartTime); - savedInstanceState.putInt(KEY_TRIM_END, mTrimEndTime); - savedInstanceState.putInt(KEY_VIDEO_POSITION, mVideoPosition); - super.onSaveInstanceState(savedInstanceState); - } - - @Override - public void onRestoreInstanceState(Bundle savedInstanceState) { - super.onRestoreInstanceState(savedInstanceState); - mTrimStartTime = savedInstanceState.getInt(KEY_TRIM_START, 0); - mTrimEndTime = savedInstanceState.getInt(KEY_TRIM_END, 0); - mVideoPosition = savedInstanceState.getInt(KEY_VIDEO_POSITION, 0); - } - - // This updates the time bar display (if necessary). It is called by - // mProgressChecker and also from places where the time bar needs - // to be updated immediately. - private int setProgress() { - mVideoPosition = mVideoView.getCurrentPosition(); - // If the video position is smaller than the starting point of trimming, - // correct it. - if (mVideoPosition < mTrimStartTime) { - mVideoView.seekTo(mTrimStartTime); - mVideoPosition = mTrimStartTime; - } - // If the position is bigger than the end point of trimming, show the - // replay button and pause. - if (mVideoPosition >= mTrimEndTime && mTrimEndTime > 0) { - if (mVideoPosition > mTrimEndTime) { - mVideoView.seekTo(mTrimEndTime); - mVideoPosition = mTrimEndTime; - } - mController.showEnded(); - mVideoView.pause(); - } - - int duration = mVideoView.getDuration(); - if (duration > 0 && mTrimEndTime == 0) { - mTrimEndTime = duration; - } - mController.setTimes(mVideoPosition, duration, mTrimStartTime, mTrimEndTime); - return mVideoPosition; - } - - private void playVideo() { - mVideoView.start(); - mController.showPlaying(); - setProgress(); - } - - private void pauseVideo() { - mVideoView.pause(); - mController.showPaused(); - } - - - private boolean isModified() { - int delta = mTrimEndTime - mTrimStartTime; - - // Considering that we only trim at sync frame, we don't want to trim - // when the time interval is too short or too close to the origin. - if (delta < 100 || Math.abs(mVideoView.getDuration() - delta) < 100) { - return false; - } else { - return true; - } - } - - private void trimVideo() { - - mDstFileInfo = SaveVideoFileUtils.getDstMp4FileInfo(TIME_STAMP_NAME, - getContentResolver(), mUri, getString(R.string.folder_download)); - final File mSrcFile = new File(mSrcVideoPath); - - showProgressDialog(); - - new Thread(new Runnable() { - @Override - public void run() { - try { - VideoUtils.startTrim(mSrcFile, mDstFileInfo.mFile, - mTrimStartTime, mTrimEndTime); - // Update the database for adding a new video file. - SaveVideoFileUtils.insertContent(mDstFileInfo, - getContentResolver(), mUri); - } catch (IOException e) { - e.printStackTrace(); - } - // After trimming is done, trigger the UI changed. - mHandler.post(new Runnable() { - @Override - public void run() { - Toast.makeText(getApplicationContext(), - getString(R.string.save_into, mDstFileInfo.mFolderName), - Toast.LENGTH_SHORT) - .show(); - // TODO: change trimming into a service to avoid - // this progressDialog and add notification properly. - if (mProgress != null) { - mProgress.dismiss(); - mProgress = null; - // Show the result only when the activity not stopped. - Intent intent = new Intent(android.content.Intent.ACTION_VIEW); - intent.setDataAndType(Uri.fromFile(mDstFileInfo.mFile), "video/*"); - intent.putExtra(MediaStore.EXTRA_FINISH_ON_COMPLETION, false); - startActivity(intent); - finish(); - } - } - }); - } - }).start(); - } - - private void showProgressDialog() { - // create a background thread to trim the video. - // and show the progress. - mProgress = new ProgressDialog(this); - mProgress.setTitle(getString(R.string.trimming)); - mProgress.setMessage(getString(R.string.please_wait)); - // TODO: make this cancelable. - mProgress.setCancelable(false); - mProgress.setCanceledOnTouchOutside(false); - mProgress.show(); - } - - @Override - public void onPlayPause() { - if (mVideoView.isPlaying()) { - pauseVideo(); - } else { - playVideo(); - } - } - - @Override - public void onSeekStart() { - pauseVideo(); - } - - @Override - public void onSeekMove(int time) { - mVideoView.seekTo(time); - } - - @Override - public void onSeekEnd(int time, int start, int end) { - mVideoView.seekTo(time); - mTrimStartTime = start; - mTrimEndTime = end; - setProgress(); - // Enable save if there's modifications - mSaveVideoTextView.setEnabled(isModified()); - } - - @Override - public void onShown() { - } - - @Override - public void onHidden() { - } - - @Override - public void onReplay() { - mVideoView.seekTo(mTrimStartTime); - playVideo(); - } - - @Override - public void onCompletion(MediaPlayer mp) { - mController.showEnded(); - } - - @Override - public boolean onError(MediaPlayer mp, int what, int extra) { - return false; - } -} diff --git a/src/com/android/gallery3d/app/VideoUtils.java b/src/com/android/gallery3d/app/VideoUtils.java deleted file mode 100644 index a3c3ef273..000000000 --- a/src/com/android/gallery3d/app/VideoUtils.java +++ /dev/null @@ -1,328 +0,0 @@ -/* - * 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. - */ - -// Modified example based on mp4parser google code open source project. -// http://code.google.com/p/mp4parser/source/browse/trunk/examples/src/main/java/com/googlecode/mp4parser/ShortenExample.java - -package com.android.gallery3d.app; - -import android.media.MediaCodec.BufferInfo; -import android.media.MediaExtractor; -import android.media.MediaFormat; -import android.media.MediaMetadataRetriever; -import android.media.MediaMuxer; -import android.util.Log; - -import com.android.gallery3d.common.ApiHelper; -import com.android.gallery3d.util.SaveVideoFileInfo; -import com.coremedia.iso.IsoFile; -import com.coremedia.iso.boxes.TimeToSampleBox; -import com.googlecode.mp4parser.authoring.Movie; -import com.googlecode.mp4parser.authoring.Track; -import com.googlecode.mp4parser.authoring.builder.DefaultMp4Builder; -import com.googlecode.mp4parser.authoring.container.mp4.MovieCreator; -import com.googlecode.mp4parser.authoring.tracks.CroppedTrack; - -import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.RandomAccessFile; -import java.nio.ByteBuffer; -import java.nio.channels.FileChannel; -import java.util.Arrays; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.List; - -public class VideoUtils { - private static final String LOGTAG = "VideoUtils"; - private static final int DEFAULT_BUFFER_SIZE = 1 * 1024 * 1024; - - /** - * Remove the sound track. - */ - public static void startMute(String filePath, SaveVideoFileInfo dstFileInfo) - throws IOException { - if (ApiHelper.HAS_MEDIA_MUXER) { - genVideoUsingMuxer(filePath, dstFileInfo.mFile.getPath(), -1, -1, - false, true); - } else { - startMuteUsingMp4Parser(filePath, dstFileInfo); - } - } - - /** - * Shortens/Crops tracks - */ - public static void startTrim(File src, File dst, int startMs, int endMs) - throws IOException { - if (ApiHelper.HAS_MEDIA_MUXER) { - genVideoUsingMuxer(src.getPath(), dst.getPath(), startMs, endMs, - true, true); - } else { - trimUsingMp4Parser(src, dst, startMs, endMs); - } - } - - private static void startMuteUsingMp4Parser(String filePath, - SaveVideoFileInfo dstFileInfo) throws FileNotFoundException, 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(); - } - - /** - * @param srcPath the path of source video file. - * @param dstPath the path of destination video file. - * @param startMs starting time in milliseconds for trimming. Set to - * negative if starting from beginning. - * @param endMs end time for trimming in milliseconds. Set to negative if - * no trimming at the end. - * @param useAudio true if keep the audio track from the source. - * @param useVideo true if keep the video track from the source. - * @throws IOException - */ - private static void genVideoUsingMuxer(String srcPath, String dstPath, - int startMs, int endMs, boolean useAudio, boolean useVideo) - throws IOException { - // Set up MediaExtractor to read from the source. - MediaExtractor extractor = new MediaExtractor(); - extractor.setDataSource(srcPath); - - int trackCount = extractor.getTrackCount(); - - // Set up MediaMuxer for the destination. - MediaMuxer muxer; - muxer = new MediaMuxer(dstPath, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4); - - // Set up the tracks and retrieve the max buffer size for selected - // tracks. - HashMap<Integer, Integer> indexMap = new HashMap<Integer, - Integer>(trackCount); - int bufferSize = -1; - for (int i = 0; i < trackCount; i++) { - MediaFormat format = extractor.getTrackFormat(i); - String mime = format.getString(MediaFormat.KEY_MIME); - - boolean selectCurrentTrack = false; - - if (mime.startsWith("audio/") && useAudio) { - selectCurrentTrack = true; - } else if (mime.startsWith("video/") && useVideo) { - selectCurrentTrack = true; - } - - if (selectCurrentTrack) { - extractor.selectTrack(i); - int dstIndex = muxer.addTrack(format); - indexMap.put(i, dstIndex); - if (format.containsKey(MediaFormat.KEY_MAX_INPUT_SIZE)) { - int newSize = format.getInteger(MediaFormat.KEY_MAX_INPUT_SIZE); - bufferSize = newSize > bufferSize ? newSize : bufferSize; - } - } - } - - if (bufferSize < 0) { - bufferSize = DEFAULT_BUFFER_SIZE; - } - - // Set up the orientation and starting time for extractor. - MediaMetadataRetriever retrieverSrc = new MediaMetadataRetriever(); - retrieverSrc.setDataSource(srcPath); - String degreesString = retrieverSrc.extractMetadata( - MediaMetadataRetriever.METADATA_KEY_VIDEO_ROTATION); - if (degreesString != null) { - int degrees = Integer.parseInt(degreesString); - if (degrees >= 0) { - muxer.setOrientationHint(degrees); - } - } - - if (startMs > 0) { - extractor.seekTo(startMs * 1000, MediaExtractor.SEEK_TO_CLOSEST_SYNC); - } - - // Copy the samples from MediaExtractor to MediaMuxer. We will loop - // for copying each sample and stop when we get to the end of the source - // file or exceed the end time of the trimming. - int offset = 0; - int trackIndex = -1; - ByteBuffer dstBuf = ByteBuffer.allocate(bufferSize); - BufferInfo bufferInfo = new BufferInfo(); - - muxer.start(); - while (true) { - bufferInfo.offset = offset; - bufferInfo.size = extractor.readSampleData(dstBuf, offset); - if (bufferInfo.size < 0) { - Log.d(LOGTAG, "Saw input EOS."); - bufferInfo.size = 0; - break; - } else { - bufferInfo.presentationTimeUs = extractor.getSampleTime(); - if (endMs > 0 && bufferInfo.presentationTimeUs > (endMs * 1000)) { - Log.d(LOGTAG, "The current sample is over the trim end time."); - break; - } else { - bufferInfo.flags = extractor.getSampleFlags(); - trackIndex = extractor.getSampleTrackIndex(); - - muxer.writeSampleData(indexMap.get(trackIndex), dstBuf, - bufferInfo); - extractor.advance(); - } - } - } - - muxer.stop(); - muxer.release(); - return; - } - - private static void trimUsingMp4Parser(File src, File dst, int startMs, int endMs) - throws FileNotFoundException, IOException { - 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>()); - - double startTime = startMs / 1000; - double endTime = endMs / 1000; - - boolean timeCorrected = false; - - // Here we try to find a track that has sync samples. Since we can only - // start decoding at such a sample we SHOULD make sure that the start of - // the new fragment is exactly such a frame. - for (Track track : tracks) { - if (track.getSyncSamples() != null && track.getSyncSamples().length > 0) { - if (timeCorrected) { - // This exception here could be a false positive in case we - // have multiple tracks with sync samples at exactly the - // same positions. E.g. a single movie containing multiple - // qualities of the same video (Microsoft Smooth Streaming - // file) - throw new RuntimeException( - "The startTime has already been corrected by" + - " another track with SyncSample. Not Supported."); - } - startTime = correctTimeToSyncSample(track, startTime, false); - endTime = correctTimeToSyncSample(track, endTime, true); - timeCorrected = true; - } - } - - for (Track track : tracks) { - long currentSample = 0; - double currentTime = 0; - long startSample = -1; - long endSample = -1; - - for (int i = 0; i < track.getDecodingTimeEntries().size(); i++) { - TimeToSampleBox.Entry entry = track.getDecodingTimeEntries().get(i); - for (int j = 0; j < entry.getCount(); j++) { - // entry.getDelta() is the amount of time the current sample - // covers. - - if (currentTime <= startTime) { - // current sample is still before the new starttime - startSample = currentSample; - } - if (currentTime <= endTime) { - // current sample is after the new start time and still - // before the new endtime - endSample = currentSample; - } else { - // current sample is after the end of the cropped video - break; - } - currentTime += (double) entry.getDelta() - / (double) track.getTrackMetaData().getTimescale(); - currentSample++; - } - } - movie.addTrack(new CroppedTrack(track, startSample, endSample)); - } - writeMovieIntoFile(dst, movie); - randomAccessFile.close(); - } - - private static double correctTimeToSyncSample(Track track, double cutHere, - boolean next) { - double[] timeOfSyncSamples = new double[track.getSyncSamples().length]; - long currentSample = 0; - double currentTime = 0; - for (int i = 0; i < track.getDecodingTimeEntries().size(); i++) { - TimeToSampleBox.Entry entry = track.getDecodingTimeEntries().get(i); - for (int j = 0; j < entry.getCount(); j++) { - if (Arrays.binarySearch(track.getSyncSamples(), currentSample + 1) >= 0) { - // samples always start with 1 but we start with zero - // therefore +1 - timeOfSyncSamples[Arrays.binarySearch( - track.getSyncSamples(), currentSample + 1)] = currentTime; - } - currentTime += (double) entry.getDelta() - / (double) track.getTrackMetaData().getTimescale(); - currentSample++; - } - } - double previous = 0; - for (double timeOfSyncSample : timeOfSyncSamples) { - if (timeOfSyncSample > cutHere) { - if (next) { - return timeOfSyncSample; - } else { - return previous; - } - } - previous = timeOfSyncSample; - } - return timeOfSyncSamples[timeOfSyncSamples.length - 1]; - } - -} diff --git a/src/com/android/gallery3d/app/Wallpaper.java b/src/com/android/gallery3d/app/Wallpaper.java deleted file mode 100644 index b0a26c236..000000000 --- a/src/com/android/gallery3d/app/Wallpaper.java +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Copyright (C) 2007 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.annotation.TargetApi; -import android.app.Activity; -import android.content.Intent; -import android.graphics.Point; -import android.net.Uri; -import android.os.Build; -import android.os.Bundle; -import android.view.Display; - -import com.android.gallery3d.common.ApiHelper; -import com.android.gallery3d.filtershow.crop.CropActivity; -import com.android.gallery3d.filtershow.crop.CropExtras; - -/** - * Wallpaper picker for the gallery application. This just redirects to the - * standard pick action. - */ -public class Wallpaper extends Activity { - @SuppressWarnings("unused") - private static final String TAG = "Wallpaper"; - - private static final String IMAGE_TYPE = "image/*"; - private static final String KEY_STATE = "activity-state"; - private static final String KEY_PICKED_ITEM = "picked-item"; - - private static final int STATE_INIT = 0; - private static final int STATE_PHOTO_PICKED = 1; - - private int mState = STATE_INIT; - private Uri mPickedItem; - - @Override - protected void onCreate(Bundle bundle) { - super.onCreate(bundle); - if (bundle != null) { - mState = bundle.getInt(KEY_STATE); - mPickedItem = (Uri) bundle.getParcelable(KEY_PICKED_ITEM); - } - } - - @Override - protected void onSaveInstanceState(Bundle saveState) { - saveState.putInt(KEY_STATE, mState); - if (mPickedItem != null) { - saveState.putParcelable(KEY_PICKED_ITEM, mPickedItem); - } - } - - @SuppressWarnings("deprecation") - @TargetApi(Build.VERSION_CODES.HONEYCOMB_MR2) - private Point getDefaultDisplaySize(Point size) { - Display d = getWindowManager().getDefaultDisplay(); - if (Build.VERSION.SDK_INT >= ApiHelper.VERSION_CODES.HONEYCOMB_MR2) { - d.getSize(size); - } else { - size.set(d.getWidth(), d.getHeight()); - } - return size; - } - - @SuppressWarnings("fallthrough") - @Override - protected void onResume() { - super.onResume(); - Intent intent = getIntent(); - switch (mState) { - case STATE_INIT: { - mPickedItem = intent.getData(); - if (mPickedItem == null) { - Intent request = new Intent(Intent.ACTION_GET_CONTENT) - .setClass(this, DialogPicker.class) - .setType(IMAGE_TYPE); - startActivityForResult(request, STATE_PHOTO_PICKED); - return; - } - mState = STATE_PHOTO_PICKED; - // fall-through - } - case STATE_PHOTO_PICKED: { - int width = getWallpaperDesiredMinimumWidth(); - int height = getWallpaperDesiredMinimumHeight(); - Point size = getDefaultDisplaySize(new Point()); - float spotlightX = (float) size.x / width; - float spotlightY = (float) size.y / height; - Intent request = new Intent(CropActivity.CROP_ACTION) - .setDataAndType(mPickedItem, IMAGE_TYPE) - .addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT) - .putExtra(CropExtras.KEY_OUTPUT_X, width) - .putExtra(CropExtras.KEY_OUTPUT_Y, height) - .putExtra(CropExtras.KEY_ASPECT_X, width) - .putExtra(CropExtras.KEY_ASPECT_Y, height) - .putExtra(CropExtras.KEY_SPOTLIGHT_X, spotlightX) - .putExtra(CropExtras.KEY_SPOTLIGHT_Y, spotlightY) - .putExtra(CropExtras.KEY_SCALE, true) - .putExtra(CropExtras.KEY_SCALE_UP_IF_NEEDED, true) - .putExtra(CropExtras.KEY_SET_AS_WALLPAPER, true); - startActivity(request); - finish(); - } - } - } - - @Override - protected void onActivityResult(int requestCode, int resultCode, Intent data) { - if (resultCode != RESULT_OK) { - setResult(resultCode); - finish(); - return; - } - mState = requestCode; - if (mState == STATE_PHOTO_PICKED) { - mPickedItem = data.getData(); - } - - // onResume() would be called next - } -} |