am 0bf2ed90
: Merge "Move search to roots; Documents root; hide empty." into klp-dev
* commit '0bf2ed90c42d3a1f1d4be4b70c337f9eaec9cd14': Move search to roots; Documents root; hide empty.
This commit is contained in:
@ -17974,6 +17974,7 @@ package android.os {
|
|||||||
method public static boolean isExternalStorageRemovable();
|
method public static boolean isExternalStorageRemovable();
|
||||||
field public static java.lang.String DIRECTORY_ALARMS;
|
field public static java.lang.String DIRECTORY_ALARMS;
|
||||||
field public static java.lang.String DIRECTORY_DCIM;
|
field public static java.lang.String DIRECTORY_DCIM;
|
||||||
|
field public static java.lang.String DIRECTORY_DOCUMENTS;
|
||||||
field public static java.lang.String DIRECTORY_DOWNLOADS;
|
field public static java.lang.String DIRECTORY_DOWNLOADS;
|
||||||
field public static java.lang.String DIRECTORY_MOVIES;
|
field public static java.lang.String DIRECTORY_MOVIES;
|
||||||
field public static java.lang.String DIRECTORY_MUSIC;
|
field public static java.lang.String DIRECTORY_MUSIC;
|
||||||
@ -20811,10 +20812,9 @@ package android.provider {
|
|||||||
field public static final java.lang.String COLUMN_MIME_TYPE = "mime_type";
|
field public static final java.lang.String COLUMN_MIME_TYPE = "mime_type";
|
||||||
field public static final java.lang.String COLUMN_SIZE = "_size";
|
field public static final java.lang.String COLUMN_SIZE = "_size";
|
||||||
field public static final java.lang.String COLUMN_SUMMARY = "summary";
|
field public static final java.lang.String COLUMN_SUMMARY = "summary";
|
||||||
field public static final int FLAG_DIR_PREFERS_GRID = 32; // 0x20
|
field public static final int FLAG_DIR_PREFERS_GRID = 16; // 0x10
|
||||||
field public static final int FLAG_DIR_PREFERS_LAST_MODIFIED = 64; // 0x40
|
field public static final int FLAG_DIR_PREFERS_LAST_MODIFIED = 32; // 0x20
|
||||||
field public static final int FLAG_DIR_SUPPORTS_CREATE = 8; // 0x8
|
field public static final int FLAG_DIR_SUPPORTS_CREATE = 8; // 0x8
|
||||||
field public static final int FLAG_DIR_SUPPORTS_SEARCH = 16; // 0x10
|
|
||||||
field public static final int FLAG_SUPPORTS_DELETE = 4; // 0x4
|
field public static final int FLAG_SUPPORTS_DELETE = 4; // 0x4
|
||||||
field public static final int FLAG_SUPPORTS_THUMBNAIL = 1; // 0x1
|
field public static final int FLAG_SUPPORTS_THUMBNAIL = 1; // 0x1
|
||||||
field public static final int FLAG_SUPPORTS_WRITE = 2; // 0x2
|
field public static final int FLAG_SUPPORTS_WRITE = 2; // 0x2
|
||||||
@ -20832,9 +20832,11 @@ package android.provider {
|
|||||||
field public static final java.lang.String COLUMN_SUMMARY = "summary";
|
field public static final java.lang.String COLUMN_SUMMARY = "summary";
|
||||||
field public static final java.lang.String COLUMN_TITLE = "title";
|
field public static final java.lang.String COLUMN_TITLE = "title";
|
||||||
field public static final int FLAG_ADVANCED = 4; // 0x4
|
field public static final int FLAG_ADVANCED = 4; // 0x4
|
||||||
|
field public static final int FLAG_EMPTY = 32; // 0x20
|
||||||
field public static final int FLAG_LOCAL_ONLY = 2; // 0x2
|
field public static final int FLAG_LOCAL_ONLY = 2; // 0x2
|
||||||
field public static final int FLAG_SUPPORTS_CREATE = 1; // 0x1
|
field public static final int FLAG_SUPPORTS_CREATE = 1; // 0x1
|
||||||
field public static final int FLAG_SUPPORTS_RECENTS = 8; // 0x8
|
field public static final int FLAG_SUPPORTS_RECENTS = 8; // 0x8
|
||||||
|
field public static final int FLAG_SUPPORTS_SEARCH = 16; // 0x10
|
||||||
field public static final int ROOT_TYPE_DEVICE = 3; // 0x3
|
field public static final int ROOT_TYPE_DEVICE = 3; // 0x3
|
||||||
field public static final int ROOT_TYPE_SERVICE = 1; // 0x1
|
field public static final int ROOT_TYPE_SERVICE = 1; // 0x1
|
||||||
field public static final int ROOT_TYPE_SHORTCUT = 2; // 0x2
|
field public static final int ROOT_TYPE_SHORTCUT = 2; // 0x2
|
||||||
|
@ -460,7 +460,13 @@ public class Environment {
|
|||||||
* top-level public directory, as this convention makes no sense elsewhere.
|
* top-level public directory, as this convention makes no sense elsewhere.
|
||||||
*/
|
*/
|
||||||
public static String DIRECTORY_DCIM = "DCIM";
|
public static String DIRECTORY_DCIM = "DCIM";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Standard directory in which to place documents that have been created by
|
||||||
|
* the user.
|
||||||
|
*/
|
||||||
|
public static String DIRECTORY_DOCUMENTS = "Documents";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a top-level public external storage directory for placing files of
|
* Get a top-level public external storage directory for placing files of
|
||||||
* a particular type. This is where the user will typically place and
|
* a particular type. This is where the user will typically place and
|
||||||
|
@ -64,9 +64,9 @@ public final class DocumentsContract {
|
|||||||
// content://com.example/root/
|
// content://com.example/root/
|
||||||
// content://com.example/root/sdcard/
|
// content://com.example/root/sdcard/
|
||||||
// content://com.example/root/sdcard/recent/
|
// content://com.example/root/sdcard/recent/
|
||||||
|
// content://com.example/root/sdcard/search/?query=pony
|
||||||
// content://com.example/document/12/
|
// content://com.example/document/12/
|
||||||
// content://com.example/document/12/children/
|
// content://com.example/document/12/children/
|
||||||
// content://com.example/document/12/search/?query=pony
|
|
||||||
|
|
||||||
private DocumentsContract() {
|
private DocumentsContract() {
|
||||||
}
|
}
|
||||||
@ -174,7 +174,6 @@ public final class DocumentsContract {
|
|||||||
* @see #FLAG_SUPPORTS_THUMBNAIL
|
* @see #FLAG_SUPPORTS_THUMBNAIL
|
||||||
* @see #FLAG_DIR_PREFERS_GRID
|
* @see #FLAG_DIR_PREFERS_GRID
|
||||||
* @see #FLAG_DIR_SUPPORTS_CREATE
|
* @see #FLAG_DIR_SUPPORTS_CREATE
|
||||||
* @see #FLAG_DIR_SUPPORTS_SEARCH
|
|
||||||
*/
|
*/
|
||||||
public static final String COLUMN_FLAGS = "flags";
|
public static final String COLUMN_FLAGS = "flags";
|
||||||
|
|
||||||
@ -240,16 +239,6 @@ public final class DocumentsContract {
|
|||||||
*/
|
*/
|
||||||
public static final int FLAG_DIR_SUPPORTS_CREATE = 1 << 3;
|
public static final int FLAG_DIR_SUPPORTS_CREATE = 1 << 3;
|
||||||
|
|
||||||
/**
|
|
||||||
* Flag indicating that a directory supports search. Only valid when
|
|
||||||
* {@link #COLUMN_MIME_TYPE} is {@link #MIME_TYPE_DIR}.
|
|
||||||
*
|
|
||||||
* @see #COLUMN_FLAGS
|
|
||||||
* @see DocumentsProvider#querySearchDocuments(String, String,
|
|
||||||
* String[])
|
|
||||||
*/
|
|
||||||
public static final int FLAG_DIR_SUPPORTS_SEARCH = 1 << 4;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Flag indicating that a directory prefers its contents be shown in a
|
* Flag indicating that a directory prefers its contents be shown in a
|
||||||
* larger format grid. Usually suitable when a directory contains mostly
|
* larger format grid. Usually suitable when a directory contains mostly
|
||||||
@ -258,7 +247,7 @@ public final class DocumentsContract {
|
|||||||
*
|
*
|
||||||
* @see #COLUMN_FLAGS
|
* @see #COLUMN_FLAGS
|
||||||
*/
|
*/
|
||||||
public static final int FLAG_DIR_PREFERS_GRID = 1 << 5;
|
public static final int FLAG_DIR_PREFERS_GRID = 1 << 4;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Flag indicating that a directory prefers its contents be sorted by
|
* Flag indicating that a directory prefers its contents be sorted by
|
||||||
@ -267,7 +256,7 @@ public final class DocumentsContract {
|
|||||||
*
|
*
|
||||||
* @see #COLUMN_FLAGS
|
* @see #COLUMN_FLAGS
|
||||||
*/
|
*/
|
||||||
public static final int FLAG_DIR_PREFERS_LAST_MODIFIED = 1 << 6;
|
public static final int FLAG_DIR_PREFERS_LAST_MODIFIED = 1 << 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -306,9 +295,12 @@ public final class DocumentsContract {
|
|||||||
* <p>
|
* <p>
|
||||||
* Type: INTEGER (int)
|
* Type: INTEGER (int)
|
||||||
*
|
*
|
||||||
|
* @see #FLAG_ADVANCED
|
||||||
|
* @see #FLAG_EMPTY
|
||||||
* @see #FLAG_LOCAL_ONLY
|
* @see #FLAG_LOCAL_ONLY
|
||||||
* @see #FLAG_SUPPORTS_CREATE
|
* @see #FLAG_SUPPORTS_CREATE
|
||||||
* @see #FLAG_ADVANCED
|
* @see #FLAG_SUPPORTS_RECENTS
|
||||||
|
* @see #FLAG_SUPPORTS_SEARCH
|
||||||
*/
|
*/
|
||||||
public static final String COLUMN_FLAGS = "flags";
|
public static final String COLUMN_FLAGS = "flags";
|
||||||
|
|
||||||
@ -422,6 +414,27 @@ public final class DocumentsContract {
|
|||||||
* @see DocumentsContract#buildRecentDocumentsUri(String, String)
|
* @see DocumentsContract#buildRecentDocumentsUri(String, String)
|
||||||
*/
|
*/
|
||||||
public static final int FLAG_SUPPORTS_RECENTS = 1 << 3;
|
public static final int FLAG_SUPPORTS_RECENTS = 1 << 3;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flag indicating that this root supports search.
|
||||||
|
*
|
||||||
|
* @see #COLUMN_FLAGS
|
||||||
|
* @see DocumentsProvider#querySearchDocuments(String, String,
|
||||||
|
* String[])
|
||||||
|
*/
|
||||||
|
public static final int FLAG_SUPPORTS_SEARCH = 1 << 4;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flag indicating that this root is currently empty. This may be used
|
||||||
|
* to hide the root when opening documents, but the root will still be
|
||||||
|
* shown when creating documents and {@link #FLAG_SUPPORTS_CREATE} is
|
||||||
|
* also set.
|
||||||
|
*
|
||||||
|
* @see #COLUMN_FLAGS
|
||||||
|
* @see DocumentsProvider#querySearchDocuments(String, String,
|
||||||
|
* String[])
|
||||||
|
*/
|
||||||
|
public static final int FLAG_EMPTY = 1 << 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -493,9 +506,9 @@ public final class DocumentsContract {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Build Uri representing the recently modified documents of a specific
|
* Build Uri representing the recently modified documents of a specific root
|
||||||
* root. When queried, a provider will return zero or more rows with columns
|
* in a document provider. When queried, a provider will return zero or more
|
||||||
* defined by {@link Document}.
|
* rows with columns defined by {@link Document}.
|
||||||
*
|
*
|
||||||
* @see DocumentsProvider#queryRecentDocuments(String, String[])
|
* @see DocumentsProvider#queryRecentDocuments(String, String[])
|
||||||
* @see #getRootId(Uri)
|
* @see #getRootId(Uri)
|
||||||
@ -538,21 +551,17 @@ public final class DocumentsContract {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Build Uri representing a search for matching documents under a specific
|
* Build Uri representing a search for matching documents under a specific
|
||||||
* directory in a document provider. When queried, a provider will return
|
* root in a document provider. When queried, a provider will return zero or
|
||||||
* zero or more rows with columns defined by {@link Document}.
|
* more rows with columns defined by {@link Document}.
|
||||||
*
|
*
|
||||||
* @param parentDocumentId the document to return children for, which must
|
|
||||||
* be both a directory with MIME type of
|
|
||||||
* {@link Document#MIME_TYPE_DIR} and have
|
|
||||||
* {@link Document#FLAG_DIR_SUPPORTS_SEARCH} set.
|
|
||||||
* @see DocumentsProvider#querySearchDocuments(String, String, String[])
|
* @see DocumentsProvider#querySearchDocuments(String, String, String[])
|
||||||
* @see #getDocumentId(Uri)
|
* @see #getRootId(Uri)
|
||||||
* @see #getSearchDocumentsQuery(Uri)
|
* @see #getSearchDocumentsQuery(Uri)
|
||||||
*/
|
*/
|
||||||
public static Uri buildSearchDocumentsUri(
|
public static Uri buildSearchDocumentsUri(
|
||||||
String authority, String parentDocumentId, String query) {
|
String authority, String rootId, String query) {
|
||||||
return new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT).authority(authority)
|
return new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT).authority(authority)
|
||||||
.appendPath(PATH_DOCUMENT).appendPath(parentDocumentId).appendPath(PATH_SEARCH)
|
.appendPath(PATH_ROOT).appendPath(rootId).appendPath(PATH_SEARCH)
|
||||||
.appendQueryParameter(PARAM_QUERY, query).build();
|
.appendQueryParameter(PARAM_QUERY, query).build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -75,9 +75,9 @@ public abstract class DocumentsProvider extends ContentProvider {
|
|||||||
private static final int MATCH_ROOTS = 1;
|
private static final int MATCH_ROOTS = 1;
|
||||||
private static final int MATCH_ROOT = 2;
|
private static final int MATCH_ROOT = 2;
|
||||||
private static final int MATCH_RECENT = 3;
|
private static final int MATCH_RECENT = 3;
|
||||||
private static final int MATCH_DOCUMENT = 4;
|
private static final int MATCH_SEARCH = 4;
|
||||||
private static final int MATCH_CHILDREN = 5;
|
private static final int MATCH_DOCUMENT = 5;
|
||||||
private static final int MATCH_SEARCH = 6;
|
private static final int MATCH_CHILDREN = 6;
|
||||||
|
|
||||||
private String mAuthority;
|
private String mAuthority;
|
||||||
|
|
||||||
@ -94,9 +94,9 @@ public abstract class DocumentsProvider extends ContentProvider {
|
|||||||
mMatcher.addURI(mAuthority, "root", MATCH_ROOTS);
|
mMatcher.addURI(mAuthority, "root", MATCH_ROOTS);
|
||||||
mMatcher.addURI(mAuthority, "root/*", MATCH_ROOT);
|
mMatcher.addURI(mAuthority, "root/*", MATCH_ROOT);
|
||||||
mMatcher.addURI(mAuthority, "root/*/recent", MATCH_RECENT);
|
mMatcher.addURI(mAuthority, "root/*/recent", MATCH_RECENT);
|
||||||
|
mMatcher.addURI(mAuthority, "root/*/search", MATCH_SEARCH);
|
||||||
mMatcher.addURI(mAuthority, "document/*", MATCH_DOCUMENT);
|
mMatcher.addURI(mAuthority, "document/*", MATCH_DOCUMENT);
|
||||||
mMatcher.addURI(mAuthority, "document/*/children", MATCH_CHILDREN);
|
mMatcher.addURI(mAuthority, "document/*/children", MATCH_CHILDREN);
|
||||||
mMatcher.addURI(mAuthority, "document/*/search", MATCH_SEARCH);
|
|
||||||
|
|
||||||
// Sanity check our setup
|
// Sanity check our setup
|
||||||
if (!info.exported) {
|
if (!info.exported) {
|
||||||
@ -176,13 +176,12 @@ public abstract class DocumentsProvider extends ContentProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return documents that that match the given query, starting the search at
|
* Return documents that that match the given query.
|
||||||
* the given directory.
|
|
||||||
*
|
*
|
||||||
* @param parentDocumentId the directory to start search at.
|
* @param rootId the root to search under.
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
public Cursor querySearchDocuments(String parentDocumentId, String query, String[] projection)
|
public Cursor querySearchDocuments(String rootId, String query, String[] projection)
|
||||||
throws FileNotFoundException {
|
throws FileNotFoundException {
|
||||||
throw new UnsupportedOperationException("Search not supported");
|
throw new UnsupportedOperationException("Search not supported");
|
||||||
}
|
}
|
||||||
@ -267,6 +266,9 @@ public abstract class DocumentsProvider extends ContentProvider {
|
|||||||
return queryRoots(projection);
|
return queryRoots(projection);
|
||||||
case MATCH_RECENT:
|
case MATCH_RECENT:
|
||||||
return queryRecentDocuments(getRootId(uri), projection);
|
return queryRecentDocuments(getRootId(uri), projection);
|
||||||
|
case MATCH_SEARCH:
|
||||||
|
return querySearchDocuments(
|
||||||
|
getRootId(uri), getSearchDocumentsQuery(uri), projection);
|
||||||
case MATCH_DOCUMENT:
|
case MATCH_DOCUMENT:
|
||||||
return queryDocument(getDocumentId(uri), projection);
|
return queryDocument(getDocumentId(uri), projection);
|
||||||
case MATCH_CHILDREN:
|
case MATCH_CHILDREN:
|
||||||
@ -276,9 +278,6 @@ public abstract class DocumentsProvider extends ContentProvider {
|
|||||||
} else {
|
} else {
|
||||||
return queryChildDocuments(getDocumentId(uri), projection, sortOrder);
|
return queryChildDocuments(getDocumentId(uri), projection, sortOrder);
|
||||||
}
|
}
|
||||||
case MATCH_SEARCH:
|
|
||||||
return querySearchDocuments(
|
|
||||||
getDocumentId(uri), getSearchDocumentsQuery(uri), projection);
|
|
||||||
default:
|
default:
|
||||||
throw new UnsupportedOperationException("Unsupported Uri " + uri);
|
throw new UnsupportedOperationException("Unsupported Uri " + uri);
|
||||||
}
|
}
|
||||||
|
@ -125,9 +125,8 @@ public class DirectoryFragment extends Fragment {
|
|||||||
show(fm, TYPE_NORMAL, root, doc, null);
|
show(fm, TYPE_NORMAL, root, doc, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void showSearch(
|
public static void showSearch(FragmentManager fm, RootInfo root, String query) {
|
||||||
FragmentManager fm, RootInfo root, DocumentInfo doc, String query) {
|
show(fm, TYPE_SEARCH, root, null, query);
|
||||||
show(fm, TYPE_SEARCH, root, doc, query);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void showRecentsOpen(FragmentManager fm) {
|
public static void showRecentsOpen(FragmentManager fm) {
|
||||||
@ -205,7 +204,7 @@ public class DirectoryFragment extends Fragment {
|
|||||||
context, mType, root, doc, contentsUri, state.userSortOrder);
|
context, mType, root, doc, contentsUri, state.userSortOrder);
|
||||||
case TYPE_SEARCH:
|
case TYPE_SEARCH:
|
||||||
contentsUri = DocumentsContract.buildSearchDocumentsUri(
|
contentsUri = DocumentsContract.buildSearchDocumentsUri(
|
||||||
doc.authority, doc.documentId, query);
|
root.authority, root.rootId, query);
|
||||||
if (state.action == ACTION_MANAGE) {
|
if (state.action == ACTION_MANAGE) {
|
||||||
contentsUri = DocumentsContract.setManageMode(contentsUri);
|
contentsUri = DocumentsContract.setManageMode(contentsUri);
|
||||||
}
|
}
|
||||||
@ -274,7 +273,7 @@ public class DirectoryFragment extends Fragment {
|
|||||||
final RootInfo root = getArguments().getParcelable(EXTRA_ROOT);
|
final RootInfo root = getArguments().getParcelable(EXTRA_ROOT);
|
||||||
final DocumentInfo doc = getArguments().getParcelable(EXTRA_DOC);
|
final DocumentInfo doc = getArguments().getParcelable(EXTRA_DOC);
|
||||||
|
|
||||||
if (root != null) {
|
if (root != null && doc != null) {
|
||||||
final Uri stateUri = RecentsProvider.buildState(
|
final Uri stateUri = RecentsProvider.buildState(
|
||||||
root.authority, root.rootId, doc.documentId);
|
root.authority, root.rootId, doc.documentId);
|
||||||
final ContentValues values = new ContentValues();
|
final ContentValues values = new ContentValues();
|
||||||
|
@ -32,6 +32,7 @@ import android.database.Cursor;
|
|||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.CancellationSignal;
|
import android.os.CancellationSignal;
|
||||||
import android.os.OperationCanceledException;
|
import android.os.OperationCanceledException;
|
||||||
|
import android.provider.DocumentsContract;
|
||||||
import android.provider.DocumentsContract.Document;
|
import android.provider.DocumentsContract.Document;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
@ -42,6 +43,8 @@ import com.android.documentsui.model.RootInfo;
|
|||||||
|
|
||||||
import libcore.io.IoUtils;
|
import libcore.io.IoUtils;
|
||||||
|
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
|
||||||
class DirectoryResult implements AutoCloseable {
|
class DirectoryResult implements AutoCloseable {
|
||||||
ContentProviderClient client;
|
ContentProviderClient client;
|
||||||
Cursor cursor;
|
Cursor cursor;
|
||||||
@ -64,7 +67,7 @@ public class DirectoryLoader extends AsyncTaskLoader<DirectoryResult> {
|
|||||||
|
|
||||||
private final int mType;
|
private final int mType;
|
||||||
private final RootInfo mRoot;
|
private final RootInfo mRoot;
|
||||||
private final DocumentInfo mDoc;
|
private DocumentInfo mDoc;
|
||||||
private final Uri mUri;
|
private final Uri mUri;
|
||||||
private final int mUserSortOrder;
|
private final int mUserSortOrder;
|
||||||
|
|
||||||
@ -97,6 +100,19 @@ public class DirectoryLoader extends AsyncTaskLoader<DirectoryResult> {
|
|||||||
|
|
||||||
int userMode = State.MODE_UNKNOWN;
|
int userMode = State.MODE_UNKNOWN;
|
||||||
|
|
||||||
|
// Use default document when searching
|
||||||
|
if (mType == DirectoryFragment.TYPE_SEARCH) {
|
||||||
|
final Uri docUri = DocumentsContract.buildDocumentUri(
|
||||||
|
mRoot.authority, mRoot.documentId);
|
||||||
|
try {
|
||||||
|
mDoc = DocumentInfo.fromUri(resolver, docUri);
|
||||||
|
} catch (FileNotFoundException e) {
|
||||||
|
Log.w(TAG, "Failed to query", e);
|
||||||
|
result.exception = e;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Pick up any custom modes requested by user
|
// Pick up any custom modes requested by user
|
||||||
Cursor cursor = null;
|
Cursor cursor = null;
|
||||||
try {
|
try {
|
||||||
@ -157,7 +173,7 @@ public class DirectoryLoader extends AsyncTaskLoader<DirectoryResult> {
|
|||||||
|
|
||||||
result.cursor = cursor;
|
result.cursor = cursor;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Log.d(TAG, "Failed to query", e);
|
Log.w(TAG, "Failed to query", e);
|
||||||
result.exception = e;
|
result.exception = e;
|
||||||
ContentProviderClient.closeQuietly(result.client);
|
ContentProviderClient.closeQuietly(result.client);
|
||||||
} finally {
|
} finally {
|
||||||
|
@ -45,6 +45,7 @@ import android.net.Uri;
|
|||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Parcel;
|
import android.os.Parcel;
|
||||||
import android.provider.DocumentsContract;
|
import android.provider.DocumentsContract;
|
||||||
|
import android.provider.DocumentsContract.Root;
|
||||||
import android.support.v4.app.ActionBarDrawerToggle;
|
import android.support.v4.app.ActionBarDrawerToggle;
|
||||||
import android.support.v4.view.GravityCompat;
|
import android.support.v4.view.GravityCompat;
|
||||||
import android.support.v4.widget.DrawerLayout;
|
import android.support.v4.widget.DrawerLayout;
|
||||||
@ -442,6 +443,8 @@ public class DocumentsActivity extends Activity {
|
|||||||
super.onPrepareOptionsMenu(menu);
|
super.onPrepareOptionsMenu(menu);
|
||||||
|
|
||||||
final FragmentManager fm = getFragmentManager();
|
final FragmentManager fm = getFragmentManager();
|
||||||
|
|
||||||
|
final RootInfo root = getCurrentRoot();
|
||||||
final DocumentInfo cwd = getCurrentDirectory();
|
final DocumentInfo cwd = getCurrentDirectory();
|
||||||
|
|
||||||
final MenuItem createDir = menu.findItem(R.id.menu_create_dir);
|
final MenuItem createDir = menu.findItem(R.id.menu_create_dir);
|
||||||
@ -503,7 +506,9 @@ public class DocumentsActivity extends Activity {
|
|||||||
SaveFragment.get(fm).setSaveEnabled(cwd != null && cwd.isCreateSupported());
|
SaveFragment.get(fm).setSaveEnabled(cwd != null && cwd.isCreateSupported());
|
||||||
} else {
|
} else {
|
||||||
createDir.setVisible(false);
|
createDir.setVisible(false);
|
||||||
searchVisible = cwd != null && cwd.isSearchSupported();
|
|
||||||
|
searchVisible = root != null
|
||||||
|
&& ((root.flags & Root.FLAG_SUPPORTS_SEARCH) != 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: close any search in-progress when hiding
|
// TODO: close any search in-progress when hiding
|
||||||
@ -722,7 +727,7 @@ public class DocumentsActivity extends Activity {
|
|||||||
} else {
|
} else {
|
||||||
if (mState.currentSearch != null) {
|
if (mState.currentSearch != null) {
|
||||||
// Ongoing search
|
// Ongoing search
|
||||||
DirectoryFragment.showSearch(fm, root, cwd, mState.currentSearch);
|
DirectoryFragment.showSearch(fm, root, mState.currentSearch);
|
||||||
} else {
|
} else {
|
||||||
// Normal boring directory
|
// Normal boring directory
|
||||||
DirectoryFragment.showNormal(fm, root, cwd);
|
DirectoryFragment.showNormal(fm, root, cwd);
|
||||||
|
@ -176,6 +176,7 @@ public class RootsCache {
|
|||||||
final boolean supportsCreate = (root.flags & Root.FLAG_SUPPORTS_CREATE) != 0;
|
final boolean supportsCreate = (root.flags & Root.FLAG_SUPPORTS_CREATE) != 0;
|
||||||
final boolean advanced = (root.flags & Root.FLAG_ADVANCED) != 0;
|
final boolean advanced = (root.flags & Root.FLAG_ADVANCED) != 0;
|
||||||
final boolean localOnly = (root.flags & Root.FLAG_LOCAL_ONLY) != 0;
|
final boolean localOnly = (root.flags & Root.FLAG_LOCAL_ONLY) != 0;
|
||||||
|
final boolean empty = (root.flags & Root.FLAG_EMPTY) != 0;
|
||||||
|
|
||||||
// Exclude read-only devices when creating
|
// Exclude read-only devices when creating
|
||||||
if (state.action == State.ACTION_CREATE && !supportsCreate) continue;
|
if (state.action == State.ACTION_CREATE && !supportsCreate) continue;
|
||||||
@ -183,6 +184,8 @@ public class RootsCache {
|
|||||||
if (!state.showAdvanced && advanced) continue;
|
if (!state.showAdvanced && advanced) continue;
|
||||||
// Exclude non-local devices when local only
|
// Exclude non-local devices when local only
|
||||||
if (state.localOnly && !localOnly) continue;
|
if (state.localOnly && !localOnly) continue;
|
||||||
|
// Only show empty roots when creating
|
||||||
|
if (state.action != State.ACTION_CREATE && empty) continue;
|
||||||
|
|
||||||
// Only include roots that serve requested content
|
// Only include roots that serve requested content
|
||||||
final boolean overlap =
|
final boolean overlap =
|
||||||
|
@ -188,10 +188,6 @@ public class DocumentInfo implements Durable, Parcelable {
|
|||||||
return (flags & Document.FLAG_DIR_SUPPORTS_CREATE) != 0;
|
return (flags & Document.FLAG_DIR_SUPPORTS_CREATE) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isSearchSupported() {
|
|
||||||
return (flags & Document.FLAG_DIR_SUPPORTS_SEARCH) != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isThumbnailSupported() {
|
public boolean isThumbnailSupported() {
|
||||||
return (flags & Document.FLAG_SUPPORTS_THUMBNAIL) != 0;
|
return (flags & Document.FLAG_SUPPORTS_THUMBNAIL) != 0;
|
||||||
}
|
}
|
||||||
|
@ -161,15 +161,21 @@ public class RootInfo implements Durable, Parcelable {
|
|||||||
|
|
||||||
// TODO: remove these special case icons
|
// TODO: remove these special case icons
|
||||||
if ("com.android.externalstorage.documents".equals(authority)) {
|
if ("com.android.externalstorage.documents".equals(authority)) {
|
||||||
derivedIcon = R.drawable.ic_root_sdcard;
|
if ("documents".equals(rootId)) {
|
||||||
|
derivedIcon = R.drawable.ic_doc_text;
|
||||||
|
} else {
|
||||||
|
derivedIcon = R.drawable.ic_root_sdcard;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if ("com.android.providers.downloads.documents".equals(authority)) {
|
if ("com.android.providers.downloads.documents".equals(authority)) {
|
||||||
derivedIcon = R.drawable.ic_root_download;
|
derivedIcon = R.drawable.ic_root_download;
|
||||||
}
|
}
|
||||||
if ("com.android.providers.media.documents".equals(authority)) {
|
if ("com.android.providers.media.documents".equals(authority)) {
|
||||||
if ("image".equals(rootId)) {
|
if ("images_root".equals(rootId)) {
|
||||||
derivedIcon = R.drawable.ic_doc_image;
|
derivedIcon = R.drawable.ic_doc_image;
|
||||||
} else if ("audio".equals(rootId)) {
|
} else if ("videos_root".equals(rootId)) {
|
||||||
|
derivedIcon = R.drawable.ic_doc_video;
|
||||||
|
} else if ("audio_root".equals(rootId)) {
|
||||||
derivedIcon = R.drawable.ic_doc_audio;
|
derivedIcon = R.drawable.ic_doc_audio;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,11 @@
|
|||||||
-->
|
-->
|
||||||
|
|
||||||
<resources>
|
<resources>
|
||||||
|
<!-- Title of the external storage application [CHAR LIMIT=32] -->
|
||||||
<string name="app_label">External Storage</string>
|
<string name="app_label">External Storage</string>
|
||||||
|
|
||||||
|
<!-- Title for documents backend that offers internal storage. [CHAR LIMIT=24] -->
|
||||||
<string name="root_internal_storage">Internal storage</string>
|
<string name="root_internal_storage">Internal storage</string>
|
||||||
|
<!-- Title for documents backend that offers documents. [CHAR LIMIT=24] -->
|
||||||
|
<string name="root_documents">Documents</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
@ -62,7 +62,6 @@ public class ExternalStorageProvider extends DocumentsProvider {
|
|||||||
public String rootId;
|
public String rootId;
|
||||||
public int rootType;
|
public int rootType;
|
||||||
public int flags;
|
public int flags;
|
||||||
public int icon;
|
|
||||||
public String title;
|
public String title;
|
||||||
public String docId;
|
public String docId;
|
||||||
}
|
}
|
||||||
@ -85,9 +84,10 @@ public class ExternalStorageProvider extends DocumentsProvider {
|
|||||||
mIdToPath.put(rootId, path);
|
mIdToPath.put(rootId, path);
|
||||||
|
|
||||||
final RootInfo root = new RootInfo();
|
final RootInfo root = new RootInfo();
|
||||||
root.rootId = "primary";
|
root.rootId = rootId;
|
||||||
root.rootType = Root.ROOT_TYPE_DEVICE;
|
root.rootType = Root.ROOT_TYPE_DEVICE;
|
||||||
root.flags = Root.FLAG_SUPPORTS_CREATE | Root.FLAG_LOCAL_ONLY | Root.FLAG_ADVANCED;
|
root.flags = Root.FLAG_SUPPORTS_CREATE | Root.FLAG_LOCAL_ONLY | Root.FLAG_ADVANCED
|
||||||
|
| Root.FLAG_SUPPORTS_SEARCH;
|
||||||
root.title = getContext().getString(R.string.root_internal_storage);
|
root.title = getContext().getString(R.string.root_internal_storage);
|
||||||
root.docId = getDocIdForFile(path);
|
root.docId = getDocIdForFile(path);
|
||||||
mRoots.add(root);
|
mRoots.add(root);
|
||||||
@ -96,6 +96,25 @@ public class ExternalStorageProvider extends DocumentsProvider {
|
|||||||
throw new IllegalStateException(e);
|
throw new IllegalStateException(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
final String rootId = "documents";
|
||||||
|
final File path = Environment.getExternalStoragePublicDirectory(
|
||||||
|
Environment.DIRECTORY_DOCUMENTS);
|
||||||
|
mIdToPath.put(rootId, path);
|
||||||
|
|
||||||
|
final RootInfo root = new RootInfo();
|
||||||
|
root.rootId = rootId;
|
||||||
|
root.rootType = Root.ROOT_TYPE_SHORTCUT;
|
||||||
|
root.flags = Root.FLAG_SUPPORTS_CREATE | Root.FLAG_LOCAL_ONLY
|
||||||
|
| Root.FLAG_SUPPORTS_SEARCH;
|
||||||
|
root.title = getContext().getString(R.string.root_documents);
|
||||||
|
root.docId = getDocIdForFile(path);
|
||||||
|
mRoots.add(root);
|
||||||
|
mIdToRoot.put(rootId, root);
|
||||||
|
} catch (FileNotFoundException e) {
|
||||||
|
throw new IllegalStateException(e);
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -146,6 +165,9 @@ public class ExternalStorageProvider extends DocumentsProvider {
|
|||||||
if (target == null) {
|
if (target == null) {
|
||||||
throw new FileNotFoundException("No root for " + tag);
|
throw new FileNotFoundException("No root for " + tag);
|
||||||
}
|
}
|
||||||
|
if (!target.exists()) {
|
||||||
|
target.mkdirs();
|
||||||
|
}
|
||||||
target = new File(target, path);
|
target = new File(target, path);
|
||||||
if (!target.exists()) {
|
if (!target.exists()) {
|
||||||
throw new FileNotFoundException("Missing file for " + docId + " at " + target);
|
throw new FileNotFoundException("Missing file for " + docId + " at " + target);
|
||||||
@ -163,9 +185,6 @@ public class ExternalStorageProvider extends DocumentsProvider {
|
|||||||
|
|
||||||
int flags = 0;
|
int flags = 0;
|
||||||
|
|
||||||
if (file.isDirectory()) {
|
|
||||||
flags |= Document.FLAG_DIR_SUPPORTS_SEARCH;
|
|
||||||
}
|
|
||||||
if (file.isDirectory() && file.canWrite()) {
|
if (file.isDirectory() && file.canWrite()) {
|
||||||
flags |= Document.FLAG_DIR_SUPPORTS_CREATE;
|
flags |= Document.FLAG_DIR_SUPPORTS_CREATE;
|
||||||
}
|
}
|
||||||
@ -200,7 +219,6 @@ public class ExternalStorageProvider extends DocumentsProvider {
|
|||||||
row.add(Root.COLUMN_ROOT_ID, root.rootId);
|
row.add(Root.COLUMN_ROOT_ID, root.rootId);
|
||||||
row.add(Root.COLUMN_ROOT_TYPE, root.rootType);
|
row.add(Root.COLUMN_ROOT_TYPE, root.rootType);
|
||||||
row.add(Root.COLUMN_FLAGS, root.flags);
|
row.add(Root.COLUMN_FLAGS, root.flags);
|
||||||
row.add(Root.COLUMN_ICON, root.icon);
|
|
||||||
row.add(Root.COLUMN_TITLE, root.title);
|
row.add(Root.COLUMN_TITLE, root.title);
|
||||||
row.add(Root.COLUMN_DOCUMENT_ID, root.docId);
|
row.add(Root.COLUMN_DOCUMENT_ID, root.docId);
|
||||||
row.add(Root.COLUMN_AVAILABLE_BYTES, path.getFreeSpace());
|
row.add(Root.COLUMN_AVAILABLE_BYTES, path.getFreeSpace());
|
||||||
@ -260,10 +278,10 @@ public class ExternalStorageProvider extends DocumentsProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Cursor querySearchDocuments(String parentDocumentId, String query, String[] projection)
|
public Cursor querySearchDocuments(String rootId, String query, String[] projection)
|
||||||
throws FileNotFoundException {
|
throws FileNotFoundException {
|
||||||
final MatrixCursor result = new MatrixCursor(resolveDocumentProjection(projection));
|
final MatrixCursor result = new MatrixCursor(resolveDocumentProjection(projection));
|
||||||
final File parent = getFileForDocId(parentDocumentId);
|
final File parent = mIdToPath.get(rootId);
|
||||||
|
|
||||||
final LinkedList<File> pending = new LinkedList<File>();
|
final LinkedList<File> pending = new LinkedList<File>();
|
||||||
pending.add(parent);
|
pending.add(parent);
|
||||||
|
Reference in New Issue
Block a user