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