blob: a052c500d40db8ec6f9667ca8527cdcc8a1656b8 [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;
30import android.widget.Toast;
31
Owen Linf9a0a432011-08-17 22:07:43 +080032import com.android.gallery3d.R;
33import com.android.gallery3d.app.CropImage;
34import com.android.gallery3d.app.GalleryActivity;
35import 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;
53 private static final int MSG_DO_SHARE = 3;
54
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;
58
59 private ProgressDialog mDialog;
60 private Future<?> mTask;
61
62 private final GalleryActivity mActivity;
63 private final SelectionManager mSelectionManager;
64 private final Handler mHandler;
65
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);
75 }
76 dialog.show();
77 return dialog;
78 }
79
80 public interface ProgressListener {
81 public void onProgressUpdate(int index);
82 public void onProgressComplete(int result);
83 }
84
85 public MenuExecutor(
86 GalleryActivity activity, SelectionManager selectionManager) {
87 mActivity = Utils.checkNotNull(activity);
88 mSelectionManager = Utils.checkNotNull(selectionManager);
89 mHandler = new SynchronizedHandler(mActivity.getGLRoot()) {
90 @Override
91 public void handleMessage(Message message) {
92 switch (message.what) {
93 case MSG_TASK_COMPLETE: {
Ray Chenb2b45182011-08-31 16:37:04 +080094 stopTaskAndDismissDialog();
Owen Linf9a0a432011-08-17 22:07:43 +080095 if (message.obj != null) {
96 ProgressListener listener = (ProgressListener) message.obj;
97 listener.onProgressComplete(message.arg1);
98 }
99 mSelectionManager.leaveSelectionMode();
100 break;
101 }
102 case MSG_TASK_UPDATE: {
103 if (mDialog != null) mDialog.setProgress(message.arg1);
104 if (message.obj != null) {
105 ProgressListener listener = (ProgressListener) message.obj;
106 listener.onProgressUpdate(message.arg1);
107 }
108 break;
109 }
110 case MSG_DO_SHARE: {
111 ((Activity) mActivity).startActivity((Intent) message.obj);
112 break;
113 }
114 }
115 }
116 };
117 }
118
Ray Chenb2b45182011-08-31 16:37:04 +0800119 private void stopTaskAndDismissDialog() {
Owen Linf9a0a432011-08-17 22:07:43 +0800120 if (mTask != null) {
121 mTask.cancel();
122 mTask.waitDone();
123 mDialog.dismiss();
124 mDialog = null;
125 mTask = null;
126 }
127 }
128
Ray Chenb2b45182011-08-31 16:37:04 +0800129 public void pause() {
130 stopTaskAndDismissDialog();
131 }
132
Owen Linf9a0a432011-08-17 22:07:43 +0800133 private void onProgressUpdate(int index, ProgressListener listener) {
134 mHandler.sendMessage(
135 mHandler.obtainMessage(MSG_TASK_UPDATE, index, 0, listener));
136 }
137
138 private void onProgressComplete(int result, ProgressListener listener) {
139 mHandler.sendMessage(mHandler.obtainMessage(MSG_TASK_COMPLETE, result, 0, listener));
140 }
141
Owen Linf9a0a432011-08-17 22:07:43 +0800142 private static void setMenuItemVisibility(
143 Menu menu, int id, boolean visibility) {
144 MenuItem item = menu.findItem(id);
145 if (item != null) item.setVisible(visibility);
146 }
147
148 public static void updateMenuOperation(Menu menu, int supported) {
149 boolean supportDelete = (supported & MediaObject.SUPPORT_DELETE) != 0;
150 boolean supportRotate = (supported & MediaObject.SUPPORT_ROTATE) != 0;
151 boolean supportCrop = (supported & MediaObject.SUPPORT_CROP) != 0;
152 boolean supportShare = (supported & MediaObject.SUPPORT_SHARE) != 0;
153 boolean supportSetAs = (supported & MediaObject.SUPPORT_SETAS) != 0;
154 boolean supportShowOnMap = (supported & MediaObject.SUPPORT_SHOW_ON_MAP) != 0;
155 boolean supportCache = (supported & MediaObject.SUPPORT_CACHE) != 0;
156 boolean supportEdit = (supported & MediaObject.SUPPORT_EDIT) != 0;
157 boolean supportInfo = (supported & MediaObject.SUPPORT_INFO) != 0;
158 boolean supportImport = (supported & MediaObject.SUPPORT_IMPORT) != 0;
159
160 setMenuItemVisibility(menu, R.id.action_delete, supportDelete);
161 setMenuItemVisibility(menu, R.id.action_rotate_ccw, supportRotate);
162 setMenuItemVisibility(menu, R.id.action_rotate_cw, supportRotate);
163 setMenuItemVisibility(menu, R.id.action_crop, supportCrop);
164 setMenuItemVisibility(menu, R.id.action_share, supportShare);
165 setMenuItemVisibility(menu, R.id.action_setas, supportSetAs);
166 setMenuItemVisibility(menu, R.id.action_show_on_map, supportShowOnMap);
167 setMenuItemVisibility(menu, R.id.action_edit, supportEdit);
168 setMenuItemVisibility(menu, R.id.action_details, supportInfo);
169 setMenuItemVisibility(menu, R.id.action_import, supportImport);
170 }
171
172 private Path getSingleSelectedPath() {
173 ArrayList<Path> ids = mSelectionManager.getSelected(true);
174 Utils.assertTrue(ids.size() == 1);
175 return ids.get(0);
176 }
177
Ray Chen67098d12012-04-05 17:25:43 +0800178 private void onMenuClicked(int action, ProgressListener listener) {
Owen Linf9a0a432011-08-17 22:07:43 +0800179 int title;
180 DataManager manager = mActivity.getDataManager();
Owen Linf9a0a432011-08-17 22:07:43 +0800181 switch (action) {
182 case R.id.action_select_all:
183 if (mSelectionManager.inSelectAllMode()) {
184 mSelectionManager.deSelectAll();
185 } else {
186 mSelectionManager.selectAll();
187 }
Wu-cheng Li57263d32012-04-30 23:49:17 +0800188 return;
Owen Linf9a0a432011-08-17 22:07:43 +0800189 case R.id.action_crop: {
190 Path path = getSingleSelectedPath();
191 String mimeType = getMimeType(manager.getMediaType(path));
192 Intent intent = new Intent(CropImage.ACTION_CROP)
193 .setDataAndType(manager.getContentUri(path), mimeType);
194 ((Activity) mActivity).startActivity(intent);
Wu-cheng Li57263d32012-04-30 23:49:17 +0800195 return;
Owen Linf9a0a432011-08-17 22:07:43 +0800196 }
197 case R.id.action_setas: {
198 Path path = getSingleSelectedPath();
199 int type = manager.getMediaType(path);
200 Intent intent = new Intent(Intent.ACTION_ATTACH_DATA);
201 String mimeType = getMimeType(type);
202 intent.setDataAndType(manager.getContentUri(path), mimeType);
203 intent.putExtra("mimeType", mimeType);
204 intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
205 Activity activity = (Activity) mActivity;
206 activity.startActivity(Intent.createChooser(
207 intent, activity.getString(R.string.set_as)));
Wu-cheng Li57263d32012-04-30 23:49:17 +0800208 return;
Owen Linf9a0a432011-08-17 22:07:43 +0800209 }
Ray Chen67098d12012-04-05 17:25:43 +0800210 case R.id.action_delete:
Owen Linf9a0a432011-08-17 22:07:43 +0800211 title = R.string.delete;
212 break;
213 case R.id.action_rotate_cw:
214 title = R.string.rotate_right;
215 break;
216 case R.id.action_rotate_ccw:
217 title = R.string.rotate_left;
218 break;
219 case R.id.action_show_on_map:
220 title = R.string.show_on_map;
221 break;
222 case R.id.action_edit:
223 title = R.string.edit;
224 break;
225 case R.id.action_import:
226 title = R.string.Import;
227 break;
228 default:
Ray Chen67098d12012-04-05 17:25:43 +0800229 return;
Owen Linf9a0a432011-08-17 22:07:43 +0800230 }
231 startAction(action, title, listener);
Ray Chen67098d12012-04-05 17:25:43 +0800232 }
233
234 public void onMenuClicked(MenuItem menuItem, boolean needsConfirm,
235 final ProgressListener listener) {
236 final int action = menuItem.getItemId();
237
238 if (needsConfirm) {
239 new AlertDialog.Builder(mActivity.getAndroidContext())
240 .setMessage(R.string.confirm_action)
241 .setPositiveButton(R.string.confirm, new OnClickListener() {
242 public void onClick(DialogInterface dialog, int which) {
243 onMenuClicked(action, listener);
244 }
245 })
246 .setNegativeButton(R.string.cancel, null).create().show();
247 } else {
248 onMenuClicked(action, listener);
249 }
Owen Linf9a0a432011-08-17 22:07:43 +0800250 }
251
252 public void startAction(int action, int title, ProgressListener listener) {
253 ArrayList<Path> ids = mSelectionManager.getSelected(false);
Ray Chenb2b45182011-08-31 16:37:04 +0800254 stopTaskAndDismissDialog();
Owen Linf9a0a432011-08-17 22:07:43 +0800255
256 Activity activity = (Activity) mActivity;
257 mDialog = showProgressDialog(activity, title, ids.size());
258 MediaOperation operation = new MediaOperation(action, ids, listener);
259 mTask = mActivity.getThreadPool().submit(operation, null);
260 }
261
262 public static String getMimeType(int type) {
263 switch (type) {
264 case MediaObject.MEDIA_TYPE_IMAGE :
265 return "image/*";
266 case MediaObject.MEDIA_TYPE_VIDEO :
267 return "video/*";
268 default: return "*/*";
269 }
270 }
271
272 private boolean execute(
273 DataManager manager, JobContext jc, int cmd, Path path) {
274 boolean result = true;
Ray Chenb2b45182011-08-31 16:37:04 +0800275 Log.v(TAG, "Execute cmd: " + cmd + " for " + path);
276 long startTime = System.currentTimeMillis();
277
Owen Linf9a0a432011-08-17 22:07:43 +0800278 switch (cmd) {
Ray Chen67098d12012-04-05 17:25:43 +0800279 case R.id.action_delete:
Owen Linf9a0a432011-08-17 22:07:43 +0800280 manager.delete(path);
281 break;
282 case R.id.action_rotate_cw:
283 manager.rotate(path, 90);
284 break;
285 case R.id.action_rotate_ccw:
286 manager.rotate(path, -90);
287 break;
288 case R.id.action_toggle_full_caching: {
289 MediaObject obj = manager.getMediaObject(path);
290 int cacheFlag = obj.getCacheFlag();
291 if (cacheFlag == MediaObject.CACHE_FLAG_FULL) {
292 cacheFlag = MediaObject.CACHE_FLAG_SCREENNAIL;
293 } else {
294 cacheFlag = MediaObject.CACHE_FLAG_FULL;
295 }
296 obj.cache(cacheFlag);
297 break;
298 }
299 case R.id.action_show_on_map: {
300 MediaItem item = (MediaItem) manager.getMediaObject(path);
301 double latlng[] = new double[2];
302 item.getLatLong(latlng);
303 if (GalleryUtils.isValidLocation(latlng[0], latlng[1])) {
304 GalleryUtils.showOnMap((Context) mActivity, latlng[0], latlng[1]);
305 }
306 break;
307 }
308 case R.id.action_import: {
309 MediaObject obj = manager.getMediaObject(path);
310 result = obj.Import();
311 break;
312 }
313 case R.id.action_edit: {
314 Activity activity = (Activity) mActivity;
315 MediaItem item = (MediaItem) manager.getMediaObject(path);
316 try {
317 activity.startActivity(Intent.createChooser(
318 new Intent(Intent.ACTION_EDIT)
Owen Lin1801ef02011-08-26 22:34:13 +0800319 .setDataAndType(item.getContentUri(), item.getMimeType())
Owen Linf9a0a432011-08-17 22:07:43 +0800320 .setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION),
321 null));
322 } catch (Throwable t) {
323 Log.w(TAG, "failed to start edit activity: ", t);
324 Toast.makeText(activity,
325 activity.getString(R.string.activity_not_found),
326 Toast.LENGTH_SHORT).show();
327 }
328 break;
329 }
330 default:
331 throw new AssertionError();
332 }
Ray Chenb2b45182011-08-31 16:37:04 +0800333 Log.v(TAG, "It takes " + (System.currentTimeMillis() - startTime) +
334 " ms to execute cmd for " + path);
Owen Linf9a0a432011-08-17 22:07:43 +0800335 return result;
336 }
337
338 private class MediaOperation implements Job<Void> {
339 private final ArrayList<Path> mItems;
340 private final int mOperation;
341 private final ProgressListener mListener;
342
343 public MediaOperation(int operation, ArrayList<Path> items, ProgressListener listener) {
344 mOperation = operation;
345 mItems = items;
346 mListener = listener;
347 }
348
349 public Void run(JobContext jc) {
350 int index = 0;
351 DataManager manager = mActivity.getDataManager();
352 int result = EXECUTION_RESULT_SUCCESS;
Ray Chenb2b45182011-08-31 16:37:04 +0800353 try {
354 for (Path id : mItems) {
355 if (jc.isCancelled()) {
356 result = EXECUTION_RESULT_CANCEL;
357 break;
358 }
359 if (!execute(manager, jc, mOperation, id)) {
360 result = EXECUTION_RESULT_FAIL;
361 }
362 onProgressUpdate(index++, mListener);
Owen Linf9a0a432011-08-17 22:07:43 +0800363 }
Ray Chenb2b45182011-08-31 16:37:04 +0800364 } catch (Throwable th) {
365 Log.e(TAG, "failed to execute operation " + mOperation
366 + " : " + th);
367 } finally {
368 onProgressComplete(result, mListener);
Owen Linf9a0a432011-08-17 22:07:43 +0800369 }
Owen Linf9a0a432011-08-17 22:07:43 +0800370 return null;
371 }
372 }
373}