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