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