2 * Copyright (C) 2010 The Android Open Source Project
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 package com.android.gallery3d.ui;
19 import android.app.Activity;
20 import android.app.AlertDialog;
21 import android.app.ProgressDialog;
22 import android.content.Context;
23 import android.content.DialogInterface;
24 import android.content.DialogInterface.OnCancelListener;
25 import android.content.DialogInterface.OnClickListener;
26 import android.content.Intent;
27 import android.os.Handler;
28 import android.os.Message;
29 import android.view.Menu;
30 import android.view.MenuItem;
32 import com.android.gallery3d.R;
33 import com.android.gallery3d.app.CropImage;
34 import com.android.gallery3d.app.GalleryActivity;
35 import com.android.gallery3d.common.Utils;
36 import com.android.gallery3d.data.DataManager;
37 import com.android.gallery3d.data.MediaItem;
38 import com.android.gallery3d.data.MediaObject;
39 import com.android.gallery3d.data.Path;
40 import com.android.gallery3d.util.Future;
41 import com.android.gallery3d.util.GalleryUtils;
42 import com.android.gallery3d.util.ThreadPool.Job;
43 import com.android.gallery3d.util.ThreadPool.JobContext;
45 import java.util.ArrayList;
47 public class MenuExecutor {
48 @SuppressWarnings("unused")
49 private static final String TAG = "MenuExecutor";
51 private static final int MSG_TASK_COMPLETE = 1;
52 private static final int MSG_TASK_UPDATE = 2;
53 private static final int MSG_DO_SHARE = 3;
55 public static final int EXECUTION_RESULT_SUCCESS = 1;
56 public static final int EXECUTION_RESULT_FAIL = 2;
57 public static final int EXECUTION_RESULT_CANCEL = 3;
59 private ProgressDialog mDialog;
60 private Future<?> mTask;
62 private final GalleryActivity mActivity;
63 private final SelectionManager mSelectionManager;
64 private final Handler mHandler;
66 private static ProgressDialog showProgressDialog(
67 Context context, int titleId, int progressMax) {
68 ProgressDialog dialog = new ProgressDialog(context);
69 dialog.setTitle(titleId);
70 dialog.setMax(progressMax);
71 dialog.setCancelable(false);
72 dialog.setIndeterminate(false);
73 if (progressMax > 1) {
74 dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
80 public interface ProgressListener {
81 public void onConfirmDialogShown();
82 public void onConfirmDialogDismissed(boolean confirmed);
83 public void onProgressUpdate(int index);
84 public void onProgressComplete(int result);
88 GalleryActivity activity, SelectionManager selectionManager) {
89 mActivity = Utils.checkNotNull(activity);
90 mSelectionManager = Utils.checkNotNull(selectionManager);
91 mHandler = new SynchronizedHandler(mActivity.getGLRoot()) {
93 public void handleMessage(Message message) {
94 switch (message.what) {
95 case MSG_TASK_COMPLETE: {
96 stopTaskAndDismissDialog();
97 if (message.obj != null) {
98 ProgressListener listener = (ProgressListener) message.obj;
99 listener.onProgressComplete(message.arg1);
101 mSelectionManager.leaveSelectionMode();
104 case MSG_TASK_UPDATE: {
105 if (mDialog != null) mDialog.setProgress(message.arg1);
106 if (message.obj != null) {
107 ProgressListener listener = (ProgressListener) message.obj;
108 listener.onProgressUpdate(message.arg1);
113 ((Activity) mActivity).startActivity((Intent) message.obj);
121 private void stopTaskAndDismissDialog() {
131 public void pause() {
132 stopTaskAndDismissDialog();
135 private void onProgressUpdate(int index, ProgressListener listener) {
136 mHandler.sendMessage(
137 mHandler.obtainMessage(MSG_TASK_UPDATE, index, 0, listener));
140 private void onProgressComplete(int result, ProgressListener listener) {
141 mHandler.sendMessage(mHandler.obtainMessage(MSG_TASK_COMPLETE, result, 0, listener));
144 private static void setMenuItemVisibility(
145 Menu menu, int id, boolean visibility) {
146 MenuItem item = menu.findItem(id);
147 if (item != null) item.setVisible(visibility);
150 public static void updateMenuOperation(Menu menu, int supported) {
151 boolean supportDelete = (supported & MediaObject.SUPPORT_DELETE) != 0;
152 boolean supportRotate = (supported & MediaObject.SUPPORT_ROTATE) != 0;
153 boolean supportCrop = (supported & MediaObject.SUPPORT_CROP) != 0;
154 boolean supportShare = (supported & MediaObject.SUPPORT_SHARE) != 0;
155 boolean supportSetAs = (supported & MediaObject.SUPPORT_SETAS) != 0;
156 boolean supportShowOnMap = (supported & MediaObject.SUPPORT_SHOW_ON_MAP) != 0;
157 boolean supportCache = (supported & MediaObject.SUPPORT_CACHE) != 0;
158 boolean supportEdit = (supported & MediaObject.SUPPORT_EDIT) != 0;
159 boolean supportInfo = (supported & MediaObject.SUPPORT_INFO) != 0;
160 boolean supportImport = (supported & MediaObject.SUPPORT_IMPORT) != 0;
162 setMenuItemVisibility(menu, R.id.action_delete, supportDelete);
163 setMenuItemVisibility(menu, R.id.action_rotate_ccw, supportRotate);
164 setMenuItemVisibility(menu, R.id.action_rotate_cw, supportRotate);
165 setMenuItemVisibility(menu, R.id.action_crop, supportCrop);
166 setMenuItemVisibility(menu, R.id.action_share, supportShare);
167 setMenuItemVisibility(menu, R.id.action_setas, supportSetAs);
168 setMenuItemVisibility(menu, R.id.action_show_on_map, supportShowOnMap);
169 setMenuItemVisibility(menu, R.id.action_edit, supportEdit);
170 setMenuItemVisibility(menu, R.id.action_details, supportInfo);
171 setMenuItemVisibility(menu, R.id.action_import, supportImport);
174 private Path getSingleSelectedPath() {
175 ArrayList<Path> ids = mSelectionManager.getSelected(true);
176 Utils.assertTrue(ids.size() == 1);
180 private Intent getIntentBySingleSelectedPath(String action) {
181 DataManager manager = mActivity.getDataManager();
182 Path path = getSingleSelectedPath();
183 String mimeType = getMimeType(manager.getMediaType(path));
184 return new Intent(action).setDataAndType(manager.getContentUri(path), mimeType);
187 private void onMenuClicked(int action, ProgressListener listener) {
190 case R.id.action_select_all:
191 if (mSelectionManager.inSelectAllMode()) {
192 mSelectionManager.deSelectAll();
194 mSelectionManager.selectAll();
197 case R.id.action_crop: {
198 Intent intent = getIntentBySingleSelectedPath(CropImage.ACTION_CROP);
199 ((Activity) mActivity).startActivity(intent);
202 case R.id.action_edit: {
203 Intent intent = getIntentBySingleSelectedPath(Intent.ACTION_EDIT)
204 .setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
205 ((Activity) mActivity).startActivity(Intent.createChooser(intent, null));
208 case R.id.action_setas: {
209 Intent intent = getIntentBySingleSelectedPath(Intent.ACTION_ATTACH_DATA)
210 .addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
211 intent.putExtra("mimeType", intent.getType());
212 Activity activity = (Activity) mActivity;
213 activity.startActivity(Intent.createChooser(
214 intent, activity.getString(R.string.set_as)));
217 case R.id.action_delete:
218 title = R.string.delete;
220 case R.id.action_rotate_cw:
221 title = R.string.rotate_right;
223 case R.id.action_rotate_ccw:
224 title = R.string.rotate_left;
226 case R.id.action_show_on_map:
227 title = R.string.show_on_map;
229 case R.id.action_import:
230 title = R.string.Import;
235 startAction(action, title, listener);
238 private class ConfirmDialogListener implements OnClickListener, OnCancelListener {
239 private final int mActionId;
240 private final ProgressListener mListener;
242 public ConfirmDialogListener(int actionId, ProgressListener listener) {
243 mActionId = actionId;
244 mListener = listener;
248 public void onClick(DialogInterface dialog, int which) {
249 if (which == DialogInterface.BUTTON_POSITIVE) {
250 if (mListener != null) {
251 mListener.onConfirmDialogDismissed(true);
253 onMenuClicked(mActionId, mListener);
255 if (mListener != null) {
256 mListener.onConfirmDialogDismissed(false);
262 public void onCancel(DialogInterface dialog) {
263 if (mListener != null) {
264 mListener.onConfirmDialogDismissed(false);
269 public void onMenuClicked(MenuItem menuItem, String confirmMsg,
270 final ProgressListener listener) {
271 final int action = menuItem.getItemId();
273 if (confirmMsg != null) {
274 if (listener != null) listener.onConfirmDialogShown();
275 ConfirmDialogListener cdl = new ConfirmDialogListener(action, listener);
276 new AlertDialog.Builder(mActivity.getAndroidContext())
277 .setMessage(confirmMsg)
278 .setOnCancelListener(cdl)
279 .setPositiveButton(R.string.ok, cdl)
280 .setNegativeButton(R.string.cancel, cdl)
283 onMenuClicked(action, listener);
287 public void startAction(int action, int title, ProgressListener listener) {
288 ArrayList<Path> ids = mSelectionManager.getSelected(false);
289 stopTaskAndDismissDialog();
291 Activity activity = (Activity) mActivity;
292 mDialog = showProgressDialog(activity, title, ids.size());
293 MediaOperation operation = new MediaOperation(action, ids, listener);
294 mTask = mActivity.getThreadPool().submit(operation, null);
297 public static String getMimeType(int type) {
299 case MediaObject.MEDIA_TYPE_IMAGE :
301 case MediaObject.MEDIA_TYPE_VIDEO :
303 default: return "*/*";
307 private boolean execute(
308 DataManager manager, JobContext jc, int cmd, Path path) {
309 boolean result = true;
310 Log.v(TAG, "Execute cmd: " + cmd + " for " + path);
311 long startTime = System.currentTimeMillis();
314 case R.id.action_delete:
315 manager.delete(path);
317 case R.id.action_rotate_cw:
318 manager.rotate(path, 90);
320 case R.id.action_rotate_ccw:
321 manager.rotate(path, -90);
323 case R.id.action_toggle_full_caching: {
324 MediaObject obj = manager.getMediaObject(path);
325 int cacheFlag = obj.getCacheFlag();
326 if (cacheFlag == MediaObject.CACHE_FLAG_FULL) {
327 cacheFlag = MediaObject.CACHE_FLAG_SCREENNAIL;
329 cacheFlag = MediaObject.CACHE_FLAG_FULL;
331 obj.cache(cacheFlag);
334 case R.id.action_show_on_map: {
335 MediaItem item = (MediaItem) manager.getMediaObject(path);
336 double latlng[] = new double[2];
337 item.getLatLong(latlng);
338 if (GalleryUtils.isValidLocation(latlng[0], latlng[1])) {
339 GalleryUtils.showOnMap((Context) mActivity, latlng[0], latlng[1]);
343 case R.id.action_import: {
344 MediaObject obj = manager.getMediaObject(path);
345 result = obj.Import();
349 throw new AssertionError();
351 Log.v(TAG, "It takes " + (System.currentTimeMillis() - startTime) +
352 " ms to execute cmd for " + path);
356 private class MediaOperation implements Job<Void> {
357 private final ArrayList<Path> mItems;
358 private final int mOperation;
359 private final ProgressListener mListener;
361 public MediaOperation(int operation, ArrayList<Path> items, ProgressListener listener) {
362 mOperation = operation;
364 mListener = listener;
367 public Void run(JobContext jc) {
369 DataManager manager = mActivity.getDataManager();
370 int result = EXECUTION_RESULT_SUCCESS;
372 for (Path id : mItems) {
373 if (jc.isCancelled()) {
374 result = EXECUTION_RESULT_CANCEL;
377 if (!execute(manager, jc, mOperation, id)) {
378 result = EXECUTION_RESULT_FAIL;
380 onProgressUpdate(index++, mListener);
382 } catch (Throwable th) {
383 Log.e(TAG, "failed to execute operation " + mOperation
386 onProgressComplete(result, mListener);