diff options
12 files changed, 201 insertions, 63 deletions
diff --git a/packages/DocumentsUI/res/drawable/item_background.xml b/packages/DocumentsUI/res/drawable/item_background.xml index 7447aa8..6fcab3c 100644 --- a/packages/DocumentsUI/res/drawable/item_background.xml +++ b/packages/DocumentsUI/res/drawable/item_background.xml @@ -16,18 +16,16 @@ <selector xmlns:android="http://schemas.android.com/apk/res/android"> - <item android:state_enabled="false" android:state_selected="true" android:drawable="@*android:drawable/list_selector_disabled_holo_light" /> - <item android:state_enabled="false" android:state_focused="true" android:drawable="@*android:drawable/list_selector_disabled_holo_light" /> - <item android:state_enabled="false" android:state_pressed="true" android:drawable="@*android:drawable/list_selector_disabled_holo_light" /> + <item android:state_window_focused="false" android:drawable="@android:color/transparent" /> - <item android:state_activated="true" android:state_pressed="true" android:drawable="@*android:drawable/list_activated_holo" /> - <item android:state_activated="true" android:drawable="@*android:drawable/list_activated_holo" /> + <item android:state_focused="true" android:state_activated="true" android:drawable="@*android:drawable/list_selected_holo_light" /> + <item android:state_focused="false" android:state_activated="true" android:drawable="@*android:drawable/list_selected_holo_light" /> - <item android:state_focused="true" android:drawable="@*android:drawable/list_focused_holo" /> - <item android:state_selected="true" android:drawable="@*android:drawable/list_focused_holo" /> - - <item android:state_pressed="true" android:state_focused="true" android:drawable="@*android:drawable/list_selector_background_transition_holo_light" /> - <item android:state_pressed="true" android:drawable="@*android:drawable/list_selector_background_transition_holo_light" /> + <item android:state_focused="true" android:state_enabled="false" android:state_pressed="true" android:drawable="@*android:drawable/list_selector_disabled_holo_light" /> + <item android:state_focused="true" android:state_enabled="false" android:drawable="@*android:drawable/list_selector_disabled_holo_light" /> + <item android:state_focused="true" android:state_pressed="true" android:drawable="@*android:drawable/list_selector_background_transition_holo_light" /> + <item android:state_focused="false" android:state_pressed="true" android:drawable="@*android:drawable/list_selector_background_transition_holo_light" /> + <item android:state_focused="true" android:drawable="@*android:drawable/list_focused_holo" /> <item android:drawable="@android:color/transparent" /> diff --git a/packages/DocumentsUI/res/layout/fragment_directory.xml b/packages/DocumentsUI/res/layout/fragment_directory.xml index 98ded34..77cdc3b 100644 --- a/packages/DocumentsUI/res/layout/fragment_directory.xml +++ b/packages/DocumentsUI/res/layout/fragment_directory.xml @@ -42,6 +42,7 @@ android:paddingEnd="@dimen/grid_padding_horiz" android:paddingTop="@dimen/grid_padding" android:paddingBottom="@dimen/grid_padding" + android:clipToPadding="false" android:scrollbarStyle="outsideOverlay" android:listSelector="@android:color/transparent" android:visibility="gone" /> diff --git a/packages/DocumentsUI/res/values/dimens.xml b/packages/DocumentsUI/res/values/dimens.xml index 4a93cdb..924a8d6 100644 --- a/packages/DocumentsUI/res/values/dimens.xml +++ b/packages/DocumentsUI/res/values/dimens.xml @@ -17,8 +17,8 @@ <resources> <dimen name="icon_size">32dp</dimen> <dimen name="root_icon_size">24dp</dimen> - <dimen name="grid_width">180dp</dimen> - <dimen name="grid_height">180dp</dimen> + <dimen name="grid_width">160dp</dimen> + <dimen name="grid_height">170dp</dimen> <dimen name="grid_padding">4dp</dimen> <dimen name="grid_padding_horiz">4dp</dimen> diff --git a/packages/DocumentsUI/res/values/strings.xml b/packages/DocumentsUI/res/values/strings.xml index 682ae4a..b7dcb71 100644 --- a/packages/DocumentsUI/res/values/strings.xml +++ b/packages/DocumentsUI/res/values/strings.xml @@ -62,6 +62,8 @@ <!-- Toast shown when saving a document failed with an error [CHAR LIMIT=48] --> <string name="save_error">Failed to save document</string> + <!-- Toast shown when creating a folder failed with an error [CHAR LIMIT=48] --> + <string name="create_error">Failed to create folder</string> <!-- Title of storage root location that contains recently modified or used documents [CHAR LIMIT=24] --> <string name="root_recent">Recent</string> diff --git a/packages/DocumentsUI/src/com/android/documentsui/CreateDirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/CreateDirectoryFragment.java index d8e60aa..9d92cd8 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/CreateDirectoryFragment.java +++ b/packages/DocumentsUI/src/com/android/documentsui/CreateDirectoryFragment.java @@ -76,7 +76,7 @@ public class CreateDirectoryFragment extends DialogFragment { final DocumentInfo childDoc = DocumentInfo.fromUri(resolver, childUri); activity.onDocumentPicked(childDoc); } catch (Exception e) { - Toast.makeText(context, R.string.save_error, Toast.LENGTH_SHORT).show(); + Toast.makeText(context, R.string.create_error, Toast.LENGTH_SHORT).show(); } } }); diff --git a/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java index de1f130..79ab28d 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java +++ b/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java @@ -715,8 +715,16 @@ public class DirectoryFragment extends Fragment { final FrameLayout grid = (FrameLayout) convertView; final int gridPadding = getResources() .getDimensionPixelSize(R.dimen.grid_padding); - grid.setForeground(new InsetDrawable(grid.getForeground(), gridPadding)); - grid.setBackground(new InsetDrawable(grid.getBackground(), gridPadding)); + + // Tricksy hobbitses! We need to fully clear the drawable so + // the view doesn't clobber the new InsetDrawable callback + // when setting back later. + final Drawable fg = grid.getForeground(); + final Drawable bg = grid.getBackground(); + grid.setForeground(null); + grid.setBackground(null); + grid.setForeground(new InsetDrawable(fg, gridPadding)); + grid.setBackground(new InsetDrawable(bg, gridPadding)); } else { throw new IllegalStateException(); } diff --git a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java index 6d5475d..8d55ec4 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java +++ b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java @@ -285,6 +285,7 @@ public class DocumentsActivity extends Activity { private class RestoreStackTask extends AsyncTask<Void, Void, Void> { private volatile boolean mRestoredStack; + private volatile boolean mExternal; @Override protected Void doInBackground(Void... params) { @@ -298,6 +299,7 @@ public class DocumentsActivity extends Activity { cursor.getColumnIndex(ResumeColumns.STACK)); DurableUtils.readFromArray(rawStack, mState.stack); mRestoredStack = true; + mExternal = cursor.getInt(cursor.getColumnIndex(ResumeColumns.EXTERNAL)) != 0; } } catch (IOException e) { Log.w(TAG, "Failed to resume", e); @@ -305,12 +307,17 @@ public class DocumentsActivity extends Activity { IoUtils.closeQuietly(cursor); } - // If restored root isn't valid, fall back to recents - final RootInfo root = getCurrentRoot(); - final Collection<RootInfo> matchingRoots = mRoots.getMatchingRootsBlocking(mState); - if (!matchingRoots.contains(root)) { - mState.stack.reset(); - mRestoredStack = false; + if (mRestoredStack) { + // Update the restored stack to ensure we have freshest data + final Collection<RootInfo> matchingRoots = mRoots.getMatchingRootsBlocking(mState); + try { + mState.stack.updateRoot(matchingRoots); + mState.stack.updateDocuments(getContentResolver()); + } catch (FileNotFoundException e) { + Log.w(TAG, "Failed to restore stack: " + e); + mState.stack.reset(); + mRestoredStack = false; + } } return null; @@ -321,10 +328,22 @@ public class DocumentsActivity extends Activity { if (isDestroyed()) return; mState.restored = true; - // Only open drawer when not restoring stack, and when not showing - // visual content. - if (!mRestoredStack - && !MimePredicate.mimeMatches(MimePredicate.VISUAL_MIMES, mState.acceptMimes)) { + // Show drawer when no stack restored, but only when requesting + // non-visual content. However, if we last used an external app, + // drawer is always shown. + + boolean showDrawer = false; + if (!mRestoredStack) { + showDrawer = true; + } + if (MimePredicate.mimeMatches(MimePredicate.VISUAL_MIMES, mState.acceptMimes)) { + showDrawer = false; + } + if (mExternal && mState.action == ACTION_GET_CONTENT) { + showDrawer = true; + } + + if (showDrawer) { setRootsDrawerOpen(true); } @@ -340,6 +359,7 @@ public class DocumentsActivity extends Activity { mState.showSize = true; } else { mState.showSize = SettingsActivity.getDisplayFileSize(this); + invalidateOptionsMenu(); } } @@ -779,10 +799,10 @@ public class DocumentsActivity extends Activity { } else { DirectoryFragment.showRecentsOpen(fm, anim); - // Start recents in relevant mode - final boolean acceptImages = MimePredicate.mimeMatches( - "image/*", mState.acceptMimes); - mState.userMode = acceptImages ? MODE_GRID : MODE_LIST; + // Start recents in grid when requesting visual things + final boolean visualMimes = MimePredicate.mimeMatches( + MimePredicate.VISUAL_MIMES, mState.acceptMimes); + mState.userMode = visualMimes ? MODE_GRID : MODE_LIST; mState.derivedMode = mState.userMode; } } else { @@ -814,9 +834,17 @@ public class DocumentsActivity extends Activity { } public void onStackPicked(DocumentStack stack) { - mState.stack = stack; - mState.stackTouched = true; - onCurrentDirectoryChanged(ANIM_SIDE); + try { + // Update the restored stack to ensure we have freshest data + stack.updateDocuments(getContentResolver()); + + mState.stack = stack; + mState.stackTouched = true; + onCurrentDirectoryChanged(ANIM_SIDE); + + } catch (FileNotFoundException e) { + Log.w(TAG, "Failed to restore stack: " + e); + } } public void onRootPicked(RootInfo root, boolean closeDrawer) { @@ -858,6 +886,14 @@ public class DocumentsActivity extends Activity { // Only relay back results when not canceled; otherwise stick around to // let the user pick another app/backend. if (requestCode == CODE_FORWARD && resultCode != RESULT_CANCELED) { + + // Remember that we last picked via external app + final String packageName = getCallingPackage(); + final ContentValues values = new ContentValues(); + values.put(ResumeColumns.EXTERNAL, 1); + getContentResolver().insert(RecentsProvider.buildResume(packageName), values); + + // Pass back result to original caller setResult(resultCode, data); finish(); } else { @@ -945,6 +981,7 @@ public class DocumentsActivity extends Activity { final String packageName = getCallingPackage(); values.clear(); values.put(ResumeColumns.STACK, rawStack); + values.put(ResumeColumns.EXTERNAL, 0); resolver.insert(RecentsProvider.buildResume(packageName), values); final Intent intent = new Intent(); diff --git a/packages/DocumentsUI/src/com/android/documentsui/RecentsCreateFragment.java b/packages/DocumentsUI/src/com/android/documentsui/RecentsCreateFragment.java index a396f79..670d5c0 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/RecentsCreateFragment.java +++ b/packages/DocumentsUI/src/com/android/documentsui/RecentsCreateFragment.java @@ -45,8 +45,10 @@ import android.widget.ImageView; import android.widget.ListView; import android.widget.TextView; +import com.android.documentsui.DocumentsActivity.State; import com.android.documentsui.RecentsProvider.RecentColumns; import com.android.documentsui.model.DocumentStack; +import com.android.documentsui.model.RootInfo; import com.google.android.collect.Lists; import libcore.io.IoUtils; @@ -55,6 +57,7 @@ import java.io.ByteArrayInputStream; import java.io.DataInputStream; import java.io.IOException; import java.util.ArrayList; +import java.util.Collection; import java.util.List; /** @@ -89,10 +92,13 @@ public class RecentsCreateFragment extends Fragment { mAdapter = new DocumentStackAdapter(); mListView.setAdapter(mAdapter); + final RootsCache roots = DocumentsApplication.getRootsCache(context); + final State state = ((DocumentsActivity) getActivity()).getDisplayState(); + mCallbacks = new LoaderCallbacks<List<DocumentStack>>() { @Override public Loader<List<DocumentStack>> onCreateLoader(int id, Bundle args) { - return new RecentsCreateLoader(context); + return new RecentsCreateLoader(context, roots, state); } @Override @@ -131,12 +137,18 @@ public class RecentsCreateFragment extends Fragment { }; public static class RecentsCreateLoader extends UriDerivativeLoader<Uri, List<DocumentStack>> { - public RecentsCreateLoader(Context context) { + private final RootsCache mRoots; + private final State mState; + + public RecentsCreateLoader(Context context, RootsCache roots, State state) { super(context, RecentsProvider.buildRecent()); + mRoots = roots; + mState = state; } @Override public List<DocumentStack> loadInBackground(Uri uri, CancellationSignal signal) { + final Collection<RootInfo> matchingRoots = mRoots.getMatchingRootsBlocking(mState); final ArrayList<DocumentStack> result = Lists.newArrayList(); final ContentResolver resolver = getContext().getContentResolver(); @@ -149,6 +161,12 @@ public class RecentsCreateFragment extends Fragment { try { final DocumentStack stack = new DocumentStack(); stack.read(new DataInputStream(new ByteArrayInputStream(rawStack))); + + // Only update root here to avoid spinning up all + // providers; we update the stack during the actual + // restore. This also filters away roots that don't + // match current filter. + stack.updateRoot(matchingRoots); result.add(stack); } catch (IOException e) { Log.w(TAG, "Failed to resolve stack: " + e); diff --git a/packages/DocumentsUI/src/com/android/documentsui/RecentsProvider.java b/packages/DocumentsUI/src/com/android/documentsui/RecentsProvider.java index af79c93..7386cae 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/RecentsProvider.java +++ b/packages/DocumentsUI/src/com/android/documentsui/RecentsProvider.java @@ -72,6 +72,7 @@ public class RecentsProvider extends ContentProvider { public static final String PACKAGE_NAME = "package_name"; public static final String STACK = "stack"; public static final String TIMESTAMP = "timestamp"; + public static final String EXTERNAL = "external"; } public static Uri buildRecent() { @@ -97,9 +98,10 @@ public class RecentsProvider extends ContentProvider { private static final int VERSION_INIT = 1; private static final int VERSION_AS_BLOB = 3; + private static final int VERSION_ADD_EXTERNAL = 4; public DatabaseHelper(Context context) { - super(context, DB_NAME, null, VERSION_AS_BLOB); + super(context, DB_NAME, null, VERSION_ADD_EXTERNAL); } @Override @@ -121,9 +123,10 @@ public class RecentsProvider extends ContentProvider { ")"); db.execSQL("CREATE TABLE " + TABLE_RESUME + " (" + - ResumeColumns.PACKAGE_NAME + " TEXT PRIMARY KEY ON CONFLICT REPLACE," + - ResumeColumns.STACK + " BLOB," + - ResumeColumns.TIMESTAMP + " INTEGER" + + ResumeColumns.PACKAGE_NAME + " TEXT NOT NULL PRIMARY KEY," + + ResumeColumns.STACK + " BLOB DEFAULT NULL," + + ResumeColumns.TIMESTAMP + " INTEGER," + + ResumeColumns.EXTERNAL + " INTEGER NOT NULL DEFAULT 0" + ")"); } @@ -176,6 +179,7 @@ public class RecentsProvider extends ContentProvider { @Override public Uri insert(Uri uri, ContentValues values) { final SQLiteDatabase db = mHelper.getWritableDatabase(); + final ContentValues key = new ContentValues(); switch (sMatcher.match(uri)) { case URI_RECENT: values.put(RecentColumns.TIMESTAMP, System.currentTimeMillis()); @@ -188,7 +192,6 @@ public class RecentsProvider extends ContentProvider { final String rootId = uri.getPathSegments().get(2); final String documentId = uri.getPathSegments().get(3); - final ContentValues key = new ContentValues(); key.put(StateColumns.AUTHORITY, authority); key.put(StateColumns.ROOT_ID, rootId); key.put(StateColumns.DOCUMENT_ID, documentId); @@ -201,10 +204,15 @@ public class RecentsProvider extends ContentProvider { return uri; case URI_RESUME: - final String packageName = uri.getPathSegments().get(1); - values.put(ResumeColumns.PACKAGE_NAME, packageName); values.put(ResumeColumns.TIMESTAMP, System.currentTimeMillis()); - db.insert(TABLE_RESUME, null, values); + + final String packageName = uri.getPathSegments().get(1); + key.put(ResumeColumns.PACKAGE_NAME, packageName); + + // Ensure that row exists, then update with changed values + db.insertWithOnConflict(TABLE_RESUME, null, key, SQLiteDatabase.CONFLICT_IGNORE); + db.update(TABLE_RESUME, values, ResumeColumns.PACKAGE_NAME + "=?", + new String[] { packageName }); return uri; default: throw new UnsupportedOperationException("Unsupported Uri " + uri); diff --git a/packages/DocumentsUI/src/com/android/documentsui/TestActivity.java b/packages/DocumentsUI/src/com/android/documentsui/TestActivity.java index 7b7c3d5..1cc35a7 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/TestActivity.java +++ b/packages/DocumentsUI/src/com/android/documentsui/TestActivity.java @@ -27,6 +27,7 @@ import android.view.View.OnClickListener; import android.widget.Button; import android.widget.CheckBox; import android.widget.LinearLayout; +import android.widget.ScrollView; import android.widget.TextView; import libcore.io.IoUtils; @@ -52,6 +53,9 @@ public class TestActivity extends Activity { final LinearLayout view = new LinearLayout(context); view.setOrientation(LinearLayout.VERTICAL); + mResult = new TextView(context); + view.addView(mResult); + final CheckBox multiple = new CheckBox(context); multiple.setText("ALLOW_MULTIPLE"); view.addView(multiple); @@ -156,6 +160,23 @@ public class TestActivity extends Activity { view.addView(button); button = new Button(context); + button.setText("CREATE_DOC image/png"); + button.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + Intent intent = new Intent(Intent.ACTION_CREATE_DOCUMENT); + intent.addCategory(Intent.CATEGORY_OPENABLE); + intent.setType("image/png"); + intent.putExtra(Intent.EXTRA_TITLE, "mypicture.png"); + if (localOnly.isChecked()) { + intent.putExtra(Intent.EXTRA_LOCAL_ONLY, true); + } + startActivityForResult(intent, CODE_WRITE); + } + }); + view.addView(button); + + button = new Button(context); button.setText("GET_CONTENT */*"); button.setOnClickListener(new OnClickListener() { @Override @@ -174,10 +195,10 @@ public class TestActivity extends Activity { }); view.addView(button); - mResult = new TextView(context); - view.addView(mResult); + final ScrollView scroll = new ScrollView(context); + scroll.addView(view); - setContentView(view); + setContentView(scroll); } @Override diff --git a/packages/DocumentsUI/src/com/android/documentsui/model/DocumentInfo.java b/packages/DocumentsUI/src/com/android/documentsui/model/DocumentInfo.java index 08a8c13..5091a61 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/model/DocumentInfo.java +++ b/packages/DocumentsUI/src/com/android/documentsui/model/DocumentInfo.java @@ -23,6 +23,7 @@ import android.net.Uri; import android.os.Parcel; import android.os.Parcelable; import android.provider.DocumentsContract; +import android.provider.DocumentsProvider; import android.provider.DocumentsContract.Document; import com.android.documentsui.RootCursorWrapper; @@ -141,23 +142,42 @@ public class DocumentInfo implements Durable, Parcelable { } public static DocumentInfo fromCursor(Cursor cursor, String authority) { - final DocumentInfo doc = new DocumentInfo(); - doc.authority = authority; - doc.documentId = getCursorString(cursor, Document.COLUMN_DOCUMENT_ID); - doc.mimeType = getCursorString(cursor, Document.COLUMN_MIME_TYPE); - doc.documentId = getCursorString(cursor, Document.COLUMN_DOCUMENT_ID); - doc.mimeType = getCursorString(cursor, Document.COLUMN_MIME_TYPE); - doc.displayName = getCursorString(cursor, Document.COLUMN_DISPLAY_NAME); - doc.lastModified = getCursorLong(cursor, Document.COLUMN_LAST_MODIFIED); - doc.flags = getCursorInt(cursor, Document.COLUMN_FLAGS); - doc.summary = getCursorString(cursor, Document.COLUMN_SUMMARY); - doc.size = getCursorLong(cursor, Document.COLUMN_SIZE); - doc.icon = getCursorInt(cursor, Document.COLUMN_ICON); - doc.deriveFields(); - return doc; - } - - public static DocumentInfo fromUri(ContentResolver resolver, Uri uri) throws FileNotFoundException { + final DocumentInfo info = new DocumentInfo(); + info.updateFromCursor(cursor, authority); + return info; + } + + public void updateFromCursor(Cursor cursor, String authority) { + this.authority = authority; + this.documentId = getCursorString(cursor, Document.COLUMN_DOCUMENT_ID); + this.mimeType = getCursorString(cursor, Document.COLUMN_MIME_TYPE); + this.documentId = getCursorString(cursor, Document.COLUMN_DOCUMENT_ID); + this.mimeType = getCursorString(cursor, Document.COLUMN_MIME_TYPE); + this.displayName = getCursorString(cursor, Document.COLUMN_DISPLAY_NAME); + this.lastModified = getCursorLong(cursor, Document.COLUMN_LAST_MODIFIED); + this.flags = getCursorInt(cursor, Document.COLUMN_FLAGS); + this.summary = getCursorString(cursor, Document.COLUMN_SUMMARY); + this.size = getCursorLong(cursor, Document.COLUMN_SIZE); + this.icon = getCursorInt(cursor, Document.COLUMN_ICON); + this.deriveFields(); + } + + public static DocumentInfo fromUri(ContentResolver resolver, Uri uri) + throws FileNotFoundException { + final DocumentInfo info = new DocumentInfo(); + info.updateFromUri(resolver, uri); + return info; + } + + /** + * Update a possibly stale restored document against a live + * {@link DocumentsProvider}. + */ + public void updateSelf(ContentResolver resolver) throws FileNotFoundException { + updateFromUri(resolver, derivedUri); + } + + public void updateFromUri(ContentResolver resolver, Uri uri) throws FileNotFoundException { final ContentProviderClient client = resolver.acquireUnstableContentProviderClient( uri.getAuthority()); Cursor cursor = null; @@ -166,7 +186,7 @@ public class DocumentInfo implements Durable, Parcelable { if (!cursor.moveToFirst()) { throw new FileNotFoundException("Missing details for " + uri); } - return fromCursor(cursor, uri.getAuthority()); + updateFromCursor(cursor, uri.getAuthority()); } catch (Throwable t) { throw asFileNotFoundException(t); } finally { diff --git a/packages/DocumentsUI/src/com/android/documentsui/model/DocumentStack.java b/packages/DocumentsUI/src/com/android/documentsui/model/DocumentStack.java index 2541440..0a378c0 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/model/DocumentStack.java +++ b/packages/DocumentsUI/src/com/android/documentsui/model/DocumentStack.java @@ -16,10 +16,15 @@ package com.android.documentsui.model; +import android.content.ContentResolver; +import android.provider.DocumentsProvider; + import java.io.DataInputStream; import java.io.DataOutputStream; +import java.io.FileNotFoundException; import java.io.IOException; import java.net.ProtocolException; +import java.util.Collection; import java.util.LinkedList; /** @@ -46,6 +51,26 @@ public class DocumentStack extends LinkedList<DocumentInfo> implements Durable { return size() == 0; } + public void updateRoot(Collection<RootInfo> matchingRoots) throws FileNotFoundException { + for (RootInfo root : matchingRoots) { + if (root.equals(this.root)) { + this.root = root; + return; + } + } + throw new FileNotFoundException("Failed to find matching root for " + root); + } + + /** + * Update a possibly stale restored stack against a live + * {@link DocumentsProvider}. + */ + public void updateDocuments(ContentResolver resolver) throws FileNotFoundException { + for (DocumentInfo info : this) { + info.updateSelf(resolver); + } + } + @Override public void reset() { clear(); |