Merge "Documents management mode; API adjustment." into klp-dev

This commit is contained in:
Jeff Sharkey
2013-08-16 00:08:05 +00:00
committed by Android (Google) Code Review
13 changed files with 267 additions and 176 deletions

View File

@@ -20620,19 +20620,6 @@ package android.provider {
field public static final java.lang.String EXTRA_HAS_MORE = "has_more"; field public static final java.lang.String EXTRA_HAS_MORE = "has_more";
field public static final java.lang.String EXTRA_REQUEST_MORE = "request_more"; field public static final java.lang.String EXTRA_REQUEST_MORE = "request_more";
field public static final java.lang.String EXTRA_THUMBNAIL_SIZE = "thumbnail_size"; field public static final java.lang.String EXTRA_THUMBNAIL_SIZE = "thumbnail_size";
field public static final int FLAG_PREFERS_GRID = 64; // 0x40
field public static final int FLAG_SUPPORTS_CREATE = 1; // 0x1
field public static final int FLAG_SUPPORTS_DELETE = 4; // 0x4
field public static final int FLAG_SUPPORTS_RENAME = 2; // 0x2
field public static final int FLAG_SUPPORTS_SEARCH = 16; // 0x10
field public static final int FLAG_SUPPORTS_THUMBNAIL = 8; // 0x8
field public static final int FLAG_SUPPORTS_WRITE = 32; // 0x20
field public static final java.lang.String MIME_TYPE_DIRECTORY = "vnd.android.cursor.dir/doc";
field public static final java.lang.String ROOT_DOC_ID = "0";
field public static final int ROOT_TYPE_DEVICE = 3; // 0x3
field public static final int ROOT_TYPE_DEVICE_ADVANCED = 4; // 0x4
field public static final int ROOT_TYPE_SERVICE = 1; // 0x1
field public static final int ROOT_TYPE_SHORTCUT = 2; // 0x2
} }
public static abstract interface DocumentsContract.DocumentColumns implements android.provider.OpenableColumns { public static abstract interface DocumentsContract.DocumentColumns implements android.provider.OpenableColumns {
@@ -20643,6 +20630,18 @@ package android.provider {
field public static final java.lang.String SUMMARY = "summary"; field public static final java.lang.String SUMMARY = "summary";
} }
public static class DocumentsContract.Documents {
field public static final java.lang.String DOC_ID_ROOT = "0";
field public static final int FLAG_PREFERS_GRID = 64; // 0x40
field public static final int FLAG_SUPPORTS_CREATE = 1; // 0x1
field public static final int FLAG_SUPPORTS_DELETE = 4; // 0x4
field public static final int FLAG_SUPPORTS_RENAME = 2; // 0x2
field public static final int FLAG_SUPPORTS_SEARCH = 16; // 0x10
field public static final int FLAG_SUPPORTS_THUMBNAIL = 8; // 0x8
field public static final int FLAG_SUPPORTS_WRITE = 32; // 0x20
field public static final java.lang.String MIME_TYPE_DIR = "vnd.android.cursor.dir/doc";
}
public static abstract interface DocumentsContract.RootColumns { public static abstract interface DocumentsContract.RootColumns {
field public static final java.lang.String AVAILABLE_BYTES = "available_bytes"; field public static final java.lang.String AVAILABLE_BYTES = "available_bytes";
field public static final java.lang.String ICON = "icon"; field public static final java.lang.String ICON = "icon";
@@ -20652,6 +20651,15 @@ package android.provider {
field public static final java.lang.String TITLE = "title"; field public static final java.lang.String TITLE = "title";
} }
public static class DocumentsContract.Roots {
field public static final java.lang.String MIME_TYPE_DIR = "vnd.android.cursor.dir/root";
field public static final java.lang.String MIME_TYPE_ITEM = "vnd.android.cursor.item/root";
field public static final int ROOT_TYPE_DEVICE = 3; // 0x3
field public static final int ROOT_TYPE_DEVICE_ADVANCED = 4; // 0x4
field public static final int ROOT_TYPE_SERVICE = 1; // 0x1
field public static final int ROOT_TYPE_SHORTCUT = 2; // 0x2
}
public final deprecated class LiveFolders implements android.provider.BaseColumns { public final deprecated class LiveFolders implements android.provider.BaseColumns {
field public static final java.lang.String ACTION_CREATE_LIVE_FOLDER = "android.intent.action.CREATE_LIVE_FOLDER"; field public static final java.lang.String ACTION_CREATE_LIVE_FOLDER = "android.intent.action.CREATE_LIVE_FOLDER";
field public static final java.lang.String DESCRIPTION = "description"; field public static final java.lang.String DESCRIPTION = "description";

View File

@@ -2678,6 +2678,10 @@ public class Intent implements Parcelable, Cloneable {
@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
public static final String ACTION_CREATE_DOCUMENT = "android.intent.action.CREATE_DOCUMENT"; public static final String ACTION_CREATE_DOCUMENT = "android.intent.action.CREATE_DOCUMENT";
/** {@hide} */
@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
public static final String ACTION_MANAGE_DOCUMENT = "android.intent.action.MANAGE_DOCUMENT";
// --------------------------------------------------------------------- // ---------------------------------------------------------------------
// --------------------------------------------------------------------- // ---------------------------------------------------------------------
// Standard intent categories (see addCategory()). // Standard intent categories (see addCategory()).

View File

@@ -53,80 +53,85 @@ public final class DocumentsContract {
// content://com.example/roots/sdcard/docs/0/contents/ // content://com.example/roots/sdcard/docs/0/contents/
// content://com.example/roots/sdcard/docs/0/search/?query=pony // content://com.example/roots/sdcard/docs/0/search/?query=pony
/**
* MIME type of a document which is a directory that may contain additional
* documents.
*
* @see #buildContentsUri(String, String, String)
*/
public static final String MIME_TYPE_DIRECTORY = "vnd.android.cursor.dir/doc";
/** {@hide} */ /** {@hide} */
public static final String META_DATA_DOCUMENT_PROVIDER = "android.content.DOCUMENT_PROVIDER"; public static final String META_DATA_DOCUMENT_PROVIDER = "android.content.DOCUMENT_PROVIDER";
/** {@hide} */ /** {@hide} */
public static final String ACTION_DOCUMENT_CHANGED = "android.provider.action.DOCUMENT_CHANGED"; public static final String ACTION_DOCUMENT_CHANGED = "android.provider.action.DOCUMENT_CHANGED";
/** public static class Documents {
* {@link DocumentColumns#DOC_ID} value representing the root directory of a private Documents() {
* storage root. }
*/
public static final String ROOT_DOC_ID = "0";
/** /**
* Flag indicating that a document is a directory that supports creation of * MIME type of a document which is a directory that may contain additional
* new files within it. * documents.
* *
* @see DocumentColumns#FLAGS * @see #buildContentsUri(String, String, String)
* @see #createDocument(ContentResolver, Uri, String, String) */
*/ public static final String MIME_TYPE_DIR = "vnd.android.cursor.dir/doc";
public static final int FLAG_SUPPORTS_CREATE = 1;
/** /**
* Flag indicating that a document is renamable. * {@link DocumentColumns#DOC_ID} value representing the root directory of a
* * storage root.
* @see DocumentColumns#FLAGS */
* @see #renameDocument(ContentResolver, Uri, String) public static final String DOC_ID_ROOT = "0";
*/
public static final int FLAG_SUPPORTS_RENAME = 1 << 1;
/** /**
* Flag indicating that a document is deletable. * Flag indicating that a document is a directory that supports creation of
* * new files within it.
* @see DocumentColumns#FLAGS *
*/ * @see DocumentColumns#FLAGS
public static final int FLAG_SUPPORTS_DELETE = 1 << 2; * @see #createDocument(ContentResolver, Uri, String, String)
*/
public static final int FLAG_SUPPORTS_CREATE = 1;
/** /**
* Flag indicating that a document can be represented as a thumbnail. * Flag indicating that a document is renamable.
* *
* @see DocumentColumns#FLAGS * @see DocumentColumns#FLAGS
* @see #getThumbnail(ContentResolver, Uri, Point) * @see #renameDocument(ContentResolver, Uri, String)
*/ */
public static final int FLAG_SUPPORTS_THUMBNAIL = 1 << 3; public static final int FLAG_SUPPORTS_RENAME = 1 << 1;
/** /**
* Flag indicating that a document is a directory that supports search. * Flag indicating that a document is deletable.
* *
* @see DocumentColumns#FLAGS * @see DocumentColumns#FLAGS
*/ */
public static final int FLAG_SUPPORTS_SEARCH = 1 << 4; public static final int FLAG_SUPPORTS_DELETE = 1 << 2;
/** /**
* Flag indicating that a document is writable. * Flag indicating that a document can be represented as a thumbnail.
* *
* @see DocumentColumns#FLAGS * @see DocumentColumns#FLAGS
*/ * @see #getThumbnail(ContentResolver, Uri, Point)
public static final int FLAG_SUPPORTS_WRITE = 1 << 5; */
public static final int FLAG_SUPPORTS_THUMBNAIL = 1 << 3;
/** /**
* Flag indicating that a document is a directory that prefers its contents * Flag indicating that a document is a directory that supports search.
* be shown in a larger format grid. Usually suitable when a directory *
* contains mostly pictures. * @see DocumentColumns#FLAGS
* */
* @see DocumentColumns#FLAGS public static final int FLAG_SUPPORTS_SEARCH = 1 << 4;
*/
public static final int FLAG_PREFERS_GRID = 1 << 6; /**
* Flag indicating that a document is writable.
*
* @see DocumentColumns#FLAGS
*/
public static final int FLAG_SUPPORTS_WRITE = 1 << 5;
/**
* Flag indicating that a document is a directory that prefers its contents
* be shown in a larger format grid. Usually suitable when a directory
* contains mostly pictures.
*
* @see DocumentColumns#FLAGS
*/
public static final int FLAG_PREFERS_GRID = 1 << 6;
}
/** /**
* Optimal dimensions for a document thumbnail request, stored as a * Optimal dimensions for a document thumbnail request, stored as a
@@ -189,7 +194,7 @@ public final class DocumentsContract {
/** /**
* Build URI representing the contents of the given directory in a storage * Build URI representing the contents of the given directory in a storage
* backend. The given document must be {@link #MIME_TYPE_DIRECTORY}. * backend. The given document must be {@link Documents#MIME_TYPE_DIR}.
*/ */
public static Uri buildContentsUri(String authority, String rootId, String docId) { public static Uri buildContentsUri(String authority, String rootId, String docId) {
return new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT).authority(authority) return new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT).authority(authority)
@@ -296,7 +301,7 @@ public final class DocumentsContract {
* <p> * <p>
* Type: STRING * Type: STRING
* *
* @see DocumentsContract#MIME_TYPE_DIRECTORY * @see Documents#MIME_TYPE_DIR
*/ */
public static final String MIME_TYPE = "mime_type"; public static final String MIME_TYPE = "mime_type";
@@ -327,35 +332,43 @@ public final class DocumentsContract {
public static final String SUMMARY = "summary"; public static final String SUMMARY = "summary";
} }
/** public static class Roots {
* Root that represents a cloud-based storage service. private Roots() {
* }
* @see RootColumns#ROOT_TYPE
*/
public static final int ROOT_TYPE_SERVICE = 1;
/** public static final String MIME_TYPE_DIR = "vnd.android.cursor.dir/root";
* Root that represents a shortcut to content that may be available public static final String MIME_TYPE_ITEM = "vnd.android.cursor.item/root";
* elsewhere through another storage root.
*
* @see RootColumns#ROOT_TYPE
*/
public static final int ROOT_TYPE_SHORTCUT = 2;
/** /**
* Root that represents a physical storage device. * Root that represents a cloud-based storage service.
* *
* @see RootColumns#ROOT_TYPE * @see RootColumns#ROOT_TYPE
*/ */
public static final int ROOT_TYPE_DEVICE = 3; public static final int ROOT_TYPE_SERVICE = 1;
/** /**
* Root that represents a physical storage device that should only be * Root that represents a shortcut to content that may be available
* displayed to advanced users. * elsewhere through another storage root.
* *
* @see RootColumns#ROOT_TYPE * @see RootColumns#ROOT_TYPE
*/ */
public static final int ROOT_TYPE_DEVICE_ADVANCED = 4; public static final int ROOT_TYPE_SHORTCUT = 2;
/**
* Root that represents a physical storage device.
*
* @see RootColumns#ROOT_TYPE
*/
public static final int ROOT_TYPE_DEVICE = 3;
/**
* Root that represents a physical storage device that should only be
* displayed to advanced users.
*
* @see RootColumns#ROOT_TYPE
*/
public static final int ROOT_TYPE_DEVICE_ADVANCED = 4;
}
/** /**
* These are standard columns for the roots URI. * These are standard columns for the roots URI.
@@ -370,8 +383,8 @@ public final class DocumentsContract {
* <p> * <p>
* Type: INTEGER (int) * Type: INTEGER (int)
* *
* @see DocumentsContract#ROOT_TYPE_SERVICE * @see Roots#ROOT_TYPE_SERVICE
* @see DocumentsContract#ROOT_TYPE_DEVICE * @see Roots#ROOT_TYPE_DEVICE
*/ */
public static final String ROOT_TYPE = "root_type"; public static final String ROOT_TYPE = "root_type";
@@ -440,7 +453,7 @@ public final class DocumentsContract {
/** /**
* Return thumbnail representing the document at the given URI. Callers are * Return thumbnail representing the document at the given URI. Callers are
* responsible for their own caching. Given document must have * responsible for their own caching. Given document must have
* {@link #FLAG_SUPPORTS_THUMBNAIL} set. * {@link Documents#FLAG_SUPPORTS_THUMBNAIL} set.
* *
* @return decoded thumbnail, or {@code null} if problem was encountered. * @return decoded thumbnail, or {@code null} if problem was encountered.
*/ */
@@ -465,7 +478,8 @@ public final class DocumentsContract {
* Create a new document under a specific parent document with the given * Create a new document under a specific parent document with the given
* display name and MIME type. * display name and MIME type.
* *
* @param parentDocumentUri document with {@link #FLAG_SUPPORTS_CREATE} * @param parentDocumentUri document with
* {@link Documents#FLAG_SUPPORTS_CREATE}
* @param displayName name for new document * @param displayName name for new document
* @param mimeType MIME type for new document, which cannot be changed * @param mimeType MIME type for new document, which cannot be changed
* @return newly created document Uri, or {@code null} if failed * @return newly created document Uri, or {@code null} if failed
@@ -480,7 +494,7 @@ public final class DocumentsContract {
/** /**
* Rename the document at the given URI. Given document must have * Rename the document at the given URI. Given document must have
* {@link #FLAG_SUPPORTS_RENAME} set. * {@link Documents#FLAG_SUPPORTS_RENAME} set.
* *
* @return if rename was successful. * @return if rename was successful.
*/ */

View File

@@ -32,6 +32,12 @@
<category android:name="android.intent.category.OPENABLE" /> <category android:name="android.intent.category.OPENABLE" />
<data android:mimeType="*/*" /> <data android:mimeType="*/*" />
</intent-filter> </intent-filter>
<!-- data expected to point at existing root to manage -->
<intent-filter>
<action android:name="android.intent.action.MANAGE_DOCUMENT" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="vnd.android.cursor.item/root" />
</intent-filter>
</activity> </activity>
<activity <activity

View File

@@ -27,8 +27,8 @@ import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener; import android.content.DialogInterface.OnClickListener;
import android.net.Uri; import android.net.Uri;
import android.os.Bundle; import android.os.Bundle;
import android.provider.DocumentsContract;
import android.provider.DocumentsContract.DocumentColumns; import android.provider.DocumentsContract.DocumentColumns;
import android.provider.DocumentsContract.Documents;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.widget.EditText; import android.widget.EditText;
@@ -69,7 +69,7 @@ public class CreateDirectoryFragment extends DialogFragment {
final String displayName = text1.getText().toString(); final String displayName = text1.getText().toString();
final ContentValues values = new ContentValues(); final ContentValues values = new ContentValues();
values.put(DocumentColumns.MIME_TYPE, DocumentsContract.MIME_TYPE_DIRECTORY); values.put(DocumentColumns.MIME_TYPE, Documents.MIME_TYPE_DIR);
values.put(DocumentColumns.DISPLAY_NAME, displayName); values.put(DocumentColumns.DISPLAY_NAME, displayName);
final DocumentsActivity activity = (DocumentsActivity) getActivity(); final DocumentsActivity activity = (DocumentsActivity) getActivity();

View File

@@ -190,10 +190,6 @@ public class DirectoryFragment extends Fragment {
@Override @Override
public void onStart() { public void onStart() {
super.onStart(); super.onStart();
final Context context = getActivity();
getDisplayState(this).showSize = SettingsActivity.getDisplayFileSize(context);
getLoaderManager().restartLoader(mLoaderId, getArguments(), mCallbacks); getLoaderManager().restartLoader(mLoaderId, getArguments(), mCallbacks);
} }
@@ -244,7 +240,9 @@ public class DirectoryFragment extends Fragment {
@Override @Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) { public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
final Document doc = mAdapter.getItem(position); final Document doc = mAdapter.getItem(position);
((DocumentsActivity) getActivity()).onDocumentPicked(doc); if (mFilter.apply(doc)) {
((DocumentsActivity) getActivity()).onDocumentPicked(doc);
}
} }
}; };
@@ -389,7 +387,7 @@ public class DirectoryFragment extends Fragment {
if (state.showSize) { if (state.showSize) {
size.setVisibility(View.VISIBLE); size.setVisibility(View.VISIBLE);
if (doc.isDirectory()) { if (doc.isDirectory() || doc.size == -1) {
size.setText(null); size.setText(null);
} else { } else {
size.setText(Formatter.formatFileSize(context, doc.size)); size.setText(Formatter.formatFileSize(context, doc.size));
@@ -415,16 +413,5 @@ public class DirectoryFragment extends Fragment {
public long getItemId(int position) { public long getItemId(int position) {
return getItem(position).uri.hashCode(); return getItem(position).uri.hashCode();
} }
@Override
public boolean areAllItemsEnabled() {
return false;
}
@Override
public boolean isEnabled(int position) {
final Document doc = getItem(position);
return mFilter.apply(doc);
}
} }
} }

View File

@@ -31,6 +31,7 @@ import android.database.Cursor;
import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.ColorDrawable;
import android.net.Uri; import android.net.Uri;
import android.os.Bundle; import android.os.Bundle;
import android.provider.DocumentsContract;
import android.provider.DocumentsContract.DocumentColumns; import android.provider.DocumentsContract.DocumentColumns;
import android.support.v4.app.ActionBarDrawerToggle; import android.support.v4.app.ActionBarDrawerToggle;
import android.support.v4.view.GravityCompat; import android.support.v4.view.GravityCompat;
@@ -63,6 +64,7 @@ public class DocumentsActivity extends Activity {
public static final int ACTION_OPEN = 1; public static final int ACTION_OPEN = 1;
public static final int ACTION_CREATE = 2; public static final int ACTION_CREATE = 2;
public static final int ACTION_GET_CONTENT = 3; public static final int ACTION_GET_CONTENT = 3;
public static final int ACTION_MANAGE = 4;
private int mAction; private int mAction;
@@ -91,6 +93,8 @@ public class DocumentsActivity extends Activity {
mAction = ACTION_CREATE; mAction = ACTION_CREATE;
} else if (Intent.ACTION_GET_CONTENT.equals(action)) { } else if (Intent.ACTION_GET_CONTENT.equals(action)) {
mAction = ACTION_GET_CONTENT; mAction = ACTION_GET_CONTENT;
} else if (Intent.ACTION_MANAGE_DOCUMENT.equals(action)) {
mAction = ACTION_MANAGE;
} }
if (mAction == ACTION_OPEN || mAction == ACTION_GET_CONTENT) { if (mAction == ACTION_OPEN || mAction == ACTION_GET_CONTENT) {
@@ -98,7 +102,9 @@ public class DocumentsActivity extends Activity {
Intent.EXTRA_ALLOW_MULTIPLE, false); Intent.EXTRA_ALLOW_MULTIPLE, false);
} }
if (intent.hasExtra(Intent.EXTRA_MIME_TYPES)) { if (mAction == ACTION_MANAGE) {
mDisplayState.acceptMimes = new String[] { "*/*" };
} else if (intent.hasExtra(Intent.EXTRA_MIME_TYPES)) {
mDisplayState.acceptMimes = intent.getStringArrayExtra(Intent.EXTRA_MIME_TYPES); mDisplayState.acceptMimes = intent.getStringArrayExtra(Intent.EXTRA_MIME_TYPES);
} else { } else {
mDisplayState.acceptMimes = new String[] { intent.getType() }; mDisplayState.acceptMimes = new String[] { intent.getType() };
@@ -120,10 +126,14 @@ public class DocumentsActivity extends Activity {
moreApps.setComponent(null); moreApps.setComponent(null);
moreApps.setPackage(null); moreApps.setPackage(null);
RootsFragment.show(getFragmentManager(), moreApps); RootsFragment.show(getFragmentManager(), moreApps);
} else { } else if (mAction == ACTION_OPEN || mAction == ACTION_CREATE) {
RootsFragment.show(getFragmentManager(), null); RootsFragment.show(getFragmentManager(), null);
} }
if (mAction == ACTION_MANAGE) {
mDisplayState.sortOrder = DisplayState.SORT_ORDER_DATE;
}
mRootsContainer = findViewById(R.id.container_roots); mRootsContainer = findViewById(R.id.container_roots);
mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout); mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
@@ -134,26 +144,54 @@ public class DocumentsActivity extends Activity {
mDrawerLayout.setDrawerListener(mDrawerListener); mDrawerLayout.setDrawerListener(mDrawerListener);
mDrawerLayout.setDrawerShadow(R.drawable.drawer_shadow, GravityCompat.START); mDrawerLayout.setDrawerShadow(R.drawable.drawer_shadow, GravityCompat.START);
mDrawerLayout.openDrawer(mRootsContainer); if (mAction == ACTION_MANAGE) {
mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
// Restore last stack for calling package final Uri rootUri = intent.getData();
// TODO: move into async loader final String authority = rootUri.getAuthority();
final String packageName = getCallingPackage(); final String rootId = DocumentsContract.getRootId(rootUri);
final Cursor cursor = getContentResolver()
.query(RecentsProvider.buildResume(packageName), null, null, null, null); final Root root = RootsCache.findRoot(this, authority, rootId);
try { if (root != null) {
if (cursor.moveToFirst()) { onRootPicked(root, true);
final String raw = cursor.getString( } else {
cursor.getColumnIndex(RecentsProvider.COL_PATH)); Log.w(TAG, "Failed to find root: " + rootUri);
mStack = DocumentStack.deserialize(getContentResolver(), raw); finish();
} }
} catch (FileNotFoundException e) {
Log.w(TAG, "Failed to resume", e);
} finally {
cursor.close();
}
onCurrentDirectoryChanged(); } else {
mDrawerLayout.openDrawer(mRootsContainer);
// Restore last stack for calling package
// TODO: move into async loader
final String packageName = getCallingPackage();
final Cursor cursor = getContentResolver()
.query(RecentsProvider.buildResume(packageName), null, null, null, null);
try {
if (cursor.moveToFirst()) {
final String raw = cursor.getString(
cursor.getColumnIndex(RecentsProvider.COL_PATH));
mStack = DocumentStack.deserialize(getContentResolver(), raw);
}
} catch (FileNotFoundException e) {
Log.w(TAG, "Failed to resume", e);
} finally {
cursor.close();
}
onCurrentDirectoryChanged();
}
}
@Override
public void onStart() {
super.onStart();
if (mAction == ACTION_MANAGE) {
mDisplayState.showSize = true;
} else {
mDisplayState.showSize = SettingsActivity.getDisplayFileSize(this);
}
} }
private DrawerListener mDrawerListener = new DrawerListener() { private DrawerListener mDrawerListener = new DrawerListener() {
@@ -190,7 +228,6 @@ public class DocumentsActivity extends Activity {
final ActionBar actionBar = getActionBar(); final ActionBar actionBar = getActionBar();
actionBar.setDisplayShowHomeEnabled(true); actionBar.setDisplayShowHomeEnabled(true);
actionBar.setDisplayHomeAsUpEnabled(true);
if (mDrawerLayout.isDrawerOpen(mRootsContainer)) { if (mDrawerLayout.isDrawerOpen(mRootsContainer)) {
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD); actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
@@ -202,6 +239,9 @@ public class DocumentsActivity extends Activity {
actionBar.setTitle(R.string.title_save); actionBar.setTitle(R.string.title_save);
} }
actionBar.setDisplayHomeAsUpEnabled(true);
mDrawerToggle.setDrawerIndicatorEnabled(true);
} else { } else {
final Root root = getCurrentRoot(); final Root root = getCurrentRoot();
actionBar.setIcon(root != null ? root.icon : null); actionBar.setIcon(root != null ? root.icon : null);
@@ -217,8 +257,13 @@ public class DocumentsActivity extends Activity {
} }
if (mStack.size() > 1) { if (mStack.size() > 1) {
actionBar.setDisplayHomeAsUpEnabled(true);
mDrawerToggle.setDrawerIndicatorEnabled(false);
} else if (mAction == ACTION_MANAGE) {
actionBar.setDisplayHomeAsUpEnabled(false);
mDrawerToggle.setDrawerIndicatorEnabled(false); mDrawerToggle.setDrawerIndicatorEnabled(false);
} else { } else {
actionBar.setDisplayHomeAsUpEnabled(true);
mDrawerToggle.setDrawerIndicatorEnabled(true); mDrawerToggle.setDrawerIndicatorEnabled(true);
} }
} }
@@ -269,6 +314,7 @@ public class DocumentsActivity extends Activity {
final MenuItem search = menu.findItem(R.id.menu_search); final MenuItem search = menu.findItem(R.id.menu_search);
final MenuItem grid = menu.findItem(R.id.menu_grid); final MenuItem grid = menu.findItem(R.id.menu_grid);
final MenuItem list = menu.findItem(R.id.menu_list); final MenuItem list = menu.findItem(R.id.menu_list);
final MenuItem settings = menu.findItem(R.id.menu_settings);
grid.setVisible(mDisplayState.mode != DisplayState.MODE_GRID); grid.setVisible(mDisplayState.mode != DisplayState.MODE_GRID);
list.setVisible(mDisplayState.mode != DisplayState.MODE_LIST); list.setVisible(mDisplayState.mode != DisplayState.MODE_LIST);
@@ -293,6 +339,8 @@ public class DocumentsActivity extends Activity {
// TODO: close any search in-progress when hiding // TODO: close any search in-progress when hiding
search.setVisible(searchVisible); search.setVisible(searchVisible);
settings.setVisible(mAction != ACTION_MANAGE);
return true; return true;
} }

View File

@@ -49,7 +49,9 @@ public class MimePredicate implements Predicate<Document> {
} }
public static boolean mimeMatches(String filter, String test) { public static boolean mimeMatches(String filter, String test) {
if (filter.equals(test)) { if (test == null) {
return false;
} else if (filter.equals(test)) {
return true; return true;
} else if ("*/*".equals(filter)) { } else if ("*/*".equals(filter)) {
return true; return true;

View File

@@ -27,6 +27,7 @@ import android.database.Cursor;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.net.Uri; import android.net.Uri;
import android.provider.DocumentsContract; import android.provider.DocumentsContract;
import android.provider.DocumentsContract.Documents;
import android.util.Log; import android.util.Log;
import android.util.Pair; import android.util.Pair;
@@ -162,7 +163,7 @@ public class RootsCache {
} }
} }
if (DocumentsContract.MIME_TYPE_DIRECTORY.equals(mimeType)) { if (Documents.MIME_TYPE_DIR.equals(mimeType)) {
return context.getResources().getDrawable(R.drawable.ic_dir); return context.getResources().getDrawable(R.drawable.ic_dir);
} else { } else {
final PackageManager pm = context.getPackageManager(); final PackageManager pm = context.getPackageManager();

View File

@@ -26,7 +26,7 @@ import android.content.Intent;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo; import android.content.pm.ResolveInfo;
import android.os.Bundle; import android.os.Bundle;
import android.provider.DocumentsContract; import android.provider.DocumentsContract.Roots;
import android.text.format.Formatter; import android.text.format.Formatter;
import android.util.Log; import android.util.Log;
import android.view.LayoutInflater; import android.view.LayoutInflater;
@@ -44,7 +44,6 @@ import com.android.documentsui.model.Root;
import com.android.documentsui.model.Root.RootComparator; import com.android.documentsui.model.Root.RootComparator;
import java.util.Collection; import java.util.Collection;
import java.util.Iterator;
import java.util.List; import java.util.List;
/** /**
@@ -138,8 +137,8 @@ public class RootsFragment extends Fragment {
// Device summary is always available space // Device summary is always available space
final String summaryText; final String summaryText;
if ((root.rootType == DocumentsContract.ROOT_TYPE_DEVICE if ((root.rootType == Roots.ROOT_TYPE_DEVICE
|| root.rootType == DocumentsContract.ROOT_TYPE_DEVICE_ADVANCED) || root.rootType == Roots.ROOT_TYPE_DEVICE_ADVANCED)
&& root.availableBytes >= 0) { && root.availableBytes >= 0) {
summaryText = context.getString(R.string.root_available_bytes, summaryText = context.getString(R.string.root_available_bytes,
Formatter.formatFileSize(context, root.availableBytes)); Formatter.formatFileSize(context, root.availableBytes));
@@ -226,17 +225,17 @@ public class RootsFragment extends Fragment {
for (Root root : roots) { for (Root root : roots) {
Log.d(TAG, "Found rootType=" + root.rootType); Log.d(TAG, "Found rootType=" + root.rootType);
switch (root.rootType) { switch (root.rootType) {
case DocumentsContract.ROOT_TYPE_SERVICE: case Roots.ROOT_TYPE_SERVICE:
mServices.add(root); mServices.add(root);
break; break;
case DocumentsContract.ROOT_TYPE_SHORTCUT: case Roots.ROOT_TYPE_SHORTCUT:
mShortcuts.add(root); mShortcuts.add(root);
break; break;
case DocumentsContract.ROOT_TYPE_DEVICE: case Roots.ROOT_TYPE_DEVICE:
mDevices.add(root); mDevices.add(root);
mDevicesAdvanced.add(root); mDevicesAdvanced.add(root);
break; break;
case DocumentsContract.ROOT_TYPE_DEVICE_ADVANCED: case Roots.ROOT_TYPE_DEVICE_ADVANCED:
mDevicesAdvanced.add(root); mDevicesAdvanced.add(root);
break; break;
} }

View File

@@ -21,6 +21,7 @@ import android.database.Cursor;
import android.net.Uri; import android.net.Uri;
import android.provider.DocumentsContract; import android.provider.DocumentsContract;
import android.provider.DocumentsContract.DocumentColumns; import android.provider.DocumentsContract.DocumentColumns;
import android.provider.DocumentsContract.Documents;
import com.android.documentsui.RecentsProvider; import com.android.documentsui.RecentsProvider;
@@ -87,7 +88,7 @@ public class Document {
final String mimeType = getCursorString(cursor, DocumentColumns.MIME_TYPE); final String mimeType = getCursorString(cursor, DocumentColumns.MIME_TYPE);
final String displayName = getCursorString(cursor, DocumentColumns.DISPLAY_NAME); final String displayName = getCursorString(cursor, DocumentColumns.DISPLAY_NAME);
final int flags = getCursorInt(cursor, DocumentColumns.FLAGS) final int flags = getCursorInt(cursor, DocumentColumns.FLAGS)
& DocumentsContract.FLAG_SUPPORTS_THUMBNAIL; & Documents.FLAG_SUPPORTS_THUMBNAIL;
final String summary = getCursorString(cursor, DocumentColumns.SUMMARY); final String summary = getCursorString(cursor, DocumentColumns.SUMMARY);
final long size = getCursorLong(cursor, DocumentColumns.SIZE); final long size = getCursorLong(cursor, DocumentColumns.SIZE);
@@ -127,19 +128,19 @@ public class Document {
} }
public boolean isCreateSupported() { public boolean isCreateSupported() {
return (flags & DocumentsContract.FLAG_SUPPORTS_CREATE) != 0; return (flags & Documents.FLAG_SUPPORTS_CREATE) != 0;
} }
public boolean isSearchSupported() { public boolean isSearchSupported() {
return (flags & DocumentsContract.FLAG_SUPPORTS_SEARCH) != 0; return (flags & Documents.FLAG_SUPPORTS_SEARCH) != 0;
} }
public boolean isThumbnailSupported() { public boolean isThumbnailSupported() {
return (flags & DocumentsContract.FLAG_SUPPORTS_THUMBNAIL) != 0; return (flags & Documents.FLAG_SUPPORTS_THUMBNAIL) != 0;
} }
public boolean isDirectory() { public boolean isDirectory() {
return DocumentsContract.MIME_TYPE_DIRECTORY.equals(mimeType); return Documents.MIME_TYPE_DIR.equals(mimeType);
} }
private static String getCursorString(Cursor cursor, String columnName) { private static String getCursorString(Cursor cursor, String columnName) {
@@ -147,9 +148,19 @@ public class Document {
return (index != -1) ? cursor.getString(index) : null; return (index != -1) ? cursor.getString(index) : null;
} }
/**
* Missing or null values are returned as -1.
*/
private static long getCursorLong(Cursor cursor, String columnName) { private static long getCursorLong(Cursor cursor, String columnName) {
final int index = cursor.getColumnIndex(columnName); final int index = cursor.getColumnIndex(columnName);
return (index != -1) ? cursor.getLong(index) : 0; if (index == -1) return -1;
final String value = cursor.getString(index);
if (value == null) return -1;
try {
return Long.parseLong(value);
} catch (NumberFormatException e) {
return -1;
}
} }
private static int getCursorInt(Cursor cursor, String columnName) { private static int getCursorInt(Cursor cursor, String columnName) {

View File

@@ -24,7 +24,9 @@ import android.database.Cursor;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.net.Uri; import android.net.Uri;
import android.provider.DocumentsContract; import android.provider.DocumentsContract;
import android.provider.DocumentsContract.Documents;
import android.provider.DocumentsContract.RootColumns; import android.provider.DocumentsContract.RootColumns;
import android.provider.DocumentsContract.Roots;
import com.android.documentsui.R; import com.android.documentsui.R;
@@ -47,7 +49,7 @@ public class Root {
final PackageManager pm = context.getPackageManager(); final PackageManager pm = context.getPackageManager();
final Root root = new Root(); final Root root = new Root();
root.rootId = null; root.rootId = null;
root.rootType = DocumentsContract.ROOT_TYPE_SHORTCUT; root.rootType = Roots.ROOT_TYPE_SHORTCUT;
root.uri = null; root.uri = null;
root.icon = context.getResources().getDrawable(R.drawable.ic_dir); root.icon = context.getResources().getDrawable(R.drawable.ic_dir);
root.title = context.getString(R.string.root_recent); root.title = context.getString(R.string.root_recent);
@@ -65,7 +67,7 @@ public class Root {
root.rootId = cursor.getString(cursor.getColumnIndex(RootColumns.ROOT_ID)); root.rootId = cursor.getString(cursor.getColumnIndex(RootColumns.ROOT_ID));
root.rootType = cursor.getInt(cursor.getColumnIndex(RootColumns.ROOT_TYPE)); root.rootType = cursor.getInt(cursor.getColumnIndex(RootColumns.ROOT_TYPE));
root.uri = DocumentsContract.buildDocumentUri( root.uri = DocumentsContract.buildDocumentUri(
info.providerInfo.authority, root.rootId, DocumentsContract.ROOT_DOC_ID); info.providerInfo.authority, root.rootId, Documents.DOC_ID_ROOT);
root.icon = info.providerInfo.loadIcon(pm); root.icon = info.providerInfo.loadIcon(pm);
root.title = info.providerInfo.loadLabel(pm).toString(); root.title = info.providerInfo.loadLabel(pm).toString();
root.availableBytes = cursor.getLong(cursor.getColumnIndex(RootColumns.AVAILABLE_BYTES)); root.availableBytes = cursor.getLong(cursor.getColumnIndex(RootColumns.AVAILABLE_BYTES));

View File

@@ -28,7 +28,9 @@ import android.os.ParcelFileDescriptor;
import android.provider.BaseColumns; import android.provider.BaseColumns;
import android.provider.DocumentsContract; import android.provider.DocumentsContract;
import android.provider.DocumentsContract.DocumentColumns; import android.provider.DocumentsContract.DocumentColumns;
import android.provider.DocumentsContract.Documents;
import android.provider.DocumentsContract.RootColumns; import android.provider.DocumentsContract.RootColumns;
import android.provider.DocumentsContract.Roots;
import android.util.Log; import android.util.Log;
import android.webkit.MimeTypeMap; import android.webkit.MimeTypeMap;
@@ -79,7 +81,7 @@ public class ExternalStorageProvider extends ContentProvider {
mRoots.clear(); mRoots.clear();
final Root root = new Root(); final Root root = new Root();
root.rootType = DocumentsContract.ROOT_TYPE_DEVICE_ADVANCED; root.rootType = Roots.ROOT_TYPE_DEVICE_ADVANCED;
root.name = "primary"; root.name = "primary";
root.title = getContext().getString(R.string.root_internal_storage); root.title = getContext().getString(R.string.root_internal_storage);
root.path = Environment.getExternalStorageDirectory(); root.path = Environment.getExternalStorageDirectory();
@@ -173,7 +175,7 @@ public class ExternalStorageProvider extends ContentProvider {
String rootPath = root.path.getAbsolutePath(); String rootPath = root.path.getAbsolutePath();
final String path = file.getAbsolutePath(); final String path = file.getAbsolutePath();
if (path.equals(rootPath)) { if (path.equals(rootPath)) {
return DocumentsContract.ROOT_DOC_ID; return Documents.DOC_ID_ROOT;
} }
if (!rootPath.endsWith("/")) { if (!rootPath.endsWith("/")) {
@@ -187,7 +189,7 @@ public class ExternalStorageProvider extends ContentProvider {
} }
private File docIdToFile(Root root, String docId) { private File docIdToFile(Root root, String docId) {
if (DocumentsContract.ROOT_DOC_ID.equals(docId)) { if (Documents.DOC_ID_ROOT.equals(docId)) {
return root.path; return root.path;
} else { } else {
return new File(root.path, docId); return new File(root.path, docId);
@@ -204,26 +206,27 @@ public class ExternalStorageProvider extends ContentProvider {
int flags = 0; int flags = 0;
if (file.isDirectory()) { if (file.isDirectory()) {
flags |= DocumentsContract.FLAG_SUPPORTS_SEARCH; flags |= Documents.FLAG_SUPPORTS_SEARCH;
} }
if (file.isDirectory() && file.canWrite()) { if (file.isDirectory() && file.canWrite()) {
flags |= DocumentsContract.FLAG_SUPPORTS_CREATE; flags |= Documents.FLAG_SUPPORTS_CREATE;
} }
if (file.canWrite()) { if (file.canWrite()) {
flags |= DocumentsContract.FLAG_SUPPORTS_RENAME; flags |= Documents.FLAG_SUPPORTS_WRITE;
flags |= DocumentsContract.FLAG_SUPPORTS_DELETE; flags |= Documents.FLAG_SUPPORTS_RENAME;
flags |= Documents.FLAG_SUPPORTS_DELETE;
} }
final String mimeType = getTypeForFile(file); final String mimeType = getTypeForFile(file);
if (mimeType.startsWith("image/")) { if (mimeType.startsWith("image/")) {
flags |= DocumentsContract.FLAG_SUPPORTS_THUMBNAIL; flags |= Documents.FLAG_SUPPORTS_THUMBNAIL;
} }
final String docId = fileToDocId(root, file); final String docId = fileToDocId(root, file);
final long id = docId.hashCode(); final long id = docId.hashCode();
final String displayName; final String displayName;
if (DocumentsContract.ROOT_DOC_ID.equals(docId)) { if (Documents.DOC_ID_ROOT.equals(docId)) {
displayName = root.title; displayName = root.title;
} else { } else {
displayName = file.getName(); displayName = file.getName();
@@ -236,6 +239,12 @@ public class ExternalStorageProvider extends ContentProvider {
@Override @Override
public String getType(Uri uri) { public String getType(Uri uri) {
switch (sMatcher.match(uri)) { switch (sMatcher.match(uri)) {
case URI_ROOTS: {
return Roots.MIME_TYPE_DIR;
}
case URI_ROOTS_ID: {
return Roots.MIME_TYPE_ITEM;
}
case URI_DOCS_ID: { case URI_DOCS_ID: {
final Root root = mRoots.get(DocumentsContract.getRootId(uri)); final Root root = mRoots.get(DocumentsContract.getRootId(uri));
final String docId = DocumentsContract.getDocId(uri); final String docId = DocumentsContract.getDocId(uri);
@@ -249,7 +258,7 @@ public class ExternalStorageProvider extends ContentProvider {
private String getTypeForFile(File file) { private String getTypeForFile(File file) {
if (file.isDirectory()) { if (file.isDirectory()) {
return DocumentsContract.MIME_TYPE_DIRECTORY; return Documents.MIME_TYPE_DIR;
} else { } else {
return getTypeForName(file.getName()); return getTypeForName(file.getName());
} }
@@ -299,7 +308,7 @@ public class ExternalStorageProvider extends ContentProvider {
values.getAsString(DocumentColumns.DISPLAY_NAME), mimeType); values.getAsString(DocumentColumns.DISPLAY_NAME), mimeType);
final File file = new File(parent, name); final File file = new File(parent, name);
if (DocumentsContract.MIME_TYPE_DIRECTORY.equals(mimeType)) { if (Documents.MIME_TYPE_DIR.equals(mimeType)) {
if (!file.mkdir()) { if (!file.mkdir()) {
return null; return null;
} }
@@ -359,7 +368,7 @@ public class ExternalStorageProvider extends ContentProvider {
} }
private String validateDisplayName(String displayName, String mimeType) { private String validateDisplayName(String displayName, String mimeType) {
if (DocumentsContract.MIME_TYPE_DIRECTORY.equals(mimeType)) { if (Documents.MIME_TYPE_DIR.equals(mimeType)) {
return displayName; return displayName;
} else { } else {
// Try appending meaningful extension if needed // Try appending meaningful extension if needed