diff options
Diffstat (limited to 'src/com/android/gallery3d/ui/MenuExecutor.java')
-rw-r--r-- | src/com/android/gallery3d/ui/MenuExecutor.java | 448 |
1 files changed, 448 insertions, 0 deletions
diff --git a/src/com/android/gallery3d/ui/MenuExecutor.java b/src/com/android/gallery3d/ui/MenuExecutor.java new file mode 100644 index 000000000..29def0527 --- /dev/null +++ b/src/com/android/gallery3d/ui/MenuExecutor.java @@ -0,0 +1,448 @@ +/* + * 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.ui; + +import android.app.Activity; +import android.app.AlertDialog; +import android.app.ProgressDialog; +import android.content.Context; +import android.content.DialogInterface; +import android.content.DialogInterface.OnCancelListener; +import android.content.DialogInterface.OnClickListener; +import android.content.Intent; +import android.os.Handler; +import android.os.Message; +import android.view.Menu; +import android.view.MenuItem; + +import com.android.gallery3d.R; +import com.android.gallery3d.app.AbstractGalleryActivity; +import com.android.gallery3d.common.Utils; +import com.android.gallery3d.data.DataManager; +import com.android.gallery3d.data.MediaItem; +import com.android.gallery3d.data.MediaObject; +import com.android.gallery3d.data.Path; +import com.android.gallery3d.filtershow.crop.CropActivity; +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 MenuExecutor { + @SuppressWarnings("unused") + private static final String TAG = "MenuExecutor"; + + private static final int MSG_TASK_COMPLETE = 1; + private static final int MSG_TASK_UPDATE = 2; + private static final int MSG_TASK_START = 3; + private static final int MSG_DO_SHARE = 4; + + public static final int EXECUTION_RESULT_SUCCESS = 1; + public static final int EXECUTION_RESULT_FAIL = 2; + public static final int EXECUTION_RESULT_CANCEL = 3; + + private ProgressDialog mDialog; + private Future<?> mTask; + // wait the operation to finish when we want to stop it. + private boolean mWaitOnStop; + private boolean mPaused; + + private final AbstractGalleryActivity mActivity; + private final SelectionManager mSelectionManager; + private final Handler mHandler; + + private static ProgressDialog createProgressDialog( + Context context, int titleId, int progressMax) { + ProgressDialog dialog = new ProgressDialog(context); + dialog.setTitle(titleId); + dialog.setMax(progressMax); + dialog.setCancelable(false); + dialog.setIndeterminate(false); + if (progressMax > 1) { + dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); + } + return dialog; + } + + public interface ProgressListener { + public void onConfirmDialogShown(); + public void onConfirmDialogDismissed(boolean confirmed); + public void onProgressStart(); + public void onProgressUpdate(int index); + public void onProgressComplete(int result); + } + + public MenuExecutor( + AbstractGalleryActivity activity, SelectionManager selectionManager) { + mActivity = Utils.checkNotNull(activity); + mSelectionManager = Utils.checkNotNull(selectionManager); + mHandler = new SynchronizedHandler(mActivity.getGLRoot()) { + @Override + public void handleMessage(Message message) { + switch (message.what) { + case MSG_TASK_START: { + if (message.obj != null) { + ProgressListener listener = (ProgressListener) message.obj; + listener.onProgressStart(); + } + break; + } + case MSG_TASK_COMPLETE: { + stopTaskAndDismissDialog(); + if (message.obj != null) { + ProgressListener listener = (ProgressListener) message.obj; + listener.onProgressComplete(message.arg1); + } + mSelectionManager.leaveSelectionMode(); + break; + } + case MSG_TASK_UPDATE: { + if (mDialog != null && !mPaused) mDialog.setProgress(message.arg1); + if (message.obj != null) { + ProgressListener listener = (ProgressListener) message.obj; + listener.onProgressUpdate(message.arg1); + } + break; + } + case MSG_DO_SHARE: { + ((Activity) mActivity).startActivity((Intent) message.obj); + break; + } + } + } + }; + } + + private void stopTaskAndDismissDialog() { + if (mTask != null) { + if (!mWaitOnStop) mTask.cancel(); + if (mDialog != null && mDialog.isShowing()) mDialog.dismiss(); + mDialog = null; + mTask = null; + } + } + + public void resume() { + mPaused = false; + if (mDialog != null) mDialog.show(); + } + + public void pause() { + mPaused = true; + if (mDialog != null && mDialog.isShowing()) mDialog.hide(); + } + + public void destroy() { + stopTaskAndDismissDialog(); + } + + private void onProgressUpdate(int index, ProgressListener listener) { + mHandler.sendMessage( + mHandler.obtainMessage(MSG_TASK_UPDATE, index, 0, listener)); + } + + private void onProgressStart(ProgressListener listener) { + mHandler.sendMessage(mHandler.obtainMessage(MSG_TASK_START, listener)); + } + + private void onProgressComplete(int result, ProgressListener listener) { + mHandler.sendMessage(mHandler.obtainMessage(MSG_TASK_COMPLETE, result, 0, listener)); + } + + public static void updateMenuOperation(Menu menu, int supported) { + boolean supportDelete = (supported & MediaObject.SUPPORT_DELETE) != 0; + boolean supportRotate = (supported & MediaObject.SUPPORT_ROTATE) != 0; + boolean supportCrop = (supported & MediaObject.SUPPORT_CROP) != 0; + boolean supportTrim = (supported & MediaObject.SUPPORT_TRIM) != 0; + boolean supportMute = (supported & MediaObject.SUPPORT_MUTE) != 0; + boolean supportShare = (supported & MediaObject.SUPPORT_SHARE) != 0; + boolean supportSetAs = (supported & MediaObject.SUPPORT_SETAS) != 0; + boolean supportShowOnMap = (supported & MediaObject.SUPPORT_SHOW_ON_MAP) != 0; + boolean supportCache = (supported & MediaObject.SUPPORT_CACHE) != 0; + boolean supportEdit = (supported & MediaObject.SUPPORT_EDIT) != 0; + boolean supportInfo = (supported & MediaObject.SUPPORT_INFO) != 0; + + setMenuItemVisible(menu, R.id.action_delete, supportDelete); + setMenuItemVisible(menu, R.id.action_rotate_ccw, supportRotate); + setMenuItemVisible(menu, R.id.action_rotate_cw, supportRotate); + setMenuItemVisible(menu, R.id.action_crop, supportCrop); + setMenuItemVisible(menu, R.id.action_trim, supportTrim); + setMenuItemVisible(menu, R.id.action_mute, supportMute); + // Hide panorama until call to updateMenuForPanorama corrects it + setMenuItemVisible(menu, R.id.action_share_panorama, false); + setMenuItemVisible(menu, R.id.action_share, supportShare); + setMenuItemVisible(menu, R.id.action_setas, supportSetAs); + setMenuItemVisible(menu, R.id.action_show_on_map, supportShowOnMap); + setMenuItemVisible(menu, R.id.action_edit, supportEdit); + setMenuItemVisible(menu, R.id.action_simple_edit, supportEdit); + setMenuItemVisible(menu, R.id.action_details, supportInfo); + } + + public static void updateMenuForPanorama(Menu menu, boolean shareAsPanorama360, + boolean disablePanorama360Options) { + setMenuItemVisible(menu, R.id.action_share_panorama, shareAsPanorama360); + if (disablePanorama360Options) { + setMenuItemVisible(menu, R.id.action_rotate_ccw, false); + setMenuItemVisible(menu, R.id.action_rotate_cw, false); + } + } + + private static void setMenuItemVisible(Menu menu, int itemId, boolean visible) { + MenuItem item = menu.findItem(itemId); + if (item != null) item.setVisible(visible); + } + + private Path getSingleSelectedPath() { + ArrayList<Path> ids = mSelectionManager.getSelected(true); + Utils.assertTrue(ids.size() == 1); + return ids.get(0); + } + + private Intent getIntentBySingleSelectedPath(String action) { + DataManager manager = mActivity.getDataManager(); + Path path = getSingleSelectedPath(); + String mimeType = getMimeType(manager.getMediaType(path)); + return new Intent(action).setDataAndType(manager.getContentUri(path), mimeType); + } + + private void onMenuClicked(int action, ProgressListener listener) { + onMenuClicked(action, listener, false, true); + } + + public void onMenuClicked(int action, ProgressListener listener, + boolean waitOnStop, boolean showDialog) { + int title; + switch (action) { + case R.id.action_select_all: + if (mSelectionManager.inSelectAllMode()) { + mSelectionManager.deSelectAll(); + } else { + mSelectionManager.selectAll(); + } + return; + case R.id.action_crop: { + Intent intent = getIntentBySingleSelectedPath(CropActivity.CROP_ACTION); + ((Activity) mActivity).startActivity(intent); + return; + } + case R.id.action_edit: { + Intent intent = getIntentBySingleSelectedPath(Intent.ACTION_EDIT) + .setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); + ((Activity) mActivity).startActivity(Intent.createChooser(intent, null)); + return; + } + case R.id.action_setas: { + Intent intent = getIntentBySingleSelectedPath(Intent.ACTION_ATTACH_DATA) + .addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); + intent.putExtra("mimeType", intent.getType()); + Activity activity = mActivity; + activity.startActivity(Intent.createChooser( + intent, activity.getString(R.string.set_as))); + return; + } + case R.id.action_delete: + title = R.string.delete; + break; + case R.id.action_rotate_cw: + title = R.string.rotate_right; + break; + case R.id.action_rotate_ccw: + title = R.string.rotate_left; + break; + case R.id.action_show_on_map: + title = R.string.show_on_map; + break; + default: + return; + } + startAction(action, title, listener, waitOnStop, showDialog); + } + + private class ConfirmDialogListener implements OnClickListener, OnCancelListener { + private final int mActionId; + private final ProgressListener mListener; + + public ConfirmDialogListener(int actionId, ProgressListener listener) { + mActionId = actionId; + mListener = listener; + } + + @Override + public void onClick(DialogInterface dialog, int which) { + if (which == DialogInterface.BUTTON_POSITIVE) { + if (mListener != null) { + mListener.onConfirmDialogDismissed(true); + } + onMenuClicked(mActionId, mListener); + } else { + if (mListener != null) { + mListener.onConfirmDialogDismissed(false); + } + } + } + + @Override + public void onCancel(DialogInterface dialog) { + if (mListener != null) { + mListener.onConfirmDialogDismissed(false); + } + } + } + + public void onMenuClicked(MenuItem menuItem, String confirmMsg, + final ProgressListener listener) { + final int action = menuItem.getItemId(); + + if (confirmMsg != null) { + if (listener != null) listener.onConfirmDialogShown(); + ConfirmDialogListener cdl = new ConfirmDialogListener(action, listener); + new AlertDialog.Builder(mActivity.getAndroidContext()) + .setMessage(confirmMsg) + .setOnCancelListener(cdl) + .setPositiveButton(R.string.ok, cdl) + .setNegativeButton(R.string.cancel, cdl) + .create().show(); + } else { + onMenuClicked(action, listener); + } + } + + public void startAction(int action, int title, ProgressListener listener) { + startAction(action, title, listener, false, true); + } + + public void startAction(int action, int title, ProgressListener listener, + boolean waitOnStop, boolean showDialog) { + ArrayList<Path> ids = mSelectionManager.getSelected(false); + stopTaskAndDismissDialog(); + + Activity activity = mActivity; + if (showDialog) { + mDialog = createProgressDialog(activity, title, ids.size()); + mDialog.show(); + } else { + mDialog = null; + } + MediaOperation operation = new MediaOperation(action, ids, listener); + mTask = mActivity.getBatchServiceThreadPoolIfAvailable().submit(operation, null); + mWaitOnStop = waitOnStop; + } + + public void startSingleItemAction(int action, Path targetPath) { + ArrayList<Path> ids = new ArrayList<Path>(1); + ids.add(targetPath); + mDialog = null; + MediaOperation operation = new MediaOperation(action, ids, null); + mTask = mActivity.getBatchServiceThreadPoolIfAvailable().submit(operation, null); + mWaitOnStop = false; + } + + public static String getMimeType(int type) { + switch (type) { + case MediaObject.MEDIA_TYPE_IMAGE : + return GalleryUtils.MIME_TYPE_IMAGE; + case MediaObject.MEDIA_TYPE_VIDEO : + return GalleryUtils.MIME_TYPE_VIDEO; + default: return GalleryUtils.MIME_TYPE_ALL; + } + } + + private boolean execute( + DataManager manager, JobContext jc, int cmd, Path path) { + boolean result = true; + Log.v(TAG, "Execute cmd: " + cmd + " for " + path); + long startTime = System.currentTimeMillis(); + + switch (cmd) { + case R.id.action_delete: + manager.delete(path); + break; + case R.id.action_rotate_cw: + manager.rotate(path, 90); + break; + case R.id.action_rotate_ccw: + manager.rotate(path, -90); + break; + case R.id.action_toggle_full_caching: { + MediaObject obj = manager.getMediaObject(path); + int cacheFlag = obj.getCacheFlag(); + if (cacheFlag == MediaObject.CACHE_FLAG_FULL) { + cacheFlag = MediaObject.CACHE_FLAG_SCREENNAIL; + } else { + cacheFlag = MediaObject.CACHE_FLAG_FULL; + } + obj.cache(cacheFlag); + break; + } + case R.id.action_show_on_map: { + MediaItem item = (MediaItem) manager.getMediaObject(path); + double latlng[] = new double[2]; + item.getLatLong(latlng); + if (GalleryUtils.isValidLocation(latlng[0], latlng[1])) { + GalleryUtils.showOnMap(mActivity, latlng[0], latlng[1]); + } + break; + } + default: + throw new AssertionError(); + } + Log.v(TAG, "It takes " + (System.currentTimeMillis() - startTime) + + " ms to execute cmd for " + path); + return result; + } + + private class MediaOperation implements Job<Void> { + private final ArrayList<Path> mItems; + private final int mOperation; + private final ProgressListener mListener; + + public MediaOperation(int operation, ArrayList<Path> items, + ProgressListener listener) { + mOperation = operation; + mItems = items; + mListener = listener; + } + + @Override + public Void run(JobContext jc) { + int index = 0; + DataManager manager = mActivity.getDataManager(); + int result = EXECUTION_RESULT_SUCCESS; + try { + onProgressStart(mListener); + for (Path id : mItems) { + if (jc.isCancelled()) { + result = EXECUTION_RESULT_CANCEL; + break; + } + if (!execute(manager, jc, mOperation, id)) { + result = EXECUTION_RESULT_FAIL; + } + onProgressUpdate(index++, mListener); + } + } catch (Throwable th) { + Log.e(TAG, "failed to execute operation " + mOperation + + " : " + th); + } finally { + onProgressComplete(result, mListener); + } + return null; + } + } +} |