blob: 7bccda84cfa750d877f95420943c49ced8362dbd [file] [log] [blame]
Owen Linf9a0a432011-08-17 22:07:43 +08001/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
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
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
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.
15 */
16
17package com.android.gallery3d.ui;
18
Ray Chen0c1f2c82011-10-05 14:32:58 +080019import android.app.Activity;
Ray Chen67098d12012-04-05 17:25:43 +080020import android.app.AlertDialog;
Ray Chen0c1f2c82011-10-05 14:32:58 +080021import android.app.ProgressDialog;
22import android.content.Context;
Ray Chen67098d12012-04-05 17:25:43 +080023import android.content.DialogInterface;
Owen Lind759b7c2012-05-16 15:32:02 -070024import android.content.DialogInterface.OnCancelListener;
Ray Chen67098d12012-04-05 17:25:43 +080025import android.content.DialogInterface.OnClickListener;
Ray Chen0c1f2c82011-10-05 14:32:58 +080026import android.content.Intent;
27import android.os.Handler;
28import android.os.Message;
Ray Chen0c1f2c82011-10-05 14:32:58 +080029
Owen Linb21b8e52012-08-24 12:25:57 +080030import com.actionbarsherlock.view.Menu;
31import com.actionbarsherlock.view.MenuItem;
Owen Linf9a0a432011-08-17 22:07:43 +080032import com.android.gallery3d.R;
Owen Linb21b8e52012-08-24 12:25:57 +080033import com.android.gallery3d.app.AbstractGalleryActivity;
Owen Linf9a0a432011-08-17 22:07:43 +080034import com.android.gallery3d.app.CropImage;
Owen Linf9a0a432011-08-17 22:07:43 +080035import com.android.gallery3d.common.Utils;
36import com.android.gallery3d.data.DataManager;
37import com.android.gallery3d.data.MediaItem;
38import com.android.gallery3d.data.MediaObject;
39import com.android.gallery3d.data.Path;
40import com.android.gallery3d.util.Future;
41import com.android.gallery3d.util.GalleryUtils;
42import com.android.gallery3d.util.ThreadPool.Job;
43import com.android.gallery3d.util.ThreadPool.JobContext;
44
Owen Linf9a0a432011-08-17 22:07:43 +080045import java.util.ArrayList;
46
47public class MenuExecutor {
48 @SuppressWarnings("unused")
49 private static final String TAG = "MenuExecutor";
50
51 private static final int MSG_TASK_COMPLETE = 1;
52 private static final int MSG_TASK_UPDATE = 2;
Bobby Georgescuba50b942012-08-08 00:09:50 -070053 private static final int MSG_TASK_START = 3;
54 private static final int MSG_DO_SHARE = 4;
Owen Linf9a0a432011-08-17 22:07:43 +080055
56 public static final int EXECUTION_RESULT_SUCCESS = 1;
57 public static final int EXECUTION_RESULT_FAIL = 2;
58 public static final int EXECUTION_RESULT_CANCEL = 3;
59
60 private ProgressDialog mDialog;
61 private Future<?> mTask;
Chih-Chung Chang6b891c62012-06-07 20:09:13 +080062 // wait the operation to finish when we want to stop it.
63 private boolean mWaitOnStop;
Wu-cheng Lifb557192012-07-19 17:11:06 +080064 private Intent mShareIntent;
Owen Linf9a0a432011-08-17 22:07:43 +080065
Owen Linb21b8e52012-08-24 12:25:57 +080066 private final AbstractGalleryActivity mActivity;
Owen Linf9a0a432011-08-17 22:07:43 +080067 private final SelectionManager mSelectionManager;
68 private final Handler mHandler;
69
Chih-Chung Chang6b891c62012-06-07 20:09:13 +080070 private static ProgressDialog createProgressDialog(
Owen Linf9a0a432011-08-17 22:07:43 +080071 Context context, int titleId, int progressMax) {
72 ProgressDialog dialog = new ProgressDialog(context);
73 dialog.setTitle(titleId);
74 dialog.setMax(progressMax);
75 dialog.setCancelable(false);
76 dialog.setIndeterminate(false);
77 if (progressMax > 1) {
78 dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
79 }
Owen Linf9a0a432011-08-17 22:07:43 +080080 return dialog;
81 }
82
83 public interface ProgressListener {
Owen Lind759b7c2012-05-16 15:32:02 -070084 public void onConfirmDialogShown();
85 public void onConfirmDialogDismissed(boolean confirmed);
Bobby Georgescuba50b942012-08-08 00:09:50 -070086 public void onProgressStart();
Owen Linf9a0a432011-08-17 22:07:43 +080087 public void onProgressUpdate(int index);
88 public void onProgressComplete(int result);
89 }
90
91 public MenuExecutor(
Owen Linb21b8e52012-08-24 12:25:57 +080092 AbstractGalleryActivity activity, SelectionManager selectionManager) {
Owen Linf9a0a432011-08-17 22:07:43 +080093 mActivity = Utils.checkNotNull(activity);
94 mSelectionManager = Utils.checkNotNull(selectionManager);
95 mHandler = new SynchronizedHandler(mActivity.getGLRoot()) {
96 @Override
97 public void handleMessage(Message message) {
98 switch (message.what) {
Bobby Georgescuba50b942012-08-08 00:09:50 -070099 case MSG_TASK_START: {
100 if (message.obj != null) {
101 ProgressListener listener = (ProgressListener) message.obj;
102 listener.onProgressStart();
103 }
104 break;
105 }
Owen Linf9a0a432011-08-17 22:07:43 +0800106 case MSG_TASK_COMPLETE: {
Ray Chenb2b45182011-08-31 16:37:04 +0800107 stopTaskAndDismissDialog();
Owen Linf9a0a432011-08-17 22:07:43 +0800108 if (message.obj != null) {
109 ProgressListener listener = (ProgressListener) message.obj;
110 listener.onProgressComplete(message.arg1);
111 }
112 mSelectionManager.leaveSelectionMode();
113 break;
114 }
115 case MSG_TASK_UPDATE: {
116 if (mDialog != null) mDialog.setProgress(message.arg1);
117 if (message.obj != null) {
118 ProgressListener listener = (ProgressListener) message.obj;
119 listener.onProgressUpdate(message.arg1);
120 }
121 break;
122 }
123 case MSG_DO_SHARE: {
124 ((Activity) mActivity).startActivity((Intent) message.obj);
125 break;
126 }
127 }
128 }
129 };
130 }
131
Ray Chenb2b45182011-08-31 16:37:04 +0800132 private void stopTaskAndDismissDialog() {
Owen Linf9a0a432011-08-17 22:07:43 +0800133 if (mTask != null) {
Chih-Chung Chang6b891c62012-06-07 20:09:13 +0800134 if (!mWaitOnStop) mTask.cancel();
Owen Linf9a0a432011-08-17 22:07:43 +0800135 mTask.waitDone();
136 mDialog.dismiss();
137 mDialog = null;
138 mTask = null;
139 }
140 }
141
Ray Chenb2b45182011-08-31 16:37:04 +0800142 public void pause() {
143 stopTaskAndDismissDialog();
144 }
145
Owen Linf9a0a432011-08-17 22:07:43 +0800146 private void onProgressUpdate(int index, ProgressListener listener) {
147 mHandler.sendMessage(
148 mHandler.obtainMessage(MSG_TASK_UPDATE, index, 0, listener));
149 }
150
Bobby Georgescuba50b942012-08-08 00:09:50 -0700151 private void onProgressStart(ProgressListener listener) {
152 mHandler.sendMessage(mHandler.obtainMessage(MSG_TASK_START, listener));
153 }
154
Owen Linf9a0a432011-08-17 22:07:43 +0800155 private void onProgressComplete(int result, ProgressListener listener) {
156 mHandler.sendMessage(mHandler.obtainMessage(MSG_TASK_COMPLETE, result, 0, listener));
157 }
158
Owen Linb21b8e52012-08-24 12:25:57 +0800159 public static void updateMenuOperation(Menu menu, int supported) {
Owen Linf9a0a432011-08-17 22:07:43 +0800160 boolean supportDelete = (supported & MediaObject.SUPPORT_DELETE) != 0;
161 boolean supportRotate = (supported & MediaObject.SUPPORT_ROTATE) != 0;
162 boolean supportCrop = (supported & MediaObject.SUPPORT_CROP) != 0;
163 boolean supportShare = (supported & MediaObject.SUPPORT_SHARE) != 0;
164 boolean supportSetAs = (supported & MediaObject.SUPPORT_SETAS) != 0;
165 boolean supportShowOnMap = (supported & MediaObject.SUPPORT_SHOW_ON_MAP) != 0;
166 boolean supportCache = (supported & MediaObject.SUPPORT_CACHE) != 0;
167 boolean supportEdit = (supported & MediaObject.SUPPORT_EDIT) != 0;
168 boolean supportInfo = (supported & MediaObject.SUPPORT_INFO) != 0;
169 boolean supportImport = (supported & MediaObject.SUPPORT_IMPORT) != 0;
170
Owen Linb21b8e52012-08-24 12:25:57 +0800171 setMenuItemVisible(menu, R.id.action_delete, supportDelete);
172 setMenuItemVisible(menu, R.id.action_rotate_ccw, supportRotate);
173 setMenuItemVisible(menu, R.id.action_rotate_cw, supportRotate);
174 setMenuItemVisible(menu, R.id.action_crop, supportCrop);
175 setMenuItemVisible(menu, R.id.action_share, supportShare);
176 setMenuItemVisible(menu, R.id.action_setas, supportSetAs);
177 setMenuItemVisible(menu, R.id.action_show_on_map, supportShowOnMap);
178 setMenuItemVisible(menu, R.id.action_edit, supportEdit);
179 setMenuItemVisible(menu, R.id.action_details, supportInfo);
180 setMenuItemVisible(menu, R.id.action_import, supportImport);
181 }
182
183 private static void setMenuItemVisible(Menu menu, int itemId, boolean visible) {
184 MenuItem item = menu.findItem(itemId);
185 if (item != null) item.setVisible(visible);
Owen Linf9a0a432011-08-17 22:07:43 +0800186 }
187
188 private Path getSingleSelectedPath() {
189 ArrayList<Path> ids = mSelectionManager.getSelected(true);
190 Utils.assertTrue(ids.size() == 1);
191 return ids.get(0);
192 }
193
Yuli Huangf50ce2b2012-05-02 00:50:56 +0800194 private Intent getIntentBySingleSelectedPath(String action) {
195 DataManager manager = mActivity.getDataManager();
196 Path path = getSingleSelectedPath();
197 String mimeType = getMimeType(manager.getMediaType(path));
198 return new Intent(action).setDataAndType(manager.getContentUri(path), mimeType);
199 }
200
Ray Chen67098d12012-04-05 17:25:43 +0800201 private void onMenuClicked(int action, ProgressListener listener) {
Chih-Chung Chang6b891c62012-06-07 20:09:13 +0800202 onMenuClicked(action, listener, false, true);
203 }
204
205 public void onMenuClicked(int action, ProgressListener listener,
206 boolean waitOnStop, boolean showDialog) {
Owen Linf9a0a432011-08-17 22:07:43 +0800207 int title;
Owen Linf9a0a432011-08-17 22:07:43 +0800208 switch (action) {
209 case R.id.action_select_all:
210 if (mSelectionManager.inSelectAllMode()) {
211 mSelectionManager.deSelectAll();
212 } else {
213 mSelectionManager.selectAll();
214 }
Wu-cheng Li57263d32012-04-30 23:49:17 +0800215 return;
Owen Linf9a0a432011-08-17 22:07:43 +0800216 case R.id.action_crop: {
Yuli Huangf50ce2b2012-05-02 00:50:56 +0800217 Intent intent = getIntentBySingleSelectedPath(CropImage.ACTION_CROP);
Owen Linf9a0a432011-08-17 22:07:43 +0800218 ((Activity) mActivity).startActivity(intent);
Wu-cheng Li57263d32012-04-30 23:49:17 +0800219 return;
Owen Linf9a0a432011-08-17 22:07:43 +0800220 }
Yuli Huangf50ce2b2012-05-02 00:50:56 +0800221 case R.id.action_edit: {
222 Intent intent = getIntentBySingleSelectedPath(Intent.ACTION_EDIT)
223 .setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
224 ((Activity) mActivity).startActivity(Intent.createChooser(intent, null));
225 return;
226 }
Owen Linf9a0a432011-08-17 22:07:43 +0800227 case R.id.action_setas: {
Yuli Huangf50ce2b2012-05-02 00:50:56 +0800228 Intent intent = getIntentBySingleSelectedPath(Intent.ACTION_ATTACH_DATA)
229 .addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
230 intent.putExtra("mimeType", intent.getType());
Owen Linf9a0a432011-08-17 22:07:43 +0800231 Activity activity = (Activity) mActivity;
232 activity.startActivity(Intent.createChooser(
233 intent, activity.getString(R.string.set_as)));
Wu-cheng Li57263d32012-04-30 23:49:17 +0800234 return;
Owen Linf9a0a432011-08-17 22:07:43 +0800235 }
Ray Chen67098d12012-04-05 17:25:43 +0800236 case R.id.action_delete:
Owen Linf9a0a432011-08-17 22:07:43 +0800237 title = R.string.delete;
238 break;
239 case R.id.action_rotate_cw:
240 title = R.string.rotate_right;
241 break;
242 case R.id.action_rotate_ccw:
243 title = R.string.rotate_left;
244 break;
245 case R.id.action_show_on_map:
246 title = R.string.show_on_map;
247 break;
Owen Linf9a0a432011-08-17 22:07:43 +0800248 case R.id.action_import:
249 title = R.string.Import;
250 break;
251 default:
Ray Chen67098d12012-04-05 17:25:43 +0800252 return;
Owen Linf9a0a432011-08-17 22:07:43 +0800253 }
Chih-Chung Chang6b891c62012-06-07 20:09:13 +0800254 startAction(action, title, listener, waitOnStop, showDialog);
Ray Chen67098d12012-04-05 17:25:43 +0800255 }
256
Owen Lind759b7c2012-05-16 15:32:02 -0700257 private class ConfirmDialogListener implements OnClickListener, OnCancelListener {
258 private final int mActionId;
259 private final ProgressListener mListener;
260
261 public ConfirmDialogListener(int actionId, ProgressListener listener) {
262 mActionId = actionId;
263 mListener = listener;
264 }
265
266 @Override
267 public void onClick(DialogInterface dialog, int which) {
268 if (which == DialogInterface.BUTTON_POSITIVE) {
269 if (mListener != null) {
270 mListener.onConfirmDialogDismissed(true);
271 }
272 onMenuClicked(mActionId, mListener);
273 } else {
274 if (mListener != null) {
275 mListener.onConfirmDialogDismissed(false);
276 }
277 }
278 }
279
280 @Override
281 public void onCancel(DialogInterface dialog) {
282 if (mListener != null) {
283 mListener.onConfirmDialogDismissed(false);
284 }
285 }
286 }
287
Ray Chen9a033b02012-05-15 11:22:21 +0800288 public void onMenuClicked(MenuItem menuItem, String confirmMsg,
Ray Chen67098d12012-04-05 17:25:43 +0800289 final ProgressListener listener) {
290 final int action = menuItem.getItemId();
291
Ray Chen9a033b02012-05-15 11:22:21 +0800292 if (confirmMsg != null) {
Owen Lind759b7c2012-05-16 15:32:02 -0700293 if (listener != null) listener.onConfirmDialogShown();
294 ConfirmDialogListener cdl = new ConfirmDialogListener(action, listener);
Ray Chen67098d12012-04-05 17:25:43 +0800295 new AlertDialog.Builder(mActivity.getAndroidContext())
Ray Chen9a033b02012-05-15 11:22:21 +0800296 .setMessage(confirmMsg)
Owen Lind759b7c2012-05-16 15:32:02 -0700297 .setOnCancelListener(cdl)
298 .setPositiveButton(R.string.ok, cdl)
299 .setNegativeButton(R.string.cancel, cdl)
300 .create().show();
Ray Chen67098d12012-04-05 17:25:43 +0800301 } else {
302 onMenuClicked(action, listener);
303 }
Owen Linf9a0a432011-08-17 22:07:43 +0800304 }
305
306 public void startAction(int action, int title, ProgressListener listener) {
Chih-Chung Chang6b891c62012-06-07 20:09:13 +0800307 startAction(action, title, listener, false, true);
308 }
309
310 public void startAction(int action, int title, ProgressListener listener,
311 boolean waitOnStop, boolean showDialog) {
Owen Linf9a0a432011-08-17 22:07:43 +0800312 ArrayList<Path> ids = mSelectionManager.getSelected(false);
Ray Chenb2b45182011-08-31 16:37:04 +0800313 stopTaskAndDismissDialog();
Owen Linf9a0a432011-08-17 22:07:43 +0800314
315 Activity activity = (Activity) mActivity;
Chih-Chung Chang6b891c62012-06-07 20:09:13 +0800316 mDialog = createProgressDialog(activity, title, ids.size());
317 if (showDialog) {
318 mDialog.show();
319 }
Owen Linf9a0a432011-08-17 22:07:43 +0800320 MediaOperation operation = new MediaOperation(action, ids, listener);
321 mTask = mActivity.getThreadPool().submit(operation, null);
Chih-Chung Chang6b891c62012-06-07 20:09:13 +0800322 mWaitOnStop = waitOnStop;
Owen Linf9a0a432011-08-17 22:07:43 +0800323 }
324
325 public static String getMimeType(int type) {
326 switch (type) {
327 case MediaObject.MEDIA_TYPE_IMAGE :
328 return "image/*";
329 case MediaObject.MEDIA_TYPE_VIDEO :
330 return "video/*";
331 default: return "*/*";
332 }
333 }
334
335 private boolean execute(
336 DataManager manager, JobContext jc, int cmd, Path path) {
337 boolean result = true;
Ray Chenb2b45182011-08-31 16:37:04 +0800338 Log.v(TAG, "Execute cmd: " + cmd + " for " + path);
339 long startTime = System.currentTimeMillis();
340
Owen Linf9a0a432011-08-17 22:07:43 +0800341 switch (cmd) {
Ray Chen67098d12012-04-05 17:25:43 +0800342 case R.id.action_delete:
Owen Linf9a0a432011-08-17 22:07:43 +0800343 manager.delete(path);
344 break;
345 case R.id.action_rotate_cw:
346 manager.rotate(path, 90);
347 break;
348 case R.id.action_rotate_ccw:
349 manager.rotate(path, -90);
350 break;
351 case R.id.action_toggle_full_caching: {
352 MediaObject obj = manager.getMediaObject(path);
353 int cacheFlag = obj.getCacheFlag();
354 if (cacheFlag == MediaObject.CACHE_FLAG_FULL) {
355 cacheFlag = MediaObject.CACHE_FLAG_SCREENNAIL;
356 } else {
357 cacheFlag = MediaObject.CACHE_FLAG_FULL;
358 }
359 obj.cache(cacheFlag);
360 break;
361 }
362 case R.id.action_show_on_map: {
363 MediaItem item = (MediaItem) manager.getMediaObject(path);
364 double latlng[] = new double[2];
365 item.getLatLong(latlng);
366 if (GalleryUtils.isValidLocation(latlng[0], latlng[1])) {
367 GalleryUtils.showOnMap((Context) mActivity, latlng[0], latlng[1]);
368 }
369 break;
370 }
371 case R.id.action_import: {
372 MediaObject obj = manager.getMediaObject(path);
373 result = obj.Import();
374 break;
375 }
Owen Linf9a0a432011-08-17 22:07:43 +0800376 default:
377 throw new AssertionError();
378 }
Ray Chenb2b45182011-08-31 16:37:04 +0800379 Log.v(TAG, "It takes " + (System.currentTimeMillis() - startTime) +
380 " ms to execute cmd for " + path);
Owen Linf9a0a432011-08-17 22:07:43 +0800381 return result;
382 }
383
384 private class MediaOperation implements Job<Void> {
385 private final ArrayList<Path> mItems;
386 private final int mOperation;
387 private final ProgressListener mListener;
388
Chih-Chung Chang6b891c62012-06-07 20:09:13 +0800389 public MediaOperation(int operation, ArrayList<Path> items,
390 ProgressListener listener) {
Owen Linf9a0a432011-08-17 22:07:43 +0800391 mOperation = operation;
392 mItems = items;
393 mListener = listener;
394 }
395
Ahbong Chang78179792012-07-30 11:34:13 +0800396 @Override
Owen Linf9a0a432011-08-17 22:07:43 +0800397 public Void run(JobContext jc) {
398 int index = 0;
399 DataManager manager = mActivity.getDataManager();
400 int result = EXECUTION_RESULT_SUCCESS;
Ray Chenb2b45182011-08-31 16:37:04 +0800401 try {
Bobby Georgescuba50b942012-08-08 00:09:50 -0700402 onProgressStart(mListener);
Ray Chenb2b45182011-08-31 16:37:04 +0800403 for (Path id : mItems) {
404 if (jc.isCancelled()) {
405 result = EXECUTION_RESULT_CANCEL;
406 break;
407 }
408 if (!execute(manager, jc, mOperation, id)) {
409 result = EXECUTION_RESULT_FAIL;
410 }
411 onProgressUpdate(index++, mListener);
Owen Linf9a0a432011-08-17 22:07:43 +0800412 }
Ray Chenb2b45182011-08-31 16:37:04 +0800413 } catch (Throwable th) {
414 Log.e(TAG, "failed to execute operation " + mOperation
415 + " : " + th);
416 } finally {
417 onProgressComplete(result, mListener);
Owen Linf9a0a432011-08-17 22:07:43 +0800418 }
Owen Linf9a0a432011-08-17 22:07:43 +0800419 return null;
420 }
421 }
422}