blob: 14bdc4d53325552a8b986dabad96f635bb9e70cb [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;
24import android.content.DialogInterface.OnClickListener;
Ray Chen0c1f2c82011-10-05 14:32:58 +080025import android.content.Intent;
26import android.os.Handler;
27import android.os.Message;
28import android.view.Menu;
29import android.view.MenuItem;
Ray Chen0c1f2c82011-10-05 14:32:58 +080030
Owen Linf9a0a432011-08-17 22:07:43 +080031import com.android.gallery3d.R;
32import com.android.gallery3d.app.CropImage;
33import com.android.gallery3d.app.GalleryActivity;
34import com.android.gallery3d.common.Utils;
35import com.android.gallery3d.data.DataManager;
36import com.android.gallery3d.data.MediaItem;
37import com.android.gallery3d.data.MediaObject;
38import com.android.gallery3d.data.Path;
39import com.android.gallery3d.util.Future;
40import com.android.gallery3d.util.GalleryUtils;
41import com.android.gallery3d.util.ThreadPool.Job;
42import com.android.gallery3d.util.ThreadPool.JobContext;
43
Owen Linf9a0a432011-08-17 22:07:43 +080044import java.util.ArrayList;
45
46public class MenuExecutor {
47 @SuppressWarnings("unused")
48 private static final String TAG = "MenuExecutor";
49
50 private static final int MSG_TASK_COMPLETE = 1;
51 private static final int MSG_TASK_UPDATE = 2;
52 private static final int MSG_DO_SHARE = 3;
53
54 public static final int EXECUTION_RESULT_SUCCESS = 1;
55 public static final int EXECUTION_RESULT_FAIL = 2;
56 public static final int EXECUTION_RESULT_CANCEL = 3;
57
58 private ProgressDialog mDialog;
59 private Future<?> mTask;
60
61 private final GalleryActivity mActivity;
62 private final SelectionManager mSelectionManager;
63 private final Handler mHandler;
64
65 private static ProgressDialog showProgressDialog(
66 Context context, int titleId, int progressMax) {
67 ProgressDialog dialog = new ProgressDialog(context);
68 dialog.setTitle(titleId);
69 dialog.setMax(progressMax);
70 dialog.setCancelable(false);
71 dialog.setIndeterminate(false);
72 if (progressMax > 1) {
73 dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
74 }
75 dialog.show();
76 return dialog;
77 }
78
79 public interface ProgressListener {
80 public void onProgressUpdate(int index);
81 public void onProgressComplete(int result);
82 }
83
84 public MenuExecutor(
85 GalleryActivity activity, SelectionManager selectionManager) {
86 mActivity = Utils.checkNotNull(activity);
87 mSelectionManager = Utils.checkNotNull(selectionManager);
88 mHandler = new SynchronizedHandler(mActivity.getGLRoot()) {
89 @Override
90 public void handleMessage(Message message) {
91 switch (message.what) {
92 case MSG_TASK_COMPLETE: {
Ray Chenb2b45182011-08-31 16:37:04 +080093 stopTaskAndDismissDialog();
Owen Linf9a0a432011-08-17 22:07:43 +080094 if (message.obj != null) {
95 ProgressListener listener = (ProgressListener) message.obj;
96 listener.onProgressComplete(message.arg1);
97 }
98 mSelectionManager.leaveSelectionMode();
99 break;
100 }
101 case MSG_TASK_UPDATE: {
102 if (mDialog != null) mDialog.setProgress(message.arg1);
103 if (message.obj != null) {
104 ProgressListener listener = (ProgressListener) message.obj;
105 listener.onProgressUpdate(message.arg1);
106 }
107 break;
108 }
109 case MSG_DO_SHARE: {
110 ((Activity) mActivity).startActivity((Intent) message.obj);
111 break;
112 }
113 }
114 }
115 };
116 }
117
Ray Chenb2b45182011-08-31 16:37:04 +0800118 private void stopTaskAndDismissDialog() {
Owen Linf9a0a432011-08-17 22:07:43 +0800119 if (mTask != null) {
120 mTask.cancel();
121 mTask.waitDone();
122 mDialog.dismiss();
123 mDialog = null;
124 mTask = null;
125 }
126 }
127
Ray Chenb2b45182011-08-31 16:37:04 +0800128 public void pause() {
129 stopTaskAndDismissDialog();
130 }
131
Owen Linf9a0a432011-08-17 22:07:43 +0800132 private void onProgressUpdate(int index, ProgressListener listener) {
133 mHandler.sendMessage(
134 mHandler.obtainMessage(MSG_TASK_UPDATE, index, 0, listener));
135 }
136
137 private void onProgressComplete(int result, ProgressListener listener) {
138 mHandler.sendMessage(mHandler.obtainMessage(MSG_TASK_COMPLETE, result, 0, listener));
139 }
140
Owen Linf9a0a432011-08-17 22:07:43 +0800141 private static void setMenuItemVisibility(
142 Menu menu, int id, boolean visibility) {
143 MenuItem item = menu.findItem(id);
144 if (item != null) item.setVisible(visibility);
145 }
146
147 public static void updateMenuOperation(Menu menu, int supported) {
148 boolean supportDelete = (supported & MediaObject.SUPPORT_DELETE) != 0;
149 boolean supportRotate = (supported & MediaObject.SUPPORT_ROTATE) != 0;
150 boolean supportCrop = (supported & MediaObject.SUPPORT_CROP) != 0;
151 boolean supportShare = (supported & MediaObject.SUPPORT_SHARE) != 0;
152 boolean supportSetAs = (supported & MediaObject.SUPPORT_SETAS) != 0;
153 boolean supportShowOnMap = (supported & MediaObject.SUPPORT_SHOW_ON_MAP) != 0;
154 boolean supportCache = (supported & MediaObject.SUPPORT_CACHE) != 0;
155 boolean supportEdit = (supported & MediaObject.SUPPORT_EDIT) != 0;
156 boolean supportInfo = (supported & MediaObject.SUPPORT_INFO) != 0;
157 boolean supportImport = (supported & MediaObject.SUPPORT_IMPORT) != 0;
158
159 setMenuItemVisibility(menu, R.id.action_delete, supportDelete);
160 setMenuItemVisibility(menu, R.id.action_rotate_ccw, supportRotate);
161 setMenuItemVisibility(menu, R.id.action_rotate_cw, supportRotate);
162 setMenuItemVisibility(menu, R.id.action_crop, supportCrop);
163 setMenuItemVisibility(menu, R.id.action_share, supportShare);
164 setMenuItemVisibility(menu, R.id.action_setas, supportSetAs);
165 setMenuItemVisibility(menu, R.id.action_show_on_map, supportShowOnMap);
166 setMenuItemVisibility(menu, R.id.action_edit, supportEdit);
167 setMenuItemVisibility(menu, R.id.action_details, supportInfo);
168 setMenuItemVisibility(menu, R.id.action_import, supportImport);
169 }
170
171 private Path getSingleSelectedPath() {
172 ArrayList<Path> ids = mSelectionManager.getSelected(true);
173 Utils.assertTrue(ids.size() == 1);
174 return ids.get(0);
175 }
176
Yuli Huangf50ce2b2012-05-02 00:50:56 +0800177 private Intent getIntentBySingleSelectedPath(String action) {
178 DataManager manager = mActivity.getDataManager();
179 Path path = getSingleSelectedPath();
180 String mimeType = getMimeType(manager.getMediaType(path));
181 return new Intent(action).setDataAndType(manager.getContentUri(path), mimeType);
182 }
183
Ray Chen67098d12012-04-05 17:25:43 +0800184 private void onMenuClicked(int action, ProgressListener listener) {
Owen Linf9a0a432011-08-17 22:07:43 +0800185 int title;
Owen Linf9a0a432011-08-17 22:07:43 +0800186 switch (action) {
187 case R.id.action_select_all:
188 if (mSelectionManager.inSelectAllMode()) {
189 mSelectionManager.deSelectAll();
190 } else {
191 mSelectionManager.selectAll();
192 }
Wu-cheng Li57263d32012-04-30 23:49:17 +0800193 return;
Owen Linf9a0a432011-08-17 22:07:43 +0800194 case R.id.action_crop: {
Yuli Huangf50ce2b2012-05-02 00:50:56 +0800195 Intent intent = getIntentBySingleSelectedPath(CropImage.ACTION_CROP);
Owen Linf9a0a432011-08-17 22:07:43 +0800196 ((Activity) mActivity).startActivity(intent);
Wu-cheng Li57263d32012-04-30 23:49:17 +0800197 return;
Owen Linf9a0a432011-08-17 22:07:43 +0800198 }
Yuli Huangf50ce2b2012-05-02 00:50:56 +0800199 case R.id.action_edit: {
200 Intent intent = getIntentBySingleSelectedPath(Intent.ACTION_EDIT)
201 .setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
202 ((Activity) mActivity).startActivity(Intent.createChooser(intent, null));
203 return;
204 }
Owen Linf9a0a432011-08-17 22:07:43 +0800205 case R.id.action_setas: {
Yuli Huangf50ce2b2012-05-02 00:50:56 +0800206 Intent intent = getIntentBySingleSelectedPath(Intent.ACTION_ATTACH_DATA)
207 .addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
208 intent.putExtra("mimeType", intent.getType());
Owen Linf9a0a432011-08-17 22:07:43 +0800209 Activity activity = (Activity) mActivity;
210 activity.startActivity(Intent.createChooser(
211 intent, activity.getString(R.string.set_as)));
Wu-cheng Li57263d32012-04-30 23:49:17 +0800212 return;
Owen Linf9a0a432011-08-17 22:07:43 +0800213 }
Ray Chen67098d12012-04-05 17:25:43 +0800214 case R.id.action_delete:
Owen Linf9a0a432011-08-17 22:07:43 +0800215 title = R.string.delete;
216 break;
217 case R.id.action_rotate_cw:
218 title = R.string.rotate_right;
219 break;
220 case R.id.action_rotate_ccw:
221 title = R.string.rotate_left;
222 break;
223 case R.id.action_show_on_map:
224 title = R.string.show_on_map;
225 break;
Owen Linf9a0a432011-08-17 22:07:43 +0800226 case R.id.action_import:
227 title = R.string.Import;
228 break;
229 default:
Ray Chen67098d12012-04-05 17:25:43 +0800230 return;
Owen Linf9a0a432011-08-17 22:07:43 +0800231 }
232 startAction(action, title, listener);
Ray Chen67098d12012-04-05 17:25:43 +0800233 }
234
Ray Chen9a033b02012-05-15 11:22:21 +0800235 public void onMenuClicked(MenuItem menuItem, String confirmMsg,
Ray Chen67098d12012-04-05 17:25:43 +0800236 final ProgressListener listener) {
237 final int action = menuItem.getItemId();
238
Ray Chen9a033b02012-05-15 11:22:21 +0800239 if (confirmMsg != null) {
Ray Chen67098d12012-04-05 17:25:43 +0800240 new AlertDialog.Builder(mActivity.getAndroidContext())
Ray Chen9a033b02012-05-15 11:22:21 +0800241 .setMessage(confirmMsg)
242 .setPositiveButton(R.string.ok, new OnClickListener() {
Ray Chen67098d12012-04-05 17:25:43 +0800243 public void onClick(DialogInterface dialog, int which) {
244 onMenuClicked(action, listener);
245 }
246 })
247 .setNegativeButton(R.string.cancel, null).create().show();
248 } else {
249 onMenuClicked(action, listener);
250 }
Owen Linf9a0a432011-08-17 22:07:43 +0800251 }
252
253 public void startAction(int action, int title, ProgressListener listener) {
254 ArrayList<Path> ids = mSelectionManager.getSelected(false);
Ray Chenb2b45182011-08-31 16:37:04 +0800255 stopTaskAndDismissDialog();
Owen Linf9a0a432011-08-17 22:07:43 +0800256
257 Activity activity = (Activity) mActivity;
258 mDialog = showProgressDialog(activity, title, ids.size());
259 MediaOperation operation = new MediaOperation(action, ids, listener);
260 mTask = mActivity.getThreadPool().submit(operation, null);
261 }
262
263 public static String getMimeType(int type) {
264 switch (type) {
265 case MediaObject.MEDIA_TYPE_IMAGE :
266 return "image/*";
267 case MediaObject.MEDIA_TYPE_VIDEO :
268 return "video/*";
269 default: return "*/*";
270 }
271 }
272
273 private boolean execute(
274 DataManager manager, JobContext jc, int cmd, Path path) {
275 boolean result = true;
Ray Chenb2b45182011-08-31 16:37:04 +0800276 Log.v(TAG, "Execute cmd: " + cmd + " for " + path);
277 long startTime = System.currentTimeMillis();
278
Owen Linf9a0a432011-08-17 22:07:43 +0800279 switch (cmd) {
Ray Chen67098d12012-04-05 17:25:43 +0800280 case R.id.action_delete:
Owen Linf9a0a432011-08-17 22:07:43 +0800281 manager.delete(path);
282 break;
283 case R.id.action_rotate_cw:
284 manager.rotate(path, 90);
285 break;
286 case R.id.action_rotate_ccw:
287 manager.rotate(path, -90);
288 break;
289 case R.id.action_toggle_full_caching: {
290 MediaObject obj = manager.getMediaObject(path);
291 int cacheFlag = obj.getCacheFlag();
292 if (cacheFlag == MediaObject.CACHE_FLAG_FULL) {
293 cacheFlag = MediaObject.CACHE_FLAG_SCREENNAIL;
294 } else {
295 cacheFlag = MediaObject.CACHE_FLAG_FULL;
296 }
297 obj.cache(cacheFlag);
298 break;
299 }
300 case R.id.action_show_on_map: {
301 MediaItem item = (MediaItem) manager.getMediaObject(path);
302 double latlng[] = new double[2];
303 item.getLatLong(latlng);
304 if (GalleryUtils.isValidLocation(latlng[0], latlng[1])) {
305 GalleryUtils.showOnMap((Context) mActivity, latlng[0], latlng[1]);
306 }
307 break;
308 }
309 case R.id.action_import: {
310 MediaObject obj = manager.getMediaObject(path);
311 result = obj.Import();
312 break;
313 }
Owen Linf9a0a432011-08-17 22:07:43 +0800314 default:
315 throw new AssertionError();
316 }
Ray Chenb2b45182011-08-31 16:37:04 +0800317 Log.v(TAG, "It takes " + (System.currentTimeMillis() - startTime) +
318 " ms to execute cmd for " + path);
Owen Linf9a0a432011-08-17 22:07:43 +0800319 return result;
320 }
321
322 private class MediaOperation implements Job<Void> {
323 private final ArrayList<Path> mItems;
324 private final int mOperation;
325 private final ProgressListener mListener;
326
327 public MediaOperation(int operation, ArrayList<Path> items, ProgressListener listener) {
328 mOperation = operation;
329 mItems = items;
330 mListener = listener;
331 }
332
333 public Void run(JobContext jc) {
334 int index = 0;
335 DataManager manager = mActivity.getDataManager();
336 int result = EXECUTION_RESULT_SUCCESS;
Ray Chenb2b45182011-08-31 16:37:04 +0800337 try {
338 for (Path id : mItems) {
339 if (jc.isCancelled()) {
340 result = EXECUTION_RESULT_CANCEL;
341 break;
342 }
343 if (!execute(manager, jc, mOperation, id)) {
344 result = EXECUTION_RESULT_FAIL;
345 }
346 onProgressUpdate(index++, mListener);
Owen Linf9a0a432011-08-17 22:07:43 +0800347 }
Ray Chenb2b45182011-08-31 16:37:04 +0800348 } catch (Throwable th) {
349 Log.e(TAG, "failed to execute operation " + mOperation
350 + " : " + th);
351 } finally {
352 onProgressComplete(result, mListener);
Owen Linf9a0a432011-08-17 22:07:43 +0800353 }
Owen Linf9a0a432011-08-17 22:07:43 +0800354 return null;
355 }
356 }
357}