summaryrefslogtreecommitdiffstats
path: root/packages/DocumentsUI/src
diff options
context:
space:
mode:
authorJeff Sharkey <jsharkey@android.com>2013-07-01 16:56:54 -0700
committerJeff Sharkey <jsharkey@android.com>2013-07-01 17:00:14 -0700
commitbe8b12e687bd10a526b1f54c2d8a52abdad15d85 (patch)
tree1ef49eac10010b487799de3cdc625d0783bfe3d5 /packages/DocumentsUI/src
parent54e55b740fef1be654c3959aee41ef5ddfa61293 (diff)
downloadframeworks_base-be8b12e687bd10a526b1f54c2d8a52abdad15d85.zip
frameworks_base-be8b12e687bd10a526b1f54c2d8a52abdad15d85.tar.gz
frameworks_base-be8b12e687bd10a526b1f54c2d8a52abdad15d85.tar.bz2
Support multi-select in storage UI.
When caller has specified that multiple documents are okay, enable multi-select action mode. Currently only allows document selection, not directories. Returns multiple documents through ClipData. Fix bug where GridView was stuck with 2 columns on tablets. Change-Id: Id49b29a86330639b56fa116d37e7f0d874980c5b
Diffstat (limited to 'packages/DocumentsUI/src')
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java89
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java50
2 files changed, 129 insertions, 10 deletions
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
index 5ba1930..bae42d5 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
@@ -29,12 +29,16 @@ import android.os.Bundle;
import android.provider.DocumentsContract;
import android.provider.DocumentsContract.DocumentColumns;
import android.text.format.DateUtils;
+import android.util.SparseBooleanArray;
+import android.view.ActionMode;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
+import android.widget.AbsListView;
+import android.widget.AbsListView.MultiChoiceModeListener;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.CursorAdapter;
@@ -44,6 +48,9 @@ import android.widget.ListView;
import android.widget.TextView;
import com.android.documentsui.DocumentsActivity.Document;
+import com.google.android.collect.Lists;
+
+import java.util.ArrayList;
/**
* Display the documents inside a single directory.
@@ -52,11 +59,12 @@ public class DirectoryFragment extends Fragment {
// TODO: show storage backend in item views when requested
// TODO: implement sorting dialog
- // TODO: support multiple selection with actionmode
private ListView mListView;
private GridView mGridView;
+ private AbsListView mCurrentView;
+
private DocumentsAdapter mAdapter;
private LoaderCallbacks<Cursor> mCallbacks;
@@ -64,16 +72,19 @@ public class DirectoryFragment extends Fragment {
private static final String EXTRA_URI = "uri";
private static final String EXTRA_MODE = "display_mode";
+ private static final String EXTRA_ALLOW_MULTIPLE = "allow_multiple";
private static final int MODE_LIST = 1;
private static final int MODE_GRID = 2;
private static final int LOADER_DOCUMENTS = 2;
- public static void show(FragmentManager fm, Uri uri, String displayName) {
+ public static void show(
+ FragmentManager fm, Uri uri, String displayName, boolean allowMultiple) {
final Bundle args = new Bundle();
args.putParcelable(EXTRA_URI, uri);
args.putInt(EXTRA_MODE, MODE_LIST);
+ args.putBoolean(EXTRA_ALLOW_MULTIPLE, allowMultiple);
final DirectoryFragment fragment = new DirectoryFragment();
fragment.setArguments(args);
@@ -100,9 +111,11 @@ public class DirectoryFragment extends Fragment {
mListView = (ListView) view.findViewById(R.id.list);
mListView.setOnItemClickListener(mItemListener);
+ mListView.setMultiChoiceModeListener(mMultiListener);
mGridView = (GridView) view.findViewById(R.id.grid);
mGridView.setOnItemClickListener(mItemListener);
+ mGridView.setMultiChoiceModeListener(mMultiListener);
mAdapter = new DocumentsAdapter(context);
updateMode();
@@ -184,13 +197,27 @@ public class DirectoryFragment extends Fragment {
mListView.setVisibility(mode == MODE_LIST ? View.VISIBLE : View.GONE);
mGridView.setVisibility(mode == MODE_GRID ? View.VISIBLE : View.GONE);
+ final int choiceMode;
+ if (getArguments().getBoolean(EXTRA_ALLOW_MULTIPLE)) {
+ choiceMode = ListView.CHOICE_MODE_MULTIPLE_MODAL;
+ } else {
+ choiceMode = ListView.CHOICE_MODE_NONE;
+ }
+
if (mode == MODE_GRID) {
mListView.setAdapter(null);
+ mListView.setChoiceMode(ListView.CHOICE_MODE_NONE);
mGridView.setAdapter(mAdapter);
+ mGridView.setColumnWidth(getResources().getDimensionPixelSize(R.dimen.grid_width));
mGridView.setNumColumns(GridView.AUTO_FIT);
+ mGridView.setChoiceMode(choiceMode);
+ mCurrentView = mGridView;
} else {
mGridView.setAdapter(null);
+ mGridView.setChoiceMode(ListView.CHOICE_MODE_NONE);
mListView.setAdapter(mAdapter);
+ mListView.setChoiceMode(choiceMode);
+ mCurrentView = mListView;
}
}
@@ -198,13 +225,69 @@ public class DirectoryFragment extends Fragment {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
final Cursor cursor = (Cursor) mAdapter.getItem(position);
-
final Uri uri = getArguments().getParcelable(EXTRA_URI);
final Document doc = Document.fromCursor(uri.getAuthority(), cursor);
((DocumentsActivity) getActivity()).onDocumentPicked(doc);
}
};
+ private MultiChoiceModeListener mMultiListener = new MultiChoiceModeListener() {
+ @Override
+ public boolean onCreateActionMode(ActionMode mode, Menu menu) {
+ mode.getMenuInflater().inflate(R.menu.mode_directory, menu);
+ return true;
+ }
+
+ @Override
+ public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
+ return true;
+ }
+
+ @Override
+ public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
+ if (item.getItemId() == R.id.menu_open) {
+ final Uri uri = getArguments().getParcelable(EXTRA_URI);
+ final SparseBooleanArray checked = mCurrentView.getCheckedItemPositions();
+ final ArrayList<Document> docs = Lists.newArrayList();
+
+ final int size = checked.size();
+ for (int i = 0; i < size; i++) {
+ if (checked.valueAt(i)) {
+ final Cursor cursor = (Cursor) mAdapter.getItem(checked.keyAt(i));
+ docs.add(Document.fromCursor(uri.getAuthority(), cursor));
+ }
+ }
+
+ ((DocumentsActivity) getActivity()).onDocumentsPicked(docs);
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public void onDestroyActionMode(ActionMode mode) {
+ // ignored
+ }
+
+ @Override
+ public void onItemCheckedStateChanged(
+ ActionMode mode, int position, long id, boolean checked) {
+ if (checked) {
+ final Cursor cursor = (Cursor) mAdapter.getItem(position);
+ final String mimeType = getCursorString(cursor, DocumentColumns.MIME_TYPE);
+
+ // Directories cannot be checked
+ if (DocumentsContract.MIME_TYPE_DIRECTORY.equals(mimeType)) {
+ mCurrentView.setItemChecked(position, false);
+ }
+ }
+
+ mode.setTitle(getResources()
+ .getString(R.string.mode_selected_count, mCurrentView.getCheckedItemCount()));
+ }
+ };
+
private boolean getSupportsCreate() {
return (mFlags & DocumentsContract.FLAG_SUPPORTS_CREATE) != 0;
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
index c83edc4..ca4ea82 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
@@ -24,6 +24,8 @@ import android.app.Activity;
import android.app.FragmentManager;
import android.app.FragmentManager.BackStackEntry;
import android.app.FragmentManager.OnBackStackChangedListener;
+import android.content.ClipData;
+import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
@@ -44,6 +46,9 @@ import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;
+import java.util.Arrays;
+import java.util.List;
+
public class DocumentsActivity extends Activity {
private static final String TAG = "Documents";
@@ -54,6 +59,9 @@ public class DocumentsActivity extends Activity {
private static final int MODE_CREATE = 2;
private int mMode;
+ private boolean mAllowMultiple;
+ private String[] mAcceptMimes;
+
private boolean mIgnoreNextNavigation;
private Uri mCurrentDir;
@@ -63,11 +71,20 @@ public class DocumentsActivity extends Activity {
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
- final String action = getIntent().getAction();
+ final Intent intent = getIntent();
+ final String action = intent.getAction();
if (Intent.ACTION_OPEN_DOCUMENT.equals(action)) {
mMode = MODE_OPEN;
+ mAllowMultiple = intent.getBooleanExtra(Intent.EXTRA_ALLOW_MULTIPLE, false);
} else if (Intent.ACTION_CREATE_DOCUMENT.equals(action)) {
mMode = MODE_CREATE;
+ mAllowMultiple = false;
+ }
+
+ if (intent.hasExtra(Intent.EXTRA_MIME_TYPES)) {
+ mAcceptMimes = intent.getStringArrayExtra(Intent.EXTRA_MIME_TYPES);
+ } else {
+ mAcceptMimes = new String[] { intent.getType() };
}
setResult(Activity.RESULT_CANCELED);
@@ -208,14 +225,14 @@ public class DocumentsActivity extends Activity {
final Uri uri = DocumentsContract.buildDocumentUri(
info.authority, DocumentsContract.ROOT_GUID);
final CharSequence displayName = info.loadLabel(getPackageManager());
- DirectoryFragment.show(getFragmentManager(), uri, displayName.toString());
+ DirectoryFragment.show(getFragmentManager(), uri, displayName.toString(), mAllowMultiple);
}
public void onDocumentPicked(Document doc) {
final FragmentManager fm = getFragmentManager();
if (DocumentsContract.MIME_TYPE_DIRECTORY.equals(doc.mimeType)) {
// Nested directory picked, recurse using new fragment
- DirectoryFragment.show(fm, doc.uri, doc.displayName);
+ DirectoryFragment.show(fm, doc.uri, doc.displayName, mAllowMultiple);
} else if (mMode == MODE_OPEN) {
// Explicit file picked, return
onFinished(doc.uri);
@@ -225,16 +242,35 @@ public class DocumentsActivity extends Activity {
}
}
+ public void onDocumentsPicked(List<Document> docs) {
+ final int size = docs.size();
+ final Uri[] uris = new Uri[size];
+ for (int i = 0; i < size; i++) {
+ uris[i] = docs.get(i).uri;
+ }
+ onFinished(uris);
+ }
+
public void onSaveRequested(String mimeType, String displayName) {
// TODO: create file, confirming before overwriting
- onFinished(null);
+ final Uri uri = null;
+ onFinished(uri);
}
- private void onFinished(Uri uri) {
- Log.d(TAG, "onFinished() " + uri);
+ private void onFinished(Uri... uris) {
+ Log.d(TAG, "onFinished() " + Arrays.toString(uris));
final Intent intent = new Intent();
- intent.setData(uri);
+ if (uris.length == 1) {
+ intent.setData(uris[0]);
+ } else if (uris.length > 1) {
+ final ContentResolver resolver = getContentResolver();
+ final ClipData clipData = new ClipData(null, mAcceptMimes, new ClipData.Item(uris[0]));
+ for (int i = 1; i < uris.length; i++) {
+ clipData.addItem(new ClipData.Item(uris[i]));
+ }
+ intent.setClipData(clipData);
+ }
intent.addFlags(
Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_PERSIST_GRANT_URI_PERMISSION);