blob: 710ddc4229ec3aa52b023e41ccd87fedabcb793e [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
19import com.android.gallery3d.R;
20import com.android.gallery3d.app.CropImage;
21import com.android.gallery3d.app.GalleryActivity;
22import com.android.gallery3d.common.Utils;
23import com.android.gallery3d.data.DataManager;
24import com.android.gallery3d.data.MediaItem;
25import com.android.gallery3d.data.MediaObject;
26import com.android.gallery3d.data.Path;
27import com.android.gallery3d.util.Future;
28import com.android.gallery3d.util.GalleryUtils;
29import com.android.gallery3d.util.ThreadPool.Job;
30import com.android.gallery3d.util.ThreadPool.JobContext;
31
32import android.app.Activity;
33import android.app.ProgressDialog;
34import android.content.ComponentName;
35import android.content.Context;
36import android.content.Intent;
37import android.net.Uri;
38import android.os.Handler;
39import android.os.Message;
40import android.view.Menu;
41import android.view.MenuItem;
42import android.widget.Toast;
43
44import 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: {
93 if (mDialog != null) {
94 mDialog.dismiss();
95 mDialog = null;
96 mTask = null;
97 }
98 if (message.obj != null) {
99 ProgressListener listener = (ProgressListener) message.obj;
100 listener.onProgressComplete(message.arg1);
101 }
102 mSelectionManager.leaveSelectionMode();
103 break;
104 }
105 case MSG_TASK_UPDATE: {
106 if (mDialog != null) mDialog.setProgress(message.arg1);
107 if (message.obj != null) {
108 ProgressListener listener = (ProgressListener) message.obj;
109 listener.onProgressUpdate(message.arg1);
110 }
111 break;
112 }
113 case MSG_DO_SHARE: {
114 ((Activity) mActivity).startActivity((Intent) message.obj);
115 break;
116 }
117 }
118 }
119 };
120 }
121
122 public void pause() {
123 if (mTask != null) {
124 mTask.cancel();
125 mTask.waitDone();
126 mDialog.dismiss();
127 mDialog = null;
128 mTask = null;
129 }
130 }
131
132 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
141 private int getShareType(SelectionManager selectionManager) {
142 ArrayList<Path> items = selectionManager.getSelected(false);
143 int type = 0;
144 DataManager dataManager = mActivity.getDataManager();
145 for (Path id : items) {
146 type |= dataManager.getMediaType(id);
147 }
148 return type;
149 }
150
151 private void onShareItemClicked(final SelectionManager selectionManager,
152 final String mimeType, final ComponentName component) {
153 Utils.assertTrue(mDialog == null);
154 final ArrayList<Path> items = selectionManager.getSelected(true);
155 mDialog = showProgressDialog((Activity) mActivity,
156 R.string.loading_image, items.size());
157
158 mTask = mActivity.getThreadPool().submit(new Job<Void>() {
159 @Override
160 public Void run(JobContext jc) {
161 DataManager manager = mActivity.getDataManager();
162 ArrayList<Uri> uris = new ArrayList<Uri>(items.size());
163 int index = 0;
164 for (Path path : items) {
165 if ((manager.getSupportedOperations(path)
166 & MediaObject.SUPPORT_SHARE) != 0) {
167 uris.add(manager.getContentUri(path));
168 }
169 onProgressUpdate(++index, null);
170 }
171 if (jc.isCancelled()) return null;
172 Intent intent = new Intent()
173 .setComponent(component).setType(mimeType);
174 if (uris.isEmpty()) {
175 return null;
176 } else if (uris.size() == 1) {
177 intent.setAction(Intent.ACTION_SEND);
178 intent.putExtra(Intent.EXTRA_STREAM, uris.get(0));
179 } else {
180 intent.setAction(Intent.ACTION_SEND_MULTIPLE);
181 intent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, uris);
182 }
183 onProgressComplete(EXECUTION_RESULT_SUCCESS, null);
184 mHandler.sendMessage(mHandler.obtainMessage(MSG_DO_SHARE, intent));
185 return null;
186 }
187 }, null);
188 }
189
190 private static void setMenuItemVisibility(
191 Menu menu, int id, boolean visibility) {
192 MenuItem item = menu.findItem(id);
193 if (item != null) item.setVisible(visibility);
194 }
195
196 public static void updateMenuOperation(Menu menu, int supported) {
197 boolean supportDelete = (supported & MediaObject.SUPPORT_DELETE) != 0;
198 boolean supportRotate = (supported & MediaObject.SUPPORT_ROTATE) != 0;
199 boolean supportCrop = (supported & MediaObject.SUPPORT_CROP) != 0;
200 boolean supportShare = (supported & MediaObject.SUPPORT_SHARE) != 0;
201 boolean supportSetAs = (supported & MediaObject.SUPPORT_SETAS) != 0;
202 boolean supportShowOnMap = (supported & MediaObject.SUPPORT_SHOW_ON_MAP) != 0;
203 boolean supportCache = (supported & MediaObject.SUPPORT_CACHE) != 0;
204 boolean supportEdit = (supported & MediaObject.SUPPORT_EDIT) != 0;
205 boolean supportInfo = (supported & MediaObject.SUPPORT_INFO) != 0;
206 boolean supportImport = (supported & MediaObject.SUPPORT_IMPORT) != 0;
207
208 setMenuItemVisibility(menu, R.id.action_delete, supportDelete);
209 setMenuItemVisibility(menu, R.id.action_rotate_ccw, supportRotate);
210 setMenuItemVisibility(menu, R.id.action_rotate_cw, supportRotate);
211 setMenuItemVisibility(menu, R.id.action_crop, supportCrop);
212 setMenuItemVisibility(menu, R.id.action_share, supportShare);
213 setMenuItemVisibility(menu, R.id.action_setas, supportSetAs);
214 setMenuItemVisibility(menu, R.id.action_show_on_map, supportShowOnMap);
215 setMenuItemVisibility(menu, R.id.action_edit, supportEdit);
216 setMenuItemVisibility(menu, R.id.action_details, supportInfo);
217 setMenuItemVisibility(menu, R.id.action_import, supportImport);
218 }
219
220 private Path getSingleSelectedPath() {
221 ArrayList<Path> ids = mSelectionManager.getSelected(true);
222 Utils.assertTrue(ids.size() == 1);
223 return ids.get(0);
224 }
225
226 public boolean onMenuClicked(MenuItem menuItem, ProgressListener listener) {
227 int title;
228 DataManager manager = mActivity.getDataManager();
229 int action = menuItem.getItemId();
230 switch (action) {
231 case R.id.action_select_all:
232 if (mSelectionManager.inSelectAllMode()) {
233 mSelectionManager.deSelectAll();
234 } else {
235 mSelectionManager.selectAll();
236 }
237 return true;
238 case R.id.action_crop: {
239 Path path = getSingleSelectedPath();
240 String mimeType = getMimeType(manager.getMediaType(path));
241 Intent intent = new Intent(CropImage.ACTION_CROP)
242 .setDataAndType(manager.getContentUri(path), mimeType);
243 ((Activity) mActivity).startActivity(intent);
244 return true;
245 }
246 case R.id.action_setas: {
247 Path path = getSingleSelectedPath();
248 int type = manager.getMediaType(path);
249 Intent intent = new Intent(Intent.ACTION_ATTACH_DATA);
250 String mimeType = getMimeType(type);
251 intent.setDataAndType(manager.getContentUri(path), mimeType);
252 intent.putExtra("mimeType", mimeType);
253 intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
254 Activity activity = (Activity) mActivity;
255 activity.startActivity(Intent.createChooser(
256 intent, activity.getString(R.string.set_as)));
257 return true;
258 }
259 case R.id.action_confirm_delete:
260 title = R.string.delete;
261 break;
262 case R.id.action_rotate_cw:
263 title = R.string.rotate_right;
264 break;
265 case R.id.action_rotate_ccw:
266 title = R.string.rotate_left;
267 break;
268 case R.id.action_show_on_map:
269 title = R.string.show_on_map;
270 break;
271 case R.id.action_edit:
272 title = R.string.edit;
273 break;
274 case R.id.action_import:
275 title = R.string.Import;
276 break;
277 default:
278 return false;
279 }
280 startAction(action, title, listener);
281 return true;
282 }
283
284 public void startAction(int action, int title, ProgressListener listener) {
285 ArrayList<Path> ids = mSelectionManager.getSelected(false);
286 Utils.assertTrue(mDialog == null);
287
288 Activity activity = (Activity) mActivity;
289 mDialog = showProgressDialog(activity, title, ids.size());
290 MediaOperation operation = new MediaOperation(action, ids, listener);
291 mTask = mActivity.getThreadPool().submit(operation, null);
292 }
293
294 public static String getMimeType(int type) {
295 switch (type) {
296 case MediaObject.MEDIA_TYPE_IMAGE :
297 return "image/*";
298 case MediaObject.MEDIA_TYPE_VIDEO :
299 return "video/*";
300 default: return "*/*";
301 }
302 }
303
304 private boolean execute(
305 DataManager manager, JobContext jc, int cmd, Path path) {
306 boolean result = true;
307 switch (cmd) {
308 case R.id.action_confirm_delete:
309 manager.delete(path);
310 break;
311 case R.id.action_rotate_cw:
312 manager.rotate(path, 90);
313 break;
314 case R.id.action_rotate_ccw:
315 manager.rotate(path, -90);
316 break;
317 case R.id.action_toggle_full_caching: {
318 MediaObject obj = manager.getMediaObject(path);
319 int cacheFlag = obj.getCacheFlag();
320 if (cacheFlag == MediaObject.CACHE_FLAG_FULL) {
321 cacheFlag = MediaObject.CACHE_FLAG_SCREENNAIL;
322 } else {
323 cacheFlag = MediaObject.CACHE_FLAG_FULL;
324 }
325 obj.cache(cacheFlag);
326 break;
327 }
328 case R.id.action_show_on_map: {
329 MediaItem item = (MediaItem) manager.getMediaObject(path);
330 double latlng[] = new double[2];
331 item.getLatLong(latlng);
332 if (GalleryUtils.isValidLocation(latlng[0], latlng[1])) {
333 GalleryUtils.showOnMap((Context) mActivity, latlng[0], latlng[1]);
334 }
335 break;
336 }
337 case R.id.action_import: {
338 MediaObject obj = manager.getMediaObject(path);
339 result = obj.Import();
340 break;
341 }
342 case R.id.action_edit: {
343 Activity activity = (Activity) mActivity;
344 MediaItem item = (MediaItem) manager.getMediaObject(path);
345 try {
346 activity.startActivity(Intent.createChooser(
347 new Intent(Intent.ACTION_EDIT)
348 .setData(item.getContentUri())
349 .setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION),
350 null));
351 } catch (Throwable t) {
352 Log.w(TAG, "failed to start edit activity: ", t);
353 Toast.makeText(activity,
354 activity.getString(R.string.activity_not_found),
355 Toast.LENGTH_SHORT).show();
356 }
357 break;
358 }
359 default:
360 throw new AssertionError();
361 }
362 return result;
363 }
364
365 private class MediaOperation implements Job<Void> {
366 private final ArrayList<Path> mItems;
367 private final int mOperation;
368 private final ProgressListener mListener;
369
370 public MediaOperation(int operation, ArrayList<Path> items, ProgressListener listener) {
371 mOperation = operation;
372 mItems = items;
373 mListener = listener;
374 }
375
376 public Void run(JobContext jc) {
377 int index = 0;
378 DataManager manager = mActivity.getDataManager();
379 int result = EXECUTION_RESULT_SUCCESS;
380 for (Path id : mItems) {
381 if (jc.isCancelled()) {
382 result = EXECUTION_RESULT_CANCEL;
383 break;
384 }
385 try {
386 if (!execute(manager, jc, mOperation, id)) result = EXECUTION_RESULT_FAIL;
387 } catch (Throwable th) {
388 Log.e(TAG, "failed to execute operation " + mOperation
389 + " for " + id, th);
390 }
391 onProgressUpdate(index++, mListener);
392 }
393 onProgressComplete(result, mListener);
394 return null;
395 }
396 }
397}
398