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