blob: 6910562942db7d24051d586c2e68182bc6476738 [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;
Teng-Hui Zhu50ea2d22012-08-23 16:45:11 -0700163 boolean supportTrim = (supported & MediaObject.SUPPORT_TRIM) != 0;
Owen Linf9a0a432011-08-17 22:07:43 +0800164 boolean supportShare = (supported & MediaObject.SUPPORT_SHARE) != 0;
165 boolean supportSetAs = (supported & MediaObject.SUPPORT_SETAS) != 0;
166 boolean supportShowOnMap = (supported & MediaObject.SUPPORT_SHOW_ON_MAP) != 0;
167 boolean supportCache = (supported & MediaObject.SUPPORT_CACHE) != 0;
168 boolean supportEdit = (supported & MediaObject.SUPPORT_EDIT) != 0;
169 boolean supportInfo = (supported & MediaObject.SUPPORT_INFO) != 0;
170 boolean supportImport = (supported & MediaObject.SUPPORT_IMPORT) != 0;
171
Owen Linb21b8e52012-08-24 12:25:57 +0800172 setMenuItemVisible(menu, R.id.action_delete, supportDelete);
173 setMenuItemVisible(menu, R.id.action_rotate_ccw, supportRotate);
174 setMenuItemVisible(menu, R.id.action_rotate_cw, supportRotate);
175 setMenuItemVisible(menu, R.id.action_crop, supportCrop);
Teng-Hui Zhu50ea2d22012-08-23 16:45:11 -0700176 setMenuItemVisible(menu, R.id.action_trim, supportTrim);
Owen Linb21b8e52012-08-24 12:25:57 +0800177 setMenuItemVisible(menu, R.id.action_share, supportShare);
178 setMenuItemVisible(menu, R.id.action_setas, supportSetAs);
179 setMenuItemVisible(menu, R.id.action_show_on_map, supportShowOnMap);
180 setMenuItemVisible(menu, R.id.action_edit, supportEdit);
181 setMenuItemVisible(menu, R.id.action_details, supportInfo);
182 setMenuItemVisible(menu, R.id.action_import, supportImport);
183 }
184
185 private static void setMenuItemVisible(Menu menu, int itemId, boolean visible) {
186 MenuItem item = menu.findItem(itemId);
187 if (item != null) item.setVisible(visible);
Owen Linf9a0a432011-08-17 22:07:43 +0800188 }
189
190 private Path getSingleSelectedPath() {
191 ArrayList<Path> ids = mSelectionManager.getSelected(true);
192 Utils.assertTrue(ids.size() == 1);
193 return ids.get(0);
194 }
195
Yuli Huangf50ce2b2012-05-02 00:50:56 +0800196 private Intent getIntentBySingleSelectedPath(String action) {
197 DataManager manager = mActivity.getDataManager();
198 Path path = getSingleSelectedPath();
199 String mimeType = getMimeType(manager.getMediaType(path));
200 return new Intent(action).setDataAndType(manager.getContentUri(path), mimeType);
201 }
202
Ray Chen67098d12012-04-05 17:25:43 +0800203 private void onMenuClicked(int action, ProgressListener listener) {
Chih-Chung Chang6b891c62012-06-07 20:09:13 +0800204 onMenuClicked(action, listener, false, true);
205 }
206
207 public void onMenuClicked(int action, ProgressListener listener,
208 boolean waitOnStop, boolean showDialog) {
Owen Linf9a0a432011-08-17 22:07:43 +0800209 int title;
Owen Linf9a0a432011-08-17 22:07:43 +0800210 switch (action) {
211 case R.id.action_select_all:
212 if (mSelectionManager.inSelectAllMode()) {
213 mSelectionManager.deSelectAll();
214 } else {
215 mSelectionManager.selectAll();
216 }
Wu-cheng Li57263d32012-04-30 23:49:17 +0800217 return;
Owen Linf9a0a432011-08-17 22:07:43 +0800218 case R.id.action_crop: {
Yuli Huangf50ce2b2012-05-02 00:50:56 +0800219 Intent intent = getIntentBySingleSelectedPath(CropImage.ACTION_CROP);
Owen Linf9a0a432011-08-17 22:07:43 +0800220 ((Activity) mActivity).startActivity(intent);
Wu-cheng Li57263d32012-04-30 23:49:17 +0800221 return;
Owen Linf9a0a432011-08-17 22:07:43 +0800222 }
Yuli Huangf50ce2b2012-05-02 00:50:56 +0800223 case R.id.action_edit: {
224 Intent intent = getIntentBySingleSelectedPath(Intent.ACTION_EDIT)
225 .setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
226 ((Activity) mActivity).startActivity(Intent.createChooser(intent, null));
227 return;
228 }
Owen Linf9a0a432011-08-17 22:07:43 +0800229 case R.id.action_setas: {
Yuli Huangf50ce2b2012-05-02 00:50:56 +0800230 Intent intent = getIntentBySingleSelectedPath(Intent.ACTION_ATTACH_DATA)
231 .addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
232 intent.putExtra("mimeType", intent.getType());
Owen Linf9a0a432011-08-17 22:07:43 +0800233 Activity activity = (Activity) mActivity;
234 activity.startActivity(Intent.createChooser(
235 intent, activity.getString(R.string.set_as)));
Wu-cheng Li57263d32012-04-30 23:49:17 +0800236 return;
Owen Linf9a0a432011-08-17 22:07:43 +0800237 }
Ray Chen67098d12012-04-05 17:25:43 +0800238 case R.id.action_delete:
Owen Linf9a0a432011-08-17 22:07:43 +0800239 title = R.string.delete;
240 break;
241 case R.id.action_rotate_cw:
242 title = R.string.rotate_right;
243 break;
244 case R.id.action_rotate_ccw:
245 title = R.string.rotate_left;
246 break;
247 case R.id.action_show_on_map:
248 title = R.string.show_on_map;
249 break;
Owen Linf9a0a432011-08-17 22:07:43 +0800250 case R.id.action_import:
251 title = R.string.Import;
252 break;
253 default:
Ray Chen67098d12012-04-05 17:25:43 +0800254 return;
Owen Linf9a0a432011-08-17 22:07:43 +0800255 }
Chih-Chung Chang6b891c62012-06-07 20:09:13 +0800256 startAction(action, title, listener, waitOnStop, showDialog);
Ray Chen67098d12012-04-05 17:25:43 +0800257 }
258
Owen Lind759b7c2012-05-16 15:32:02 -0700259 private class ConfirmDialogListener implements OnClickListener, OnCancelListener {
260 private final int mActionId;
261 private final ProgressListener mListener;
262
263 public ConfirmDialogListener(int actionId, ProgressListener listener) {
264 mActionId = actionId;
265 mListener = listener;
266 }
267
268 @Override
269 public void onClick(DialogInterface dialog, int which) {
270 if (which == DialogInterface.BUTTON_POSITIVE) {
271 if (mListener != null) {
272 mListener.onConfirmDialogDismissed(true);
273 }
274 onMenuClicked(mActionId, mListener);
275 } else {
276 if (mListener != null) {
277 mListener.onConfirmDialogDismissed(false);
278 }
279 }
280 }
281
282 @Override
283 public void onCancel(DialogInterface dialog) {
284 if (mListener != null) {
285 mListener.onConfirmDialogDismissed(false);
286 }
287 }
288 }
289
Ray Chen9a033b02012-05-15 11:22:21 +0800290 public void onMenuClicked(MenuItem menuItem, String confirmMsg,
Ray Chen67098d12012-04-05 17:25:43 +0800291 final ProgressListener listener) {
292 final int action = menuItem.getItemId();
293
Ray Chen9a033b02012-05-15 11:22:21 +0800294 if (confirmMsg != null) {
Owen Lind759b7c2012-05-16 15:32:02 -0700295 if (listener != null) listener.onConfirmDialogShown();
296 ConfirmDialogListener cdl = new ConfirmDialogListener(action, listener);
Ray Chen67098d12012-04-05 17:25:43 +0800297 new AlertDialog.Builder(mActivity.getAndroidContext())
Ray Chen9a033b02012-05-15 11:22:21 +0800298 .setMessage(confirmMsg)
Owen Lind759b7c2012-05-16 15:32:02 -0700299 .setOnCancelListener(cdl)
300 .setPositiveButton(R.string.ok, cdl)
301 .setNegativeButton(R.string.cancel, cdl)
302 .create().show();
Ray Chen67098d12012-04-05 17:25:43 +0800303 } else {
304 onMenuClicked(action, listener);
305 }
Owen Linf9a0a432011-08-17 22:07:43 +0800306 }
307
308 public void startAction(int action, int title, ProgressListener listener) {
Chih-Chung Chang6b891c62012-06-07 20:09:13 +0800309 startAction(action, title, listener, false, true);
310 }
311
312 public void startAction(int action, int title, ProgressListener listener,
313 boolean waitOnStop, boolean showDialog) {
Owen Linf9a0a432011-08-17 22:07:43 +0800314 ArrayList<Path> ids = mSelectionManager.getSelected(false);
Ray Chenb2b45182011-08-31 16:37:04 +0800315 stopTaskAndDismissDialog();
Owen Linf9a0a432011-08-17 22:07:43 +0800316
317 Activity activity = (Activity) mActivity;
Chih-Chung Chang6b891c62012-06-07 20:09:13 +0800318 mDialog = createProgressDialog(activity, title, ids.size());
319 if (showDialog) {
320 mDialog.show();
321 }
Owen Linf9a0a432011-08-17 22:07:43 +0800322 MediaOperation operation = new MediaOperation(action, ids, listener);
323 mTask = mActivity.getThreadPool().submit(operation, null);
Chih-Chung Chang6b891c62012-06-07 20:09:13 +0800324 mWaitOnStop = waitOnStop;
Owen Linf9a0a432011-08-17 22:07:43 +0800325 }
326
327 public static String getMimeType(int type) {
328 switch (type) {
329 case MediaObject.MEDIA_TYPE_IMAGE :
330 return "image/*";
331 case MediaObject.MEDIA_TYPE_VIDEO :
332 return "video/*";
333 default: return "*/*";
334 }
335 }
336
337 private boolean execute(
338 DataManager manager, JobContext jc, int cmd, Path path) {
339 boolean result = true;
Ray Chenb2b45182011-08-31 16:37:04 +0800340 Log.v(TAG, "Execute cmd: " + cmd + " for " + path);
341 long startTime = System.currentTimeMillis();
342
Owen Linf9a0a432011-08-17 22:07:43 +0800343 switch (cmd) {
Ray Chen67098d12012-04-05 17:25:43 +0800344 case R.id.action_delete:
Owen Linf9a0a432011-08-17 22:07:43 +0800345 manager.delete(path);
346 break;
347 case R.id.action_rotate_cw:
348 manager.rotate(path, 90);
349 break;
350 case R.id.action_rotate_ccw:
351 manager.rotate(path, -90);
352 break;
353 case R.id.action_toggle_full_caching: {
354 MediaObject obj = manager.getMediaObject(path);
355 int cacheFlag = obj.getCacheFlag();
356 if (cacheFlag == MediaObject.CACHE_FLAG_FULL) {
357 cacheFlag = MediaObject.CACHE_FLAG_SCREENNAIL;
358 } else {
359 cacheFlag = MediaObject.CACHE_FLAG_FULL;
360 }
361 obj.cache(cacheFlag);
362 break;
363 }
364 case R.id.action_show_on_map: {
365 MediaItem item = (MediaItem) manager.getMediaObject(path);
366 double latlng[] = new double[2];
367 item.getLatLong(latlng);
368 if (GalleryUtils.isValidLocation(latlng[0], latlng[1])) {
369 GalleryUtils.showOnMap((Context) mActivity, latlng[0], latlng[1]);
370 }
371 break;
372 }
373 case R.id.action_import: {
374 MediaObject obj = manager.getMediaObject(path);
375 result = obj.Import();
376 break;
377 }
Owen Linf9a0a432011-08-17 22:07:43 +0800378 default:
379 throw new AssertionError();
380 }
Ray Chenb2b45182011-08-31 16:37:04 +0800381 Log.v(TAG, "It takes " + (System.currentTimeMillis() - startTime) +
382 " ms to execute cmd for " + path);
Owen Linf9a0a432011-08-17 22:07:43 +0800383 return result;
384 }
385
386 private class MediaOperation implements Job<Void> {
387 private final ArrayList<Path> mItems;
388 private final int mOperation;
389 private final ProgressListener mListener;
390
Chih-Chung Chang6b891c62012-06-07 20:09:13 +0800391 public MediaOperation(int operation, ArrayList<Path> items,
392 ProgressListener listener) {
Owen Linf9a0a432011-08-17 22:07:43 +0800393 mOperation = operation;
394 mItems = items;
395 mListener = listener;
396 }
397
Ahbong Chang78179792012-07-30 11:34:13 +0800398 @Override
Owen Linf9a0a432011-08-17 22:07:43 +0800399 public Void run(JobContext jc) {
400 int index = 0;
401 DataManager manager = mActivity.getDataManager();
402 int result = EXECUTION_RESULT_SUCCESS;
Ray Chenb2b45182011-08-31 16:37:04 +0800403 try {
Bobby Georgescuba50b942012-08-08 00:09:50 -0700404 onProgressStart(mListener);
Ray Chenb2b45182011-08-31 16:37:04 +0800405 for (Path id : mItems) {
406 if (jc.isCancelled()) {
407 result = EXECUTION_RESULT_CANCEL;
408 break;
409 }
410 if (!execute(manager, jc, mOperation, id)) {
411 result = EXECUTION_RESULT_FAIL;
412 }
413 onProgressUpdate(index++, mListener);
Owen Linf9a0a432011-08-17 22:07:43 +0800414 }
Ray Chenb2b45182011-08-31 16:37:04 +0800415 } catch (Throwable th) {
416 Log.e(TAG, "failed to execute operation " + mOperation
417 + " : " + th);
418 } finally {
419 onProgressComplete(result, mListener);
Owen Linf9a0a432011-08-17 22:07:43 +0800420 }
Owen Linf9a0a432011-08-17 22:07:43 +0800421 return null;
422 }
423 }
424}