OSDN Git Service

am ef3cc52f: disable print on older system.
[android-x86/packages-apps-Gallery2.git] / src / com / android / gallery3d / ui / MenuExecutor.java
1 /*
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
17 package com.android.gallery3d.ui;
18
19 import android.app.Activity;
20 import android.app.AlertDialog;
21 import android.app.ProgressDialog;
22 import android.content.Context;
23 import android.content.DialogInterface;
24 import android.content.DialogInterface.OnCancelListener;
25 import android.content.DialogInterface.OnClickListener;
26 import android.content.Intent;
27 import android.os.Handler;
28 import android.os.Message;
29 import android.view.Menu;
30 import android.view.MenuItem;
31
32 import com.android.gallery3d.R;
33 import com.android.gallery3d.app.AbstractGalleryActivity;
34 import com.android.gallery3d.common.Utils;
35 import com.android.gallery3d.data.DataManager;
36 import com.android.gallery3d.data.MediaItem;
37 import com.android.gallery3d.data.MediaObject;
38 import com.android.gallery3d.data.Path;
39 import com.android.gallery3d.filtershow.crop.CropActivity;
40 import com.android.gallery3d.util.Future;
41 import com.android.gallery3d.util.GalleryUtils;
42 import com.android.gallery3d.util.PrintJob;
43 import com.android.gallery3d.util.ThreadPool.Job;
44 import com.android.gallery3d.util.ThreadPool.JobContext;
45
46 import java.util.ArrayList;
47
48 public class MenuExecutor {
49     @SuppressWarnings("unused")
50     private static final String TAG = "MenuExecutor";
51
52     private static final int MSG_TASK_COMPLETE = 1;
53     private static final int MSG_TASK_UPDATE = 2;
54     private static final int MSG_TASK_START = 3;
55     private static final int MSG_DO_SHARE = 4;
56
57     public static final int EXECUTION_RESULT_SUCCESS = 1;
58     public static final int EXECUTION_RESULT_FAIL = 2;
59     public static final int EXECUTION_RESULT_CANCEL = 3;
60
61     private ProgressDialog mDialog;
62     private Future<?> mTask;
63     // wait the operation to finish when we want to stop it.
64     private boolean mWaitOnStop;
65     private boolean mPaused;
66
67     private final AbstractGalleryActivity mActivity;
68     private final SelectionManager mSelectionManager;
69     private final Handler mHandler;
70
71     private static ProgressDialog createProgressDialog(
72             Context context, int titleId, int progressMax) {
73         ProgressDialog dialog = new ProgressDialog(context);
74         dialog.setTitle(titleId);
75         dialog.setMax(progressMax);
76         dialog.setCancelable(false);
77         dialog.setIndeterminate(false);
78         if (progressMax > 1) {
79             dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
80         }
81         return dialog;
82     }
83
84     public interface ProgressListener {
85         public void onConfirmDialogShown();
86         public void onConfirmDialogDismissed(boolean confirmed);
87         public void onProgressStart();
88         public void onProgressUpdate(int index);
89         public void onProgressComplete(int result);
90     }
91
92     public MenuExecutor(
93             AbstractGalleryActivity activity, SelectionManager selectionManager) {
94         mActivity = Utils.checkNotNull(activity);
95         mSelectionManager = Utils.checkNotNull(selectionManager);
96         mHandler = new SynchronizedHandler(mActivity.getGLRoot()) {
97             @Override
98             public void handleMessage(Message message) {
99                 switch (message.what) {
100                     case MSG_TASK_START: {
101                         if (message.obj != null) {
102                             ProgressListener listener = (ProgressListener) message.obj;
103                             listener.onProgressStart();
104                         }
105                         break;
106                     }
107                     case MSG_TASK_COMPLETE: {
108                         stopTaskAndDismissDialog();
109                         if (message.obj != null) {
110                             ProgressListener listener = (ProgressListener) message.obj;
111                             listener.onProgressComplete(message.arg1);
112                         }
113                         mSelectionManager.leaveSelectionMode();
114                         break;
115                     }
116                     case MSG_TASK_UPDATE: {
117                         if (mDialog != null && !mPaused) mDialog.setProgress(message.arg1);
118                         if (message.obj != null) {
119                             ProgressListener listener = (ProgressListener) message.obj;
120                             listener.onProgressUpdate(message.arg1);
121                         }
122                         break;
123                     }
124                     case MSG_DO_SHARE: {
125                         ((Activity) mActivity).startActivity((Intent) message.obj);
126                         break;
127                     }
128                 }
129             }
130         };
131     }
132
133     private void stopTaskAndDismissDialog() {
134         if (mTask != null) {
135             if (!mWaitOnStop) mTask.cancel();
136             if (mDialog != null && mDialog.isShowing()) mDialog.dismiss();
137             mDialog = null;
138             mTask = null;
139         }
140     }
141
142     public void resume() {
143         mPaused = false;
144         if (mDialog != null) mDialog.show();
145     }
146
147     public void pause() {
148         mPaused = true;
149         if (mDialog != null && mDialog.isShowing()) mDialog.hide();
150     }
151
152     public void destroy() {
153         stopTaskAndDismissDialog();
154     }
155
156     private void onProgressUpdate(int index, ProgressListener listener) {
157         mHandler.sendMessage(
158                 mHandler.obtainMessage(MSG_TASK_UPDATE, index, 0, listener));
159     }
160
161     private void onProgressStart(ProgressListener listener) {
162         mHandler.sendMessage(mHandler.obtainMessage(MSG_TASK_START, listener));
163     }
164
165     private void onProgressComplete(int result, ProgressListener listener) {
166         mHandler.sendMessage(mHandler.obtainMessage(MSG_TASK_COMPLETE, result, 0, listener));
167     }
168
169     public static void updateMenuOperation(Menu menu, int supported) {
170         boolean supportDelete = (supported & MediaObject.SUPPORT_DELETE) != 0;
171         boolean supportRotate = (supported & MediaObject.SUPPORT_ROTATE) != 0;
172         boolean supportCrop = (supported & MediaObject.SUPPORT_CROP) != 0;
173         boolean supportTrim = (supported & MediaObject.SUPPORT_TRIM) != 0;
174         boolean supportMute = (supported & MediaObject.SUPPORT_MUTE) != 0;
175         boolean supportShare = (supported & MediaObject.SUPPORT_SHARE) != 0;
176         boolean supportSetAs = (supported & MediaObject.SUPPORT_SETAS) != 0;
177         boolean supportShowOnMap = (supported & MediaObject.SUPPORT_SHOW_ON_MAP) != 0;
178         boolean supportCache = (supported & MediaObject.SUPPORT_CACHE) != 0;
179         boolean supportEdit = (supported & MediaObject.SUPPORT_EDIT) != 0;
180         boolean supportInfo = (supported & MediaObject.SUPPORT_INFO) != 0;
181         boolean supportPrint = (supported & MediaObject.SUPPORT_PRINT) != 0;
182         supportPrint &= PrintJob.systemSupportsPrint();
183
184         setMenuItemVisible(menu, R.id.action_delete, supportDelete);
185         setMenuItemVisible(menu, R.id.action_rotate_ccw, supportRotate);
186         setMenuItemVisible(menu, R.id.action_rotate_cw, supportRotate);
187         setMenuItemVisible(menu, R.id.action_crop, supportCrop);
188         setMenuItemVisible(menu, R.id.action_trim, supportTrim);
189         setMenuItemVisible(menu, R.id.action_mute, supportMute);
190         // Hide panorama until call to updateMenuForPanorama corrects it
191         setMenuItemVisible(menu, R.id.action_share_panorama, false);
192         setMenuItemVisible(menu, R.id.action_share, supportShare);
193         setMenuItemVisible(menu, R.id.action_setas, supportSetAs);
194         setMenuItemVisible(menu, R.id.action_show_on_map, supportShowOnMap);
195         setMenuItemVisible(menu, R.id.action_edit, supportEdit);
196         // setMenuItemVisible(menu, R.id.action_simple_edit, supportEdit);
197         setMenuItemVisible(menu, R.id.action_details, supportInfo);
198         setMenuItemVisible(menu, R.id.print, supportPrint);
199     }
200
201     public static void updateMenuForPanorama(Menu menu, boolean shareAsPanorama360,
202             boolean disablePanorama360Options) {
203         setMenuItemVisible(menu, R.id.action_share_panorama, shareAsPanorama360);
204         if (disablePanorama360Options) {
205             setMenuItemVisible(menu, R.id.action_rotate_ccw, false);
206             setMenuItemVisible(menu, R.id.action_rotate_cw, false);
207         }
208     }
209
210     private static void setMenuItemVisible(Menu menu, int itemId, boolean visible) {
211         MenuItem item = menu.findItem(itemId);
212         if (item != null) item.setVisible(visible);
213     }
214
215     private Path getSingleSelectedPath() {
216         ArrayList<Path> ids = mSelectionManager.getSelected(true);
217         Utils.assertTrue(ids.size() == 1);
218         return ids.get(0);
219     }
220
221     private Intent getIntentBySingleSelectedPath(String action) {
222         DataManager manager = mActivity.getDataManager();
223         Path path = getSingleSelectedPath();
224         String mimeType = getMimeType(manager.getMediaType(path));
225         return new Intent(action).setDataAndType(manager.getContentUri(path), mimeType);
226     }
227
228     private void onMenuClicked(int action, ProgressListener listener) {
229         onMenuClicked(action, listener, false, true);
230     }
231
232     public void onMenuClicked(int action, ProgressListener listener,
233             boolean waitOnStop, boolean showDialog) {
234         int title;
235         switch (action) {
236             case R.id.action_select_all:
237                 if (mSelectionManager.inSelectAllMode()) {
238                     mSelectionManager.deSelectAll();
239                 } else {
240                     mSelectionManager.selectAll();
241                 }
242                 return;
243             case R.id.action_crop: {
244                 Intent intent = getIntentBySingleSelectedPath(CropActivity.CROP_ACTION);
245                 ((Activity) mActivity).startActivity(intent);
246                 return;
247             }
248             case R.id.action_edit: {
249                 Intent intent = getIntentBySingleSelectedPath(Intent.ACTION_EDIT)
250                         .setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
251                 ((Activity) mActivity).startActivity(Intent.createChooser(intent, null));
252                 return;
253             }
254             case R.id.action_setas: {
255                 Intent intent = getIntentBySingleSelectedPath(Intent.ACTION_ATTACH_DATA)
256                         .addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
257                 intent.putExtra("mimeType", intent.getType());
258                 Activity activity = mActivity;
259                 activity.startActivity(Intent.createChooser(
260                         intent, activity.getString(R.string.set_as)));
261                 return;
262             }
263             case R.id.action_delete:
264                 title = R.string.delete;
265                 break;
266             case R.id.action_rotate_cw:
267                 title = R.string.rotate_right;
268                 break;
269             case R.id.action_rotate_ccw:
270                 title = R.string.rotate_left;
271                 break;
272             case R.id.action_show_on_map:
273                 title = R.string.show_on_map;
274                 break;
275             default:
276                 return;
277         }
278         startAction(action, title, listener, waitOnStop, showDialog);
279     }
280
281     private class ConfirmDialogListener implements OnClickListener, OnCancelListener {
282         private final int mActionId;
283         private final ProgressListener mListener;
284
285         public ConfirmDialogListener(int actionId, ProgressListener listener) {
286             mActionId = actionId;
287             mListener = listener;
288         }
289
290         @Override
291         public void onClick(DialogInterface dialog, int which) {
292             if (which == DialogInterface.BUTTON_POSITIVE) {
293                 if (mListener != null) {
294                     mListener.onConfirmDialogDismissed(true);
295                 }
296                 onMenuClicked(mActionId, mListener);
297             } else {
298                 if (mListener != null) {
299                     mListener.onConfirmDialogDismissed(false);
300                 }
301             }
302         }
303
304         @Override
305         public void onCancel(DialogInterface dialog) {
306             if (mListener != null) {
307                 mListener.onConfirmDialogDismissed(false);
308             }
309         }
310     }
311
312     public void onMenuClicked(MenuItem menuItem, String confirmMsg,
313             final ProgressListener listener) {
314         final int action = menuItem.getItemId();
315
316         if (confirmMsg != null) {
317             if (listener != null) listener.onConfirmDialogShown();
318             ConfirmDialogListener cdl = new ConfirmDialogListener(action, listener);
319             new AlertDialog.Builder(mActivity.getAndroidContext())
320                     .setMessage(confirmMsg)
321                     .setOnCancelListener(cdl)
322                     .setPositiveButton(R.string.ok, cdl)
323                     .setNegativeButton(R.string.cancel, cdl)
324                     .create().show();
325         } else {
326             onMenuClicked(action, listener);
327         }
328     }
329
330     public void startAction(int action, int title, ProgressListener listener) {
331         startAction(action, title, listener, false, true);
332     }
333
334     public void startAction(int action, int title, ProgressListener listener,
335             boolean waitOnStop, boolean showDialog) {
336         ArrayList<Path> ids = mSelectionManager.getSelected(false);
337         stopTaskAndDismissDialog();
338
339         Activity activity = mActivity;
340         if (showDialog) {
341             mDialog = createProgressDialog(activity, title, ids.size());
342             mDialog.show();
343         } else {
344             mDialog = null;
345         }
346         MediaOperation operation = new MediaOperation(action, ids, listener);
347         mTask = mActivity.getBatchServiceThreadPoolIfAvailable().submit(operation, null);
348         mWaitOnStop = waitOnStop;
349     }
350
351     public void startSingleItemAction(int action, Path targetPath) {
352         ArrayList<Path> ids = new ArrayList<Path>(1);
353         ids.add(targetPath);
354         mDialog = null;
355         MediaOperation operation = new MediaOperation(action, ids, null);
356         mTask = mActivity.getBatchServiceThreadPoolIfAvailable().submit(operation, null);
357         mWaitOnStop = false;
358     }
359
360     public static String getMimeType(int type) {
361         switch (type) {
362             case MediaObject.MEDIA_TYPE_IMAGE :
363                 return GalleryUtils.MIME_TYPE_IMAGE;
364             case MediaObject.MEDIA_TYPE_VIDEO :
365                 return GalleryUtils.MIME_TYPE_VIDEO;
366             default: return GalleryUtils.MIME_TYPE_ALL;
367         }
368     }
369
370     private boolean execute(
371             DataManager manager, JobContext jc, int cmd, Path path) {
372         boolean result = true;
373         Log.v(TAG, "Execute cmd: " + cmd + " for " + path);
374         long startTime = System.currentTimeMillis();
375
376         switch (cmd) {
377             case R.id.action_delete:
378                 manager.delete(path);
379                 break;
380             case R.id.action_rotate_cw:
381                 manager.rotate(path, 90);
382                 break;
383             case R.id.action_rotate_ccw:
384                 manager.rotate(path, -90);
385                 break;
386             case R.id.action_toggle_full_caching: {
387                 MediaObject obj = manager.getMediaObject(path);
388                 int cacheFlag = obj.getCacheFlag();
389                 if (cacheFlag == MediaObject.CACHE_FLAG_FULL) {
390                     cacheFlag = MediaObject.CACHE_FLAG_SCREENNAIL;
391                 } else {
392                     cacheFlag = MediaObject.CACHE_FLAG_FULL;
393                 }
394                 obj.cache(cacheFlag);
395                 break;
396             }
397             case R.id.action_show_on_map: {
398                 MediaItem item = (MediaItem) manager.getMediaObject(path);
399                 double latlng[] = new double[2];
400                 item.getLatLong(latlng);
401                 if (GalleryUtils.isValidLocation(latlng[0], latlng[1])) {
402                     GalleryUtils.showOnMap(mActivity, latlng[0], latlng[1]);
403                 }
404                 break;
405             }
406             default:
407                 throw new AssertionError();
408         }
409         Log.v(TAG, "It takes " + (System.currentTimeMillis() - startTime) +
410                 " ms to execute cmd for " + path);
411         return result;
412     }
413
414     private class MediaOperation implements Job<Void> {
415         private final ArrayList<Path> mItems;
416         private final int mOperation;
417         private final ProgressListener mListener;
418
419         public MediaOperation(int operation, ArrayList<Path> items,
420                 ProgressListener listener) {
421             mOperation = operation;
422             mItems = items;
423             mListener = listener;
424         }
425
426         @Override
427         public Void run(JobContext jc) {
428             int index = 0;
429             DataManager manager = mActivity.getDataManager();
430             int result = EXECUTION_RESULT_SUCCESS;
431             try {
432                 onProgressStart(mListener);
433                 for (Path id : mItems) {
434                     if (jc.isCancelled()) {
435                         result = EXECUTION_RESULT_CANCEL;
436                         break;
437                     }
438                     if (!execute(manager, jc, mOperation, id)) {
439                         result = EXECUTION_RESULT_FAIL;
440                     }
441                     onProgressUpdate(index++, mListener);
442                 }
443             } catch (Throwable th) {
444                 Log.e(TAG, "failed to execute operation " + mOperation
445                         + " : " + th);
446             } finally {
447                onProgressComplete(result, mListener);
448             }
449             return null;
450         }
451     }
452 }