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.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 {
     47         public MultiChoiceManager getMultiChoiceManager();
     48     }
     49 
     50     public interface Delegate {
     51         public SparseBooleanArray getSelectedItemPositions();
     52         public int getSelectedItemCount();
     53         public int getItemMediaType(Object item);
     54         public int getItemSupportedOperations(Object item);
     55         public ArrayList<Uri> getSubItemUrisForItem(Object item);
     56         public Uri getItemUri(Object item);
     57         public Object getItemAtPosition(int position);
     58         public Object getPathForItemAtPosition(int position);
     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 
     70     public MultiChoiceManager(Activity activity) {
     71         mContext = activity;
     72         mSelectionManager = new SelectionManager(activity);
     73     }
     74 
     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
     86     public ArrayList<Uri> getSelectedShareableUris() {
     87         return mSelectedShareableUrisArray;
     88     }
     89 
     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 
     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
    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 
    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
    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
    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
    176     public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
    177         updateSelectedTitle(mode);
    178         return false;
    179     }
    180 
    181     @Override
    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 
    191         public BulkDeleteTask(Delegate delegate, List<Object> paths) {
    192             mDelegate = delegate;
    193             mPaths = paths;
    194         }
    195 
    196         @Override
    197         protected Void doInBackground(Void... ignored) {
    198             for (Object path : mPaths) {
    199                 mDelegate.deleteItemWithPath(path);
    200             }
    201             return null;
    202         }
    203     }
    204 
    205     @Override
    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 
    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 
    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 
    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