• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2013 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.photos;
18 
19 import android.app.Activity;
20 import android.content.Context;
21 import android.content.Intent;
22 import android.net.Uri;
23 import android.os.AsyncTask;
24 import android.provider.MediaStore.Files.FileColumns;
25 import android.util.SparseBooleanArray;
26 import android.view.ActionMode;
27 import android.view.Menu;
28 import android.view.MenuInflater;
29 import android.view.MenuItem;
30 import android.widget.AbsListView.MultiChoiceModeListener;
31 import android.widget.ShareActionProvider;
32 import android.widget.ShareActionProvider.OnShareTargetSelectedListener;
33 
34 import com.android.gallery3d.R;
35 import com.android.gallery3d.app.TrimVideo;
36 import com.android.gallery3d.data.MediaObject;
37 import com.android.gallery3d.filtershow.FilterShowActivity;
38 import com.android.gallery3d.util.GalleryUtils;
39 
40 import java.util.ArrayList;
41 import java.util.List;
42 
43 public class MultiChoiceManager implements MultiChoiceModeListener,
44     OnShareTargetSelectedListener, SelectionManager.SelectedUriSource {
45 
46     public interface Provider {
getMultiChoiceManager()47         public MultiChoiceManager getMultiChoiceManager();
48     }
49 
50     public interface Delegate {
getSelectedItemPositions()51         public SparseBooleanArray getSelectedItemPositions();
getSelectedItemCount()52         public int getSelectedItemCount();
getItemMediaType(Object item)53         public int getItemMediaType(Object item);
getItemSupportedOperations(Object item)54         public int getItemSupportedOperations(Object item);
getSubItemUrisForItem(Object item)55         public ArrayList<Uri> getSubItemUrisForItem(Object item);
getItemUri(Object item)56         public Uri getItemUri(Object item);
getItemAtPosition(int position)57         public Object getItemAtPosition(int position);
getPathForItemAtPosition(int position)58         public Object getPathForItemAtPosition(int position);
deleteItemWithPath(Object itemPath)59         public void deleteItemWithPath(Object itemPath);
60     }
61 
62     private SelectionManager mSelectionManager;
63     private ShareActionProvider mShareActionProvider;
64     private ActionMode mActionMode;
65     private Context mContext;
66     private Delegate mDelegate;
67 
68     private ArrayList<Uri> mSelectedShareableUrisArray = new ArrayList<Uri>();
69 
MultiChoiceManager(Activity activity)70     public MultiChoiceManager(Activity activity) {
71         mContext = activity;
72         mSelectionManager = new SelectionManager(activity);
73     }
74 
setDelegate(Delegate delegate)75     public void setDelegate(Delegate delegate) {
76         if (mDelegate == delegate) {
77             return;
78         }
79         if (mActionMode != null) {
80             mActionMode.finish();
81         }
82         mDelegate = delegate;
83     }
84 
85     @Override
getSelectedShareableUris()86     public ArrayList<Uri> getSelectedShareableUris() {
87         return mSelectedShareableUrisArray;
88     }
89 
updateSelectedTitle(ActionMode mode)90     private void updateSelectedTitle(ActionMode mode) {
91         int count = mDelegate.getSelectedItemCount();
92         mode.setTitle(mContext.getResources().getQuantityString(
93                 R.plurals.number_of_items_selected, count, count));
94     }
95 
getItemMimetype(Object item)96     private String getItemMimetype(Object item) {
97         int type = mDelegate.getItemMediaType(item);
98         if (type == FileColumns.MEDIA_TYPE_IMAGE) {
99             return GalleryUtils.MIME_TYPE_IMAGE;
100         } else if (type == FileColumns.MEDIA_TYPE_VIDEO) {
101             return GalleryUtils.MIME_TYPE_VIDEO;
102         } else {
103             return GalleryUtils.MIME_TYPE_ALL;
104         }
105     }
106 
107     @Override
onItemCheckedStateChanged(ActionMode mode, int position, long id, boolean checked)108     public void onItemCheckedStateChanged(ActionMode mode, int position, long id,
109             boolean checked) {
110         updateSelectedTitle(mode);
111         Object item = mDelegate.getItemAtPosition(position);
112 
113         int supported = mDelegate.getItemSupportedOperations(item);
114 
115         if ((supported & MediaObject.SUPPORT_SHARE) > 0) {
116             ArrayList<Uri> subItems = mDelegate.getSubItemUrisForItem(item);
117             if (checked) {
118                 mSelectedShareableUrisArray.addAll(subItems);
119             } else {
120                 mSelectedShareableUrisArray.removeAll(subItems);
121             }
122         }
123 
124         mSelectionManager.onItemSelectedStateChanged(mShareActionProvider,
125                 mDelegate.getItemMediaType(item),
126                 supported,
127                 checked);
128         updateActionItemVisibilities(mode.getMenu(),
129                 mSelectionManager.getSupportedOperations());
130     }
131 
updateActionItemVisibilities(Menu menu, int supportedOperations)132     private void updateActionItemVisibilities(Menu menu, int supportedOperations) {
133         MenuItem editItem = menu.findItem(R.id.menu_edit);
134         MenuItem deleteItem = menu.findItem(R.id.menu_delete);
135         MenuItem shareItem = menu.findItem(R.id.menu_share);
136         MenuItem cropItem = menu.findItem(R.id.menu_crop);
137         MenuItem trimItem = menu.findItem(R.id.menu_trim);
138         MenuItem muteItem = menu.findItem(R.id.menu_mute);
139         MenuItem setAsItem = menu.findItem(R.id.menu_set_as);
140 
141         editItem.setVisible((supportedOperations & MediaObject.SUPPORT_EDIT) > 0);
142         deleteItem.setVisible((supportedOperations & MediaObject.SUPPORT_DELETE) > 0);
143         shareItem.setVisible((supportedOperations & MediaObject.SUPPORT_SHARE) > 0);
144         cropItem.setVisible((supportedOperations & MediaObject.SUPPORT_CROP) > 0);
145         trimItem.setVisible((supportedOperations & MediaObject.SUPPORT_TRIM) > 0);
146         muteItem.setVisible((supportedOperations & MediaObject.SUPPORT_MUTE) > 0);
147         setAsItem.setVisible((supportedOperations & MediaObject.SUPPORT_SETAS) > 0);
148     }
149 
150     @Override
onCreateActionMode(ActionMode mode, Menu menu)151     public boolean onCreateActionMode(ActionMode mode, Menu menu) {
152         mSelectionManager.setSelectedUriSource(this);
153         mActionMode = mode;
154         MenuInflater inflater = mode.getMenuInflater();
155         inflater.inflate(R.menu.gallery_multiselect, menu);
156         MenuItem menuItem = menu.findItem(R.id.menu_share);
157         mShareActionProvider = (ShareActionProvider) menuItem.getActionProvider();
158         mShareActionProvider.setOnShareTargetSelectedListener(this);
159         updateSelectedTitle(mode);
160         return true;
161     }
162 
163     @Override
onDestroyActionMode(ActionMode mode)164     public void onDestroyActionMode(ActionMode mode) {
165         // onDestroyActionMode gets called when the share target was selected,
166         // but apparently before the ArrayList is serialized in the intent
167         // so we can't clear the old one here.
168         mSelectedShareableUrisArray = new ArrayList<Uri>();
169         mSelectionManager.onClearSelection();
170         mSelectionManager.setSelectedUriSource(null);
171         mShareActionProvider = null;
172         mActionMode = null;
173     }
174 
175     @Override
onPrepareActionMode(ActionMode mode, Menu menu)176     public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
177         updateSelectedTitle(mode);
178         return false;
179     }
180 
181     @Override
onShareTargetSelected(ShareActionProvider provider, Intent intent)182     public boolean onShareTargetSelected(ShareActionProvider provider, Intent intent) {
183         mActionMode.finish();
184         return false;
185     }
186 
187     private static class BulkDeleteTask extends AsyncTask<Void, Void, Void> {
188         private Delegate mDelegate;
189         private List<Object> mPaths;
190 
BulkDeleteTask(Delegate delegate, List<Object> paths)191         public BulkDeleteTask(Delegate delegate, List<Object> paths) {
192             mDelegate = delegate;
193             mPaths = paths;
194         }
195 
196         @Override
doInBackground(Void... ignored)197         protected Void doInBackground(Void... ignored) {
198             for (Object path : mPaths) {
199                 mDelegate.deleteItemWithPath(path);
200             }
201             return null;
202         }
203     }
204 
205     @Override
onActionItemClicked(ActionMode mode, MenuItem item)206     public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
207         int actionItemId = item.getItemId();
208         switch (actionItemId) {
209             case R.id.menu_delete:
210                 BulkDeleteTask deleteTask = new BulkDeleteTask(mDelegate,
211                         getPathsForSelectedItems());
212                 deleteTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
213                 mode.finish();
214                 return true;
215             case R.id.menu_edit:
216             case R.id.menu_crop:
217             case R.id.menu_trim:
218             case R.id.menu_mute:
219             case R.id.menu_set_as:
220                 singleItemAction(getSelectedItem(), actionItemId);
221                 mode.finish();
222                 return true;
223             default:
224                 return false;
225         }
226     }
227 
singleItemAction(Object item, int actionItemId)228     private void singleItemAction(Object item, int actionItemId) {
229         Intent intent = new Intent();
230         String mime = getItemMimetype(item);
231         Uri uri = mDelegate.getItemUri(item);
232         switch (actionItemId) {
233             case R.id.menu_edit:
234                 intent.setDataAndType(uri, mime)
235                       .setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
236                       .setAction(Intent.ACTION_EDIT);
237                 mContext.startActivity(Intent.createChooser(intent, null));
238                 return;
239             case R.id.menu_crop:
240                 intent.setDataAndType(uri, mime)
241                       .setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
242                       .setAction(FilterShowActivity.CROP_ACTION)
243                       .setClass(mContext, FilterShowActivity.class);
244                 mContext.startActivity(intent);
245                 return;
246             case R.id.menu_trim:
247                 intent.setData(uri)
248                       .setClass(mContext, TrimVideo.class);
249                 mContext.startActivity(intent);
250                 return;
251             case R.id.menu_mute:
252                 /* TODO need a way to get the file path of an item
253                 MuteVideo muteVideo = new MuteVideo(filePath,
254                         uri, (Activity) mContext);
255                 muteVideo.muteInBackground();
256                 */
257                 return;
258             case R.id.menu_set_as:
259                 intent.setDataAndType(uri, mime)
260                       .setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
261                       .setAction(Intent.ACTION_ATTACH_DATA)
262                       .putExtra("mimeType", mime);
263                 mContext.startActivity(Intent.createChooser(
264                         intent, mContext.getString(R.string.set_as)));
265                 return;
266             default:
267                 return;
268         }
269     }
270 
getPathsForSelectedItems()271     private List<Object> getPathsForSelectedItems() {
272         List<Object> paths = new ArrayList<Object>();
273         SparseBooleanArray selected = mDelegate.getSelectedItemPositions();
274         for (int i = 0; i < selected.size(); i++) {
275             if (selected.valueAt(i)) {
276                 paths.add(mDelegate.getPathForItemAtPosition(i));
277             }
278         }
279         return paths;
280     }
281 
getSelectedItem()282     public Object getSelectedItem() {
283         if (mDelegate.getSelectedItemCount() != 1) {
284             return null;
285         }
286         SparseBooleanArray selected = mDelegate.getSelectedItemPositions();
287         for (int i = 0; i < selected.size(); i++) {
288             if (selected.valueAt(i)) {
289                 return mDelegate.getItemAtPosition(selected.keyAt(i));
290             }
291         }
292         return null;
293     }
294 }
295