OSDN Git Service

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