Home | History | Annotate | Download | only in photos
      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 {
     48         public MultiChoiceManager getMultiChoiceManager();
     49     }
     50 
     51     public interface Delegate {
     52         public SparseBooleanArray getSelectedItemPositions();
     53         public int getSelectedItemCount();
     54         public int getItemMediaType(Object item);
     55         public int getItemSupportedOperations(Object item);
     56         public ArrayList<Uri> getSubItemUrisForItem(Object item);
     57         public Uri getItemUri(Object item);
     58         public Object getItemAtPosition(int position);
     59         public Object getPathForItemAtPosition(int position);
     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 
     71     public MultiChoiceManager(Activity activity) {
     72         mContext = activity;
     73         mSelectionManager = new SelectionManager(activity);
     74     }
     75 
     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
     87     public ArrayList<Uri> getSelectedShareableUris() {
     88         return mSelectedShareableUrisArray;
     89     }
     90 
     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 
     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
    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 
    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         MenuItem setAsItem = menu.findItem(R.id.menu_set_as);
    141 
    142         editItem.setVisible((supportedOperations & MediaObject.SUPPORT_EDIT) > 0);
    143         deleteItem.setVisible((supportedOperations & MediaObject.SUPPORT_DELETE) > 0);
    144         shareItem.setVisible((supportedOperations & MediaObject.SUPPORT_SHARE) > 0);
    145         cropItem.setVisible((supportedOperations & MediaObject.SUPPORT_CROP) > 0);
    146         trimItem.setVisible((supportedOperations & MediaObject.SUPPORT_TRIM) > 0);
    147         muteItem.setVisible((supportedOperations & MediaObject.SUPPORT_MUTE) > 0);
    148         setAsItem.setVisible((supportedOperations & MediaObject.SUPPORT_SETAS) > 0);
    149     }
    150 
    151     @Override
    152     public boolean onCreateActionMode(ActionMode mode, Menu menu) {
    153         mSelectionManager.setSelectedUriSource(this);
    154         mActionMode = mode;
    155         MenuInflater inflater = mode.getMenuInflater();
    156         inflater.inflate(R.menu.gallery_multiselect, menu);
    157         MenuItem menuItem = menu.findItem(R.id.menu_share);
    158         mShareActionProvider = (ShareActionProvider) menuItem.getActionProvider();
    159         mShareActionProvider.setOnShareTargetSelectedListener(this);
    160         updateSelectedTitle(mode);
    161         return true;
    162     }
    163 
    164     @Override
    165     public void onDestroyActionMode(ActionMode mode) {
    166         // onDestroyActionMode gets called when the share target was selected,
    167         // but apparently before the ArrayList is serialized in the intent
    168         // so we can't clear the old one here.
    169         mSelectedShareableUrisArray = new ArrayList<Uri>();
    170         mSelectionManager.onClearSelection();
    171         mSelectionManager.setSelectedUriSource(null);
    172         mShareActionProvider = null;
    173         mActionMode = null;
    174     }
    175 
    176     @Override
    177     public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
    178         updateSelectedTitle(mode);
    179         return false;
    180     }
    181 
    182     @Override
    183     public boolean onShareTargetSelected(ShareActionProvider provider, Intent intent) {
    184         mActionMode.finish();
    185         return false;
    186     }
    187 
    188     private static class BulkDeleteTask extends AsyncTask<Void, Void, Void> {
    189         private Delegate mDelegate;
    190         private List<Object> mPaths;
    191 
    192         public BulkDeleteTask(Delegate delegate, List<Object> paths) {
    193             mDelegate = delegate;
    194             mPaths = paths;
    195         }
    196 
    197         @Override
    198         protected Void doInBackground(Void... ignored) {
    199             for (Object path : mPaths) {
    200                 mDelegate.deleteItemWithPath(path);
    201             }
    202             return null;
    203         }
    204     }
    205 
    206     @Override
    207     public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
    208         int actionItemId = item.getItemId();
    209         switch (actionItemId) {
    210             case R.id.menu_delete:
    211                 BulkDeleteTask deleteTask = new BulkDeleteTask(mDelegate,
    212                         getPathsForSelectedItems());
    213                 deleteTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
    214                 mode.finish();
    215                 return true;
    216             case R.id.menu_edit:
    217             case R.id.menu_crop:
    218             case R.id.menu_trim:
    219             case R.id.menu_mute:
    220             case R.id.menu_set_as:
    221                 singleItemAction(getSelectedItem(), actionItemId);
    222                 mode.finish();
    223                 return true;
    224             default:
    225                 return false;
    226         }
    227     }
    228 
    229     private void singleItemAction(Object item, int actionItemId) {
    230         Intent intent = new Intent();
    231         String mime = getItemMimetype(item);
    232         Uri uri = mDelegate.getItemUri(item);
    233         switch (actionItemId) {
    234             case R.id.menu_edit:
    235                 intent.setDataAndType(uri, mime)
    236                       .setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
    237                       .setAction(Intent.ACTION_EDIT);
    238                 mContext.startActivity(Intent.createChooser(intent, null));
    239                 return;
    240             case R.id.menu_crop:
    241                 intent.setDataAndType(uri, mime)
    242                       .setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
    243                       .setAction(CropActivity.CROP_ACTION)
    244                       .setClass(mContext, FilterShowActivity.class);
    245                 mContext.startActivity(intent);
    246                 return;
    247             case R.id.menu_trim:
    248                 intent.setData(uri)
    249                       .setClass(mContext, TrimVideo.class);
    250                 mContext.startActivity(intent);
    251                 return;
    252             case R.id.menu_mute:
    253                 /* TODO need a way to get the file path of an item
    254                 MuteVideo muteVideo = new MuteVideo(filePath,
    255                         uri, (Activity) mContext);
    256                 muteVideo.muteInBackground();
    257                 */
    258                 return;
    259             case R.id.menu_set_as:
    260                 intent.setDataAndType(uri, mime)
    261                       .setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
    262                       .setAction(Intent.ACTION_ATTACH_DATA)
    263                       .putExtra("mimeType", mime);
    264                 mContext.startActivity(Intent.createChooser(
    265                         intent, mContext.getString(R.string.set_as)));
    266                 return;
    267             default:
    268                 return;
    269         }
    270     }
    271 
    272     private List<Object> getPathsForSelectedItems() {
    273         List<Object> paths = new ArrayList<Object>();
    274         SparseBooleanArray selected = mDelegate.getSelectedItemPositions();
    275         for (int i = 0; i < selected.size(); i++) {
    276             if (selected.valueAt(i)) {
    277                 paths.add(mDelegate.getPathForItemAtPosition(i));
    278             }
    279         }
    280         return paths;
    281     }
    282 
    283     public Object getSelectedItem() {
    284         if (mDelegate.getSelectedItemCount() != 1) {
    285             return null;
    286         }
    287         SparseBooleanArray selected = mDelegate.getSelectedItemPositions();
    288         for (int i = 0; i < selected.size(); i++) {
    289             if (selected.valueAt(i)) {
    290                 return mDelegate.getItemAtPosition(selected.keyAt(i));
    291             }
    292         }
    293         return null;
    294     }
    295 }
    296