Loading core/java/android/provider/DocumentsContract.java +0 −1 Original line number Diff line number Diff line Loading @@ -38,7 +38,6 @@ import libcore.io.IoUtils; import java.io.FileDescriptor; import java.io.IOException; import java.io.InputStream; import java.util.List; /** Loading packages/DocumentsUI/AndroidManifest.xml +9 −0 Original line number Diff line number Diff line Loading @@ -4,6 +4,7 @@ <uses-permission android:name="android.permission.MANAGE_DOCUMENTS" /> <application android:name=".DocumentsApplication" android:label="@string/app_label" android:supportsRtl="true"> Loading Loading @@ -51,6 +52,14 @@ android:authorities="com.android.documentsui.recents" android:exported="false" /> <receiver android:name=".DocumentChangedReceiver"> <intent-filter> <action android:name="android.provider.action.DOCUMENT_CHANGED" /> <data android:mimeType="vnd.android.cursor.dir/root" /> <data android:mimeType="vnd.android.cursor.item/root" /> </intent-filter> </receiver> <!-- TODO: remove when we have real clients --> <activity android:name=".TestActivity" android:enabled="false"> <intent-filter> Loading packages/DocumentsUI/res/menu/mode_directory.xml +10 −0 Original line number Diff line number Diff line Loading @@ -19,4 +19,14 @@ android:id="@+id/menu_open" android:title="@string/menu_open" android:showAsAction="always" /> <item android:id="@+id/menu_share" android:icon="@android:drawable/ic_menu_share" android:title="@string/menu_share" android:showAsAction="always" /> <item android:id="@+id/menu_delete" android:icon="@android:drawable/ic_menu_delete" android:title="@string/menu_delete" android:showAsAction="always" /> </menu> packages/DocumentsUI/res/values/strings.xml +5 −0 Original line number Diff line number Diff line Loading @@ -29,6 +29,8 @@ <string name="menu_open">Open</string> <string name="menu_save">Save</string> <string name="menu_share">Share</string> <string name="menu_delete">Delete</string> <string name="mode_selected_count"><xliff:g id="count" example="3">%1$d</xliff:g> selected</string> Loading @@ -55,4 +57,7 @@ <string name="empty">No items</string> <string name="toast_no_application">Can\'t open file</string> <string name="toast_failed_delete">Unable to delete some documents</string> </resources> packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java +115 −30 Original line number Diff line number Diff line Loading @@ -17,12 +17,20 @@ package com.android.documentsui; import static com.android.documentsui.DocumentsActivity.TAG; import static com.android.documentsui.DocumentsActivity.DisplayState.ACTION_MANAGE; import static com.android.documentsui.DocumentsActivity.DisplayState.MODE_GRID; import static com.android.documentsui.DocumentsActivity.DisplayState.MODE_LIST; import static com.android.documentsui.DocumentsActivity.DisplayState.SORT_ORDER_DATE; import static com.android.documentsui.DocumentsActivity.DisplayState.SORT_ORDER_NAME; import static com.android.documentsui.DocumentsActivity.DisplayState.SORT_ORDER_SIZE; import android.app.Fragment; import android.app.FragmentManager; import android.app.FragmentTransaction; import android.app.LoaderManager.LoaderCallbacks; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.Loader; import android.graphics.Bitmap; import android.graphics.Point; Loading Loading @@ -50,6 +58,7 @@ import android.widget.GridView; import android.widget.ImageView; import android.widget.ListView; import android.widget.TextView; import android.widget.Toast; import com.android.documentsui.DocumentsActivity.DisplayState; import com.android.documentsui.model.Document; Loading @@ -57,7 +66,6 @@ import com.android.documentsui.model.Root; import com.android.internal.util.Predicate; import com.google.android.collect.Lists; import java.text.DateFormat; import java.util.ArrayList; import java.util.Comparator; import java.util.List; Loading Loading @@ -167,11 +175,11 @@ public class DirectoryFragment extends Fragment { } final Comparator<Document> sortOrder; if (state.sortOrder == DisplayState.SORT_ORDER_DATE || mType == TYPE_RECENT_OPEN) { if (state.sortOrder == SORT_ORDER_DATE || mType == TYPE_RECENT_OPEN) { sortOrder = new Document.DateComparator(); } else if (state.sortOrder == DisplayState.SORT_ORDER_NAME) { } else if (state.sortOrder == SORT_ORDER_NAME) { sortOrder = new Document.NameComparator(); } else if (state.sortOrder == DisplayState.SORT_ORDER_SIZE) { } else if (state.sortOrder == SORT_ORDER_SIZE) { sortOrder = new Document.SizeComparator(); } else { throw new IllegalArgumentException("Unknown sort order " + state.sortOrder); Loading Loading @@ -216,8 +224,8 @@ public class DirectoryFragment extends Fragment { mListView.smoothScrollToPosition(0); mGridView.smoothScrollToPosition(0); mListView.setVisibility(state.mode == DisplayState.MODE_LIST ? View.VISIBLE : View.GONE); mGridView.setVisibility(state.mode == DisplayState.MODE_GRID ? View.VISIBLE : View.GONE); mListView.setVisibility(state.mode == MODE_LIST ? View.VISIBLE : View.GONE); mGridView.setVisibility(state.mode == MODE_GRID ? View.VISIBLE : View.GONE); final int choiceMode; if (state.allowMultiple) { Loading @@ -227,7 +235,7 @@ public class DirectoryFragment extends Fragment { } final int thumbSize; if (state.mode == DisplayState.MODE_GRID) { if (state.mode == MODE_GRID) { thumbSize = getResources().getDimensionPixelSize(R.dimen.grid_width); mListView.setAdapter(null); mListView.setChoiceMode(ListView.CHOICE_MODE_NONE); Loading @@ -236,7 +244,7 @@ public class DirectoryFragment extends Fragment { mGridView.setNumColumns(GridView.AUTO_FIT); mGridView.setChoiceMode(choiceMode); mCurrentView = mGridView; } else if (state.mode == DisplayState.MODE_LIST) { } else if (state.mode == MODE_LIST) { thumbSize = getResources().getDimensionPixelSize(android.R.dimen.app_icon_size); mGridView.setAdapter(null); mGridView.setChoiceMode(ListView.CHOICE_MODE_NONE); Loading Loading @@ -269,16 +277,24 @@ public class DirectoryFragment extends Fragment { @Override public boolean onPrepareActionMode(ActionMode mode, Menu menu) { final DisplayState state = getDisplayState(DirectoryFragment.this); final MenuItem open = menu.findItem(R.id.menu_open); final MenuItem share = menu.findItem(R.id.menu_share); final MenuItem delete = menu.findItem(R.id.menu_delete); final boolean manageMode = state.action == ACTION_MANAGE; open.setVisible(!manageMode); share.setVisible(manageMode); delete.setVisible(manageMode); 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)) { Loading @@ -287,8 +303,19 @@ public class DirectoryFragment extends Fragment { } } ((DocumentsActivity) getActivity()).onDocumentsPicked(docs); final int id = item.getItemId(); if (id == R.id.menu_open) { DocumentsActivity.get(DirectoryFragment.this).onDocumentsPicked(docs); return true; } else if (id == R.id.menu_share) { onShareDocuments(docs); return true; } else if (id == R.id.menu_delete) { onDeleteDocuments(docs); return true; } else { return false; } Loading @@ -315,6 +342,58 @@ public class DirectoryFragment extends Fragment { } }; private void onShareDocuments(List<Document> docs) { final ArrayList<Uri> uris = Lists.newArrayList(); for (Document doc : docs) { uris.add(doc.uri); } final Intent intent; if (uris.size() > 1) { intent = new Intent(Intent.ACTION_SEND_MULTIPLE); intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); intent.addCategory(Intent.CATEGORY_DEFAULT); // TODO: find common mimetype intent.setType("*/*"); intent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, uris); } else { intent = new Intent(Intent.ACTION_SEND); intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); intent.addCategory(Intent.CATEGORY_DEFAULT); intent.setData(uris.get(0)); } startActivity(intent); } private void onDeleteDocuments(List<Document> docs) { final Context context = getActivity(); final ContentResolver resolver = context.getContentResolver(); boolean hadTrouble = false; for (Document doc : docs) { if (!doc.isDeleteSupported()) { Log.w(TAG, "Skipping " + doc); hadTrouble = true; continue; } try { if (resolver.delete(doc.uri, null, null) != 1) { Log.w(TAG, "Failed to delete " + doc); hadTrouble = true; } } catch (Exception e) { Log.w(TAG, "Failed to delete " + doc + ": " + e); hadTrouble = true; } } if (hadTrouble) { Toast.makeText(context, R.string.toast_failed_delete, Toast.LENGTH_SHORT).show(); } } private static DisplayState getDisplayState(Fragment fragment) { return ((DocumentsActivity) fragment.getActivity()).getDisplayState(); } Loading Loading @@ -342,11 +421,15 @@ public class DirectoryFragment extends Fragment { final Context context = parent.getContext(); final DisplayState state = getDisplayState(DirectoryFragment.this); final RootsCache roots = DocumentsApplication.getRootsCache(context); final ThumbnailCache thumbs = DocumentsApplication.getThumbnailsCache( context, mThumbSize); if (convertView == null) { final LayoutInflater inflater = LayoutInflater.from(context); if (state.mode == DisplayState.MODE_LIST) { if (state.mode == MODE_LIST) { convertView = inflater.inflate(R.layout.item_doc_list, parent, false); } else if (state.mode == DisplayState.MODE_GRID) { } else if (state.mode == MODE_GRID) { convertView = inflater.inflate(R.layout.item_doc_grid, parent, false); } else { throw new IllegalStateException(); Loading @@ -369,7 +452,7 @@ public class DirectoryFragment extends Fragment { } if (doc.isThumbnailSupported()) { final Bitmap cachedResult = ThumbnailCache.get(context).get(doc.uri); final Bitmap cachedResult = thumbs.get(doc.uri); if (cachedResult != null) { icon.setImageBitmap(cachedResult); } else { Loading @@ -379,7 +462,7 @@ public class DirectoryFragment extends Fragment { task.execute(doc.uri); } } else { icon.setImageDrawable(RootsCache.resolveDocumentIcon( icon.setImageDrawable(roots.resolveDocumentIcon( context, doc.uri.getAuthority(), doc.mimeType)); } Loading @@ -394,7 +477,7 @@ public class DirectoryFragment extends Fragment { summary.setVisibility(View.INVISIBLE); } } else if (mType == TYPE_RECENT_OPEN) { final Root root = RootsCache.findRoot(context, doc); final Root root = roots.findRoot(doc); icon1.setVisibility(View.VISIBLE); icon1.setImageDrawable(root.icon); summary.setText(root.getDirectoryString()); Loading Loading @@ -444,11 +527,11 @@ public class DirectoryFragment extends Fragment { private static class ThumbnailAsyncTask extends AsyncTask<Uri, Void, Bitmap> { private final ImageView mTarget; private final Point mSize; private final Point mThumbSize; public ThumbnailAsyncTask(ImageView target, Point size) { public ThumbnailAsyncTask(ImageView target, Point thumbSize) { mTarget = target; mSize = size; mThumbSize = thumbSize; } @Override Loading @@ -464,9 +547,11 @@ public class DirectoryFragment extends Fragment { Bitmap result = null; try { result = DocumentsContract.getThumbnail( context.getContentResolver(), uri, mSize); context.getContentResolver(), uri, mThumbSize); if (result != null) { ThumbnailCache.get(context).put(uri, result); final ThumbnailCache thumbs = DocumentsApplication.getThumbnailsCache( context, mThumbSize); thumbs.put(uri, result); } } catch (Exception e) { Log.w(TAG, "Failed to load thumbnail: " + e); Loading Loading
core/java/android/provider/DocumentsContract.java +0 −1 Original line number Diff line number Diff line Loading @@ -38,7 +38,6 @@ import libcore.io.IoUtils; import java.io.FileDescriptor; import java.io.IOException; import java.io.InputStream; import java.util.List; /** Loading
packages/DocumentsUI/AndroidManifest.xml +9 −0 Original line number Diff line number Diff line Loading @@ -4,6 +4,7 @@ <uses-permission android:name="android.permission.MANAGE_DOCUMENTS" /> <application android:name=".DocumentsApplication" android:label="@string/app_label" android:supportsRtl="true"> Loading Loading @@ -51,6 +52,14 @@ android:authorities="com.android.documentsui.recents" android:exported="false" /> <receiver android:name=".DocumentChangedReceiver"> <intent-filter> <action android:name="android.provider.action.DOCUMENT_CHANGED" /> <data android:mimeType="vnd.android.cursor.dir/root" /> <data android:mimeType="vnd.android.cursor.item/root" /> </intent-filter> </receiver> <!-- TODO: remove when we have real clients --> <activity android:name=".TestActivity" android:enabled="false"> <intent-filter> Loading
packages/DocumentsUI/res/menu/mode_directory.xml +10 −0 Original line number Diff line number Diff line Loading @@ -19,4 +19,14 @@ android:id="@+id/menu_open" android:title="@string/menu_open" android:showAsAction="always" /> <item android:id="@+id/menu_share" android:icon="@android:drawable/ic_menu_share" android:title="@string/menu_share" android:showAsAction="always" /> <item android:id="@+id/menu_delete" android:icon="@android:drawable/ic_menu_delete" android:title="@string/menu_delete" android:showAsAction="always" /> </menu>
packages/DocumentsUI/res/values/strings.xml +5 −0 Original line number Diff line number Diff line Loading @@ -29,6 +29,8 @@ <string name="menu_open">Open</string> <string name="menu_save">Save</string> <string name="menu_share">Share</string> <string name="menu_delete">Delete</string> <string name="mode_selected_count"><xliff:g id="count" example="3">%1$d</xliff:g> selected</string> Loading @@ -55,4 +57,7 @@ <string name="empty">No items</string> <string name="toast_no_application">Can\'t open file</string> <string name="toast_failed_delete">Unable to delete some documents</string> </resources>
packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java +115 −30 Original line number Diff line number Diff line Loading @@ -17,12 +17,20 @@ package com.android.documentsui; import static com.android.documentsui.DocumentsActivity.TAG; import static com.android.documentsui.DocumentsActivity.DisplayState.ACTION_MANAGE; import static com.android.documentsui.DocumentsActivity.DisplayState.MODE_GRID; import static com.android.documentsui.DocumentsActivity.DisplayState.MODE_LIST; import static com.android.documentsui.DocumentsActivity.DisplayState.SORT_ORDER_DATE; import static com.android.documentsui.DocumentsActivity.DisplayState.SORT_ORDER_NAME; import static com.android.documentsui.DocumentsActivity.DisplayState.SORT_ORDER_SIZE; import android.app.Fragment; import android.app.FragmentManager; import android.app.FragmentTransaction; import android.app.LoaderManager.LoaderCallbacks; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.Loader; import android.graphics.Bitmap; import android.graphics.Point; Loading Loading @@ -50,6 +58,7 @@ import android.widget.GridView; import android.widget.ImageView; import android.widget.ListView; import android.widget.TextView; import android.widget.Toast; import com.android.documentsui.DocumentsActivity.DisplayState; import com.android.documentsui.model.Document; Loading @@ -57,7 +66,6 @@ import com.android.documentsui.model.Root; import com.android.internal.util.Predicate; import com.google.android.collect.Lists; import java.text.DateFormat; import java.util.ArrayList; import java.util.Comparator; import java.util.List; Loading Loading @@ -167,11 +175,11 @@ public class DirectoryFragment extends Fragment { } final Comparator<Document> sortOrder; if (state.sortOrder == DisplayState.SORT_ORDER_DATE || mType == TYPE_RECENT_OPEN) { if (state.sortOrder == SORT_ORDER_DATE || mType == TYPE_RECENT_OPEN) { sortOrder = new Document.DateComparator(); } else if (state.sortOrder == DisplayState.SORT_ORDER_NAME) { } else if (state.sortOrder == SORT_ORDER_NAME) { sortOrder = new Document.NameComparator(); } else if (state.sortOrder == DisplayState.SORT_ORDER_SIZE) { } else if (state.sortOrder == SORT_ORDER_SIZE) { sortOrder = new Document.SizeComparator(); } else { throw new IllegalArgumentException("Unknown sort order " + state.sortOrder); Loading Loading @@ -216,8 +224,8 @@ public class DirectoryFragment extends Fragment { mListView.smoothScrollToPosition(0); mGridView.smoothScrollToPosition(0); mListView.setVisibility(state.mode == DisplayState.MODE_LIST ? View.VISIBLE : View.GONE); mGridView.setVisibility(state.mode == DisplayState.MODE_GRID ? View.VISIBLE : View.GONE); mListView.setVisibility(state.mode == MODE_LIST ? View.VISIBLE : View.GONE); mGridView.setVisibility(state.mode == MODE_GRID ? View.VISIBLE : View.GONE); final int choiceMode; if (state.allowMultiple) { Loading @@ -227,7 +235,7 @@ public class DirectoryFragment extends Fragment { } final int thumbSize; if (state.mode == DisplayState.MODE_GRID) { if (state.mode == MODE_GRID) { thumbSize = getResources().getDimensionPixelSize(R.dimen.grid_width); mListView.setAdapter(null); mListView.setChoiceMode(ListView.CHOICE_MODE_NONE); Loading @@ -236,7 +244,7 @@ public class DirectoryFragment extends Fragment { mGridView.setNumColumns(GridView.AUTO_FIT); mGridView.setChoiceMode(choiceMode); mCurrentView = mGridView; } else if (state.mode == DisplayState.MODE_LIST) { } else if (state.mode == MODE_LIST) { thumbSize = getResources().getDimensionPixelSize(android.R.dimen.app_icon_size); mGridView.setAdapter(null); mGridView.setChoiceMode(ListView.CHOICE_MODE_NONE); Loading Loading @@ -269,16 +277,24 @@ public class DirectoryFragment extends Fragment { @Override public boolean onPrepareActionMode(ActionMode mode, Menu menu) { final DisplayState state = getDisplayState(DirectoryFragment.this); final MenuItem open = menu.findItem(R.id.menu_open); final MenuItem share = menu.findItem(R.id.menu_share); final MenuItem delete = menu.findItem(R.id.menu_delete); final boolean manageMode = state.action == ACTION_MANAGE; open.setVisible(!manageMode); share.setVisible(manageMode); delete.setVisible(manageMode); 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)) { Loading @@ -287,8 +303,19 @@ public class DirectoryFragment extends Fragment { } } ((DocumentsActivity) getActivity()).onDocumentsPicked(docs); final int id = item.getItemId(); if (id == R.id.menu_open) { DocumentsActivity.get(DirectoryFragment.this).onDocumentsPicked(docs); return true; } else if (id == R.id.menu_share) { onShareDocuments(docs); return true; } else if (id == R.id.menu_delete) { onDeleteDocuments(docs); return true; } else { return false; } Loading @@ -315,6 +342,58 @@ public class DirectoryFragment extends Fragment { } }; private void onShareDocuments(List<Document> docs) { final ArrayList<Uri> uris = Lists.newArrayList(); for (Document doc : docs) { uris.add(doc.uri); } final Intent intent; if (uris.size() > 1) { intent = new Intent(Intent.ACTION_SEND_MULTIPLE); intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); intent.addCategory(Intent.CATEGORY_DEFAULT); // TODO: find common mimetype intent.setType("*/*"); intent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, uris); } else { intent = new Intent(Intent.ACTION_SEND); intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); intent.addCategory(Intent.CATEGORY_DEFAULT); intent.setData(uris.get(0)); } startActivity(intent); } private void onDeleteDocuments(List<Document> docs) { final Context context = getActivity(); final ContentResolver resolver = context.getContentResolver(); boolean hadTrouble = false; for (Document doc : docs) { if (!doc.isDeleteSupported()) { Log.w(TAG, "Skipping " + doc); hadTrouble = true; continue; } try { if (resolver.delete(doc.uri, null, null) != 1) { Log.w(TAG, "Failed to delete " + doc); hadTrouble = true; } } catch (Exception e) { Log.w(TAG, "Failed to delete " + doc + ": " + e); hadTrouble = true; } } if (hadTrouble) { Toast.makeText(context, R.string.toast_failed_delete, Toast.LENGTH_SHORT).show(); } } private static DisplayState getDisplayState(Fragment fragment) { return ((DocumentsActivity) fragment.getActivity()).getDisplayState(); } Loading Loading @@ -342,11 +421,15 @@ public class DirectoryFragment extends Fragment { final Context context = parent.getContext(); final DisplayState state = getDisplayState(DirectoryFragment.this); final RootsCache roots = DocumentsApplication.getRootsCache(context); final ThumbnailCache thumbs = DocumentsApplication.getThumbnailsCache( context, mThumbSize); if (convertView == null) { final LayoutInflater inflater = LayoutInflater.from(context); if (state.mode == DisplayState.MODE_LIST) { if (state.mode == MODE_LIST) { convertView = inflater.inflate(R.layout.item_doc_list, parent, false); } else if (state.mode == DisplayState.MODE_GRID) { } else if (state.mode == MODE_GRID) { convertView = inflater.inflate(R.layout.item_doc_grid, parent, false); } else { throw new IllegalStateException(); Loading @@ -369,7 +452,7 @@ public class DirectoryFragment extends Fragment { } if (doc.isThumbnailSupported()) { final Bitmap cachedResult = ThumbnailCache.get(context).get(doc.uri); final Bitmap cachedResult = thumbs.get(doc.uri); if (cachedResult != null) { icon.setImageBitmap(cachedResult); } else { Loading @@ -379,7 +462,7 @@ public class DirectoryFragment extends Fragment { task.execute(doc.uri); } } else { icon.setImageDrawable(RootsCache.resolveDocumentIcon( icon.setImageDrawable(roots.resolveDocumentIcon( context, doc.uri.getAuthority(), doc.mimeType)); } Loading @@ -394,7 +477,7 @@ public class DirectoryFragment extends Fragment { summary.setVisibility(View.INVISIBLE); } } else if (mType == TYPE_RECENT_OPEN) { final Root root = RootsCache.findRoot(context, doc); final Root root = roots.findRoot(doc); icon1.setVisibility(View.VISIBLE); icon1.setImageDrawable(root.icon); summary.setText(root.getDirectoryString()); Loading Loading @@ -444,11 +527,11 @@ public class DirectoryFragment extends Fragment { private static class ThumbnailAsyncTask extends AsyncTask<Uri, Void, Bitmap> { private final ImageView mTarget; private final Point mSize; private final Point mThumbSize; public ThumbnailAsyncTask(ImageView target, Point size) { public ThumbnailAsyncTask(ImageView target, Point thumbSize) { mTarget = target; mSize = size; mThumbSize = thumbSize; } @Override Loading @@ -464,9 +547,11 @@ public class DirectoryFragment extends Fragment { Bitmap result = null; try { result = DocumentsContract.getThumbnail( context.getContentResolver(), uri, mSize); context.getContentResolver(), uri, mThumbSize); if (result != null) { ThumbnailCache.get(context).put(uri, result); final ThumbnailCache thumbs = DocumentsApplication.getThumbnailsCache( context, mThumbSize); thumbs.put(uri, result); } } catch (Exception e) { Log.w(TAG, "Failed to load thumbnail: " + e); Loading