import java.io.FileDescriptor;
import java.io.IOException;
-import java.io.InputStream;
import java.util.List;
/**
<uses-permission android:name="android.permission.MANAGE_DOCUMENTS" />
<application
+ android:name=".DocumentsApplication"
android:label="@string/app_label"
android:supportsRtl="true">
android:authorities="com.android.documentsui.recents"
android:exported="false" />
+ <receiver android:name=".DocumentChangedReceiver">
+ <intent-filter>
+ <action android:name="android.provider.action.DOCUMENT_CHANGED" />
+ <data android:mimeType="vnd.android.cursor.dir/root" />
+ <data android:mimeType="vnd.android.cursor.item/root" />
+ </intent-filter>
+ </receiver>
+
<!-- TODO: remove when we have real clients -->
<activity android:name=".TestActivity" android:enabled="false">
<intent-filter>
android:id="@+id/menu_open"
android:title="@string/menu_open"
android:showAsAction="always" />
+ <item
+ android:id="@+id/menu_share"
+ android:icon="@android:drawable/ic_menu_share"
+ android:title="@string/menu_share"
+ android:showAsAction="always" />
+ <item
+ android:id="@+id/menu_delete"
+ android:icon="@android:drawable/ic_menu_delete"
+ android:title="@string/menu_delete"
+ android:showAsAction="always" />
</menu>
<string name="menu_open">Open</string>
<string name="menu_save">Save</string>
+ <string name="menu_share">Share</string>
+ <string name="menu_delete">Delete</string>
<string name="mode_selected_count"><xliff:g id="count" example="3">%1$d</xliff:g> selected</string>
<string name="empty">No items</string>
+ <string name="toast_no_application">Can\'t open file</string>
+ <string name="toast_failed_delete">Unable to delete some documents</string>
+
</resources>
package com.android.documentsui;
import static com.android.documentsui.DocumentsActivity.TAG;
+import static com.android.documentsui.DocumentsActivity.DisplayState.ACTION_MANAGE;
+import static com.android.documentsui.DocumentsActivity.DisplayState.MODE_GRID;
+import static com.android.documentsui.DocumentsActivity.DisplayState.MODE_LIST;
+import static com.android.documentsui.DocumentsActivity.DisplayState.SORT_ORDER_DATE;
+import static com.android.documentsui.DocumentsActivity.DisplayState.SORT_ORDER_NAME;
+import static com.android.documentsui.DocumentsActivity.DisplayState.SORT_ORDER_SIZE;
import android.app.Fragment;
import android.app.FragmentManager;
import android.app.FragmentTransaction;
import android.app.LoaderManager.LoaderCallbacks;
+import android.content.ContentResolver;
import android.content.Context;
+import android.content.Intent;
import android.content.Loader;
import android.graphics.Bitmap;
import android.graphics.Point;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
+import android.widget.Toast;
import com.android.documentsui.DocumentsActivity.DisplayState;
import com.android.documentsui.model.Document;
import com.android.internal.util.Predicate;
import com.google.android.collect.Lists;
-import java.text.DateFormat;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
}
final Comparator<Document> sortOrder;
- if (state.sortOrder == DisplayState.SORT_ORDER_DATE || mType == TYPE_RECENT_OPEN) {
+ if (state.sortOrder == SORT_ORDER_DATE || mType == TYPE_RECENT_OPEN) {
sortOrder = new Document.DateComparator();
- } else if (state.sortOrder == DisplayState.SORT_ORDER_NAME) {
+ } else if (state.sortOrder == SORT_ORDER_NAME) {
sortOrder = new Document.NameComparator();
- } else if (state.sortOrder == DisplayState.SORT_ORDER_SIZE) {
+ } else if (state.sortOrder == SORT_ORDER_SIZE) {
sortOrder = new Document.SizeComparator();
} else {
throw new IllegalArgumentException("Unknown sort order " + state.sortOrder);
mListView.smoothScrollToPosition(0);
mGridView.smoothScrollToPosition(0);
- mListView.setVisibility(state.mode == DisplayState.MODE_LIST ? View.VISIBLE : View.GONE);
- mGridView.setVisibility(state.mode == DisplayState.MODE_GRID ? View.VISIBLE : View.GONE);
+ mListView.setVisibility(state.mode == MODE_LIST ? View.VISIBLE : View.GONE);
+ mGridView.setVisibility(state.mode == MODE_GRID ? View.VISIBLE : View.GONE);
final int choiceMode;
if (state.allowMultiple) {
}
final int thumbSize;
- if (state.mode == DisplayState.MODE_GRID) {
+ if (state.mode == MODE_GRID) {
thumbSize = getResources().getDimensionPixelSize(R.dimen.grid_width);
mListView.setAdapter(null);
mListView.setChoiceMode(ListView.CHOICE_MODE_NONE);
mGridView.setNumColumns(GridView.AUTO_FIT);
mGridView.setChoiceMode(choiceMode);
mCurrentView = mGridView;
- } else if (state.mode == DisplayState.MODE_LIST) {
+ } else if (state.mode == MODE_LIST) {
thumbSize = getResources().getDimensionPixelSize(android.R.dimen.app_icon_size);
mGridView.setAdapter(null);
mGridView.setChoiceMode(ListView.CHOICE_MODE_NONE);
@Override
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
+ final DisplayState state = getDisplayState(DirectoryFragment.this);
+
+ final MenuItem open = menu.findItem(R.id.menu_open);
+ final MenuItem share = menu.findItem(R.id.menu_share);
+ final MenuItem delete = menu.findItem(R.id.menu_delete);
+
+ final boolean manageMode = state.action == ACTION_MANAGE;
+ open.setVisible(!manageMode);
+ share.setVisible(manageMode);
+ delete.setVisible(manageMode);
+
return true;
}
@Override
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
- if (item.getItemId() == R.id.menu_open) {
- final Uri uri = getArguments().getParcelable(EXTRA_URI);
- final SparseBooleanArray checked = mCurrentView.getCheckedItemPositions();
- final ArrayList<Document> docs = Lists.newArrayList();
-
- final int size = checked.size();
- for (int i = 0; i < size; i++) {
- if (checked.valueAt(i)) {
- final Document doc = mAdapter.getItem(checked.keyAt(i));
- docs.add(doc);
- }
+ final SparseBooleanArray checked = mCurrentView.getCheckedItemPositions();
+ final ArrayList<Document> docs = Lists.newArrayList();
+ final int size = checked.size();
+ for (int i = 0; i < size; i++) {
+ if (checked.valueAt(i)) {
+ final Document doc = mAdapter.getItem(checked.keyAt(i));
+ docs.add(doc);
}
+ }
+
+ final int id = item.getItemId();
+ if (id == R.id.menu_open) {
+ DocumentsActivity.get(DirectoryFragment.this).onDocumentsPicked(docs);
+ return true;
- ((DocumentsActivity) getActivity()).onDocumentsPicked(docs);
+ } else if (id == R.id.menu_share) {
+ onShareDocuments(docs);
return true;
+
+ } else if (id == R.id.menu_delete) {
+ onDeleteDocuments(docs);
+ return true;
+
} else {
return false;
}
}
};
+ private void onShareDocuments(List<Document> docs) {
+ final ArrayList<Uri> uris = Lists.newArrayList();
+ for (Document doc : docs) {
+ uris.add(doc.uri);
+ }
+
+ final Intent intent;
+ if (uris.size() > 1) {
+ intent = new Intent(Intent.ACTION_SEND_MULTIPLE);
+ intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
+ intent.addCategory(Intent.CATEGORY_DEFAULT);
+ // TODO: find common mimetype
+ intent.setType("*/*");
+ intent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, uris);
+ } else {
+ intent = new Intent(Intent.ACTION_SEND);
+ intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
+ intent.addCategory(Intent.CATEGORY_DEFAULT);
+ intent.setData(uris.get(0));
+ }
+
+ startActivity(intent);
+ }
+
+ private void onDeleteDocuments(List<Document> docs) {
+ final Context context = getActivity();
+ final ContentResolver resolver = context.getContentResolver();
+
+ boolean hadTrouble = false;
+ for (Document doc : docs) {
+ if (!doc.isDeleteSupported()) {
+ Log.w(TAG, "Skipping " + doc);
+ hadTrouble = true;
+ continue;
+ }
+
+ try {
+ if (resolver.delete(doc.uri, null, null) != 1) {
+ Log.w(TAG, "Failed to delete " + doc);
+ hadTrouble = true;
+ }
+ } catch (Exception e) {
+ Log.w(TAG, "Failed to delete " + doc + ": " + e);
+ hadTrouble = true;
+ }
+ }
+
+ if (hadTrouble) {
+ Toast.makeText(context, R.string.toast_failed_delete, Toast.LENGTH_SHORT).show();
+ }
+ }
+
private static DisplayState getDisplayState(Fragment fragment) {
return ((DocumentsActivity) fragment.getActivity()).getDisplayState();
}
final Context context = parent.getContext();
final DisplayState state = getDisplayState(DirectoryFragment.this);
+ final RootsCache roots = DocumentsApplication.getRootsCache(context);
+ final ThumbnailCache thumbs = DocumentsApplication.getThumbnailsCache(
+ context, mThumbSize);
+
if (convertView == null) {
final LayoutInflater inflater = LayoutInflater.from(context);
- if (state.mode == DisplayState.MODE_LIST) {
+ if (state.mode == MODE_LIST) {
convertView = inflater.inflate(R.layout.item_doc_list, parent, false);
- } else if (state.mode == DisplayState.MODE_GRID) {
+ } else if (state.mode == MODE_GRID) {
convertView = inflater.inflate(R.layout.item_doc_grid, parent, false);
} else {
throw new IllegalStateException();
}
if (doc.isThumbnailSupported()) {
- final Bitmap cachedResult = ThumbnailCache.get(context).get(doc.uri);
+ final Bitmap cachedResult = thumbs.get(doc.uri);
if (cachedResult != null) {
icon.setImageBitmap(cachedResult);
} else {
task.execute(doc.uri);
}
} else {
- icon.setImageDrawable(RootsCache.resolveDocumentIcon(
+ icon.setImageDrawable(roots.resolveDocumentIcon(
context, doc.uri.getAuthority(), doc.mimeType));
}
summary.setVisibility(View.INVISIBLE);
}
} else if (mType == TYPE_RECENT_OPEN) {
- final Root root = RootsCache.findRoot(context, doc);
+ final Root root = roots.findRoot(doc);
icon1.setVisibility(View.VISIBLE);
icon1.setImageDrawable(root.icon);
summary.setText(root.getDirectoryString());
private static class ThumbnailAsyncTask extends AsyncTask<Uri, Void, Bitmap> {
private final ImageView mTarget;
- private final Point mSize;
+ private final Point mThumbSize;
- public ThumbnailAsyncTask(ImageView target, Point size) {
+ public ThumbnailAsyncTask(ImageView target, Point thumbSize) {
mTarget = target;
- mSize = size;
+ mThumbSize = thumbSize;
}
@Override
Bitmap result = null;
try {
result = DocumentsContract.getThumbnail(
- context.getContentResolver(), uri, mSize);
+ context.getContentResolver(), uri, mThumbSize);
if (result != null) {
- ThumbnailCache.get(context).put(uri, result);
+ final ThumbnailCache thumbs = DocumentsApplication.getThumbnailsCache(
+ context, mThumbSize);
+ thumbs.put(uri, result);
}
} catch (Exception e) {
Log.w(TAG, "Failed to load thumbnail: " + e);
private List<Document> loadInBackgroundInternal(Uri uri, CancellationSignal signal) {
final ArrayList<Document> result = Lists.newArrayList();
+ // TODO: subscribe to the notify uri from query
+
final ContentResolver resolver = getContext().getContentResolver();
final Cursor cursor = resolver.query(uri, null, null, null, getQuerySortOrder(), signal);
try {
--- /dev/null
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.documentsui;
+
+import static com.android.documentsui.DocumentsActivity.TAG;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.util.Log;
+
+import com.android.documentsui.model.Root;
+
+/**
+ * Handles {@link Root} changes which invalidate cached data.
+ */
+public class DocumentChangedReceiver extends BroadcastReceiver {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ Log.d(TAG, "Regenerating roots cache");
+ DocumentsApplication.getRootsCache(context).update();
+ // TODO: invalidate cached data in recents provider
+ }
+}
package com.android.documentsui;
+import static com.android.documentsui.DocumentsActivity.DisplayState.ACTION_CREATE;
+import static com.android.documentsui.DocumentsActivity.DisplayState.ACTION_GET_CONTENT;
+import static com.android.documentsui.DocumentsActivity.DisplayState.ACTION_MANAGE;
+import static com.android.documentsui.DocumentsActivity.DisplayState.ACTION_OPEN;
+import static com.android.documentsui.DocumentsActivity.DisplayState.MODE_GRID;
+import static com.android.documentsui.DocumentsActivity.DisplayState.MODE_LIST;
+import static com.android.documentsui.DocumentsActivity.DisplayState.SORT_ORDER_DATE;
+
import android.app.ActionBar;
import android.app.ActionBar.OnNavigationListener;
import android.app.Activity;
import android.app.Fragment;
import android.app.FragmentManager;
+import android.content.ActivityNotFoundException;
import android.content.ClipData;
import android.content.ComponentName;
import android.content.ContentResolver;
public class DocumentsActivity extends Activity {
public static final String TAG = "Documents";
- public static final int ACTION_OPEN = 1;
- public static final int ACTION_CREATE = 2;
- public static final int ACTION_GET_CONTENT = 3;
- public static final int ACTION_MANAGE = 4;
-
private int mAction;
private SearchView mSearchView;
private final DisplayState mDisplayState = new DisplayState();
+ private RootsCache mRoots;
+
/** Current user navigation stack; empty implies recents. */
private DocumentStack mStack = new DocumentStack();
/** Currently active search, overriding any stack. */
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
+ mRoots = DocumentsApplication.getRootsCache(this);
+
final Intent intent = getIntent();
final String action = intent.getAction();
if (Intent.ACTION_OPEN_DOCUMENT.equals(action)) {
mAction = ACTION_MANAGE;
}
+ // TODO: unify action in single place
+ mDisplayState.action = mAction;
+
if (mAction == ACTION_OPEN || mAction == ACTION_GET_CONTENT) {
mDisplayState.allowMultiple = intent.getBooleanExtra(
Intent.EXTRA_ALLOW_MULTIPLE, false);
if (mAction == ACTION_MANAGE) {
mDisplayState.acceptMimes = new String[] { "*/*" };
+ mDisplayState.allowMultiple = true;
} else if (intent.hasExtra(Intent.EXTRA_MIME_TYPES)) {
mDisplayState.acceptMimes = intent.getStringArrayExtra(Intent.EXTRA_MIME_TYPES);
} else {
}
if (mAction == ACTION_MANAGE) {
- mDisplayState.sortOrder = DisplayState.SORT_ORDER_DATE;
+ mDisplayState.sortOrder = SORT_ORDER_DATE;
}
mRootsContainer = findViewById(R.id.container_roots);
final String authority = rootUri.getAuthority();
final String rootId = DocumentsContract.getRootId(rootUri);
- final Root root = RootsCache.findRoot(this, authority, rootId);
+ final Root root = mRoots.findRoot(authority, rootId);
if (root != null) {
onRootPicked(root, true);
} else {
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);
- list.setVisible(mDisplayState.mode != DisplayState.MODE_LIST);
+ grid.setVisible(mDisplayState.mode != MODE_GRID);
+ list.setVisible(mDisplayState.mode != MODE_LIST);
final boolean searchVisible;
if (mAction == ACTION_CREATE) {
} else if (id == R.id.menu_search) {
return false;
} else if (id == R.id.menu_grid) {
- mDisplayState.mode = DisplayState.MODE_GRID;
+ // TODO: persist explicit user mode for cwd
+ mDisplayState.mode = MODE_GRID;
updateDisplayState();
invalidateOptionsMenu();
return true;
} else if (id == R.id.menu_list) {
- mDisplayState.mode = DisplayState.MODE_LIST;
+ // TODO: persist explicit user mode for cwd
+ mDisplayState.mode = MODE_LIST;
updateDisplayState();
invalidateOptionsMenu();
return true;
public Root getCurrentRoot() {
final Document cwd = getCurrentDirectory();
if (cwd != null) {
- return RootsCache.findRoot(this, cwd);
+ return mRoots.findRoot(cwd);
} else {
- return RootsCache.getRecentsRoot(this);
+ return mRoots.getRecentsRoot();
}
}
public void onDocumentPicked(Document doc) {
final FragmentManager fm = getFragmentManager();
if (doc.isDirectory()) {
+ // TODO: query display mode user preference for this dir
+ if (doc.isGridPreferred()) {
+ mDisplayState.mode = MODE_GRID;
+ } else {
+ mDisplayState.mode = MODE_LIST;
+ }
mStack.push(doc);
onCurrentDirectoryChanged();
} else if (mAction == ACTION_OPEN || mAction == ACTION_GET_CONTENT) {
} else if (mAction == ACTION_CREATE) {
// Replace selected file
SaveFragment.get(fm).setReplaceTarget(doc);
+ } else if (mAction == ACTION_MANAGE) {
+ // Open the document
+ // TODO: trampoline activity for launching downloaded APKs
+ final Intent intent = new Intent(Intent.ACTION_VIEW);
+ intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
+ intent.setData(doc.uri);
+ try {
+ startActivity(intent);
+ } catch (ActivityNotFoundException ex) {
+ Toast.makeText(this, R.string.toast_no_application, Toast.LENGTH_SHORT).show();
+ }
}
}
public void onDocumentsPicked(List<Document> docs) {
- final int size = docs.size();
- final Uri[] uris = new Uri[size];
- for (int i = 0; i < size; i++) {
- uris[i] = docs.get(i).uri;
+ if (mAction == ACTION_OPEN || mAction == ACTION_GET_CONTENT) {
+ final int size = docs.size();
+ final Uri[] uris = new Uri[size];
+ for (int i = 0; i < size; i++) {
+ uris[i] = docs.get(i).uri;
+ }
+ onFinished(uris);
}
- onFinished(uris);
}
public void onSaveRequested(Document replaceTarget) {
}
public static class DisplayState {
+ public int action;
public int mode = MODE_LIST;
public String[] acceptMimes;
public int sortOrder = SORT_ORDER_NAME;
public boolean showSize = false;
public boolean localOnly = false;
+ public static final int ACTION_OPEN = 1;
+ public static final int ACTION_CREATE = 2;
+ public static final int ACTION_GET_CONTENT = 3;
+ public static final int ACTION_MANAGE = 4;
+
public static final int MODE_LIST = 0;
public static final int MODE_GRID = 1;
--- /dev/null
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.documentsui;
+
+import android.app.ActivityManager;
+import android.app.Application;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.graphics.Point;
+
+public class DocumentsApplication extends Application {
+ private RootsCache mRoots;
+ private Point mThumbnailsSize;
+ private ThumbnailCache mThumbnails;
+
+ public static RootsCache getRootsCache(Context context) {
+ return ((DocumentsApplication) context.getApplicationContext()).mRoots;
+ }
+
+ public static ThumbnailCache getThumbnailsCache(Context context, Point size) {
+ final DocumentsApplication app = (DocumentsApplication) context.getApplicationContext();
+ final ThumbnailCache thumbnails = app.mThumbnails;
+ if (!size.equals(app.mThumbnailsSize)) {
+ thumbnails.evictAll();
+ app.mThumbnailsSize = size;
+ }
+ return thumbnails;
+ }
+
+ @Override
+ public void onCreate() {
+ final ActivityManager am = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
+ final int memoryClassBytes = am.getMemoryClass() * 1024 * 1024;
+
+ mRoots = new RootsCache(this);
+ mThumbnails = new ThumbnailCache(memoryClassBytes / 4);
+
+ final IntentFilter packageFilter = new IntentFilter();
+ packageFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
+ packageFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
+ packageFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
+ packageFilter.addDataScheme("package");
+ registerReceiver(mPackageReceiver, packageFilter);
+ }
+
+ @Override
+ public void onTrimMemory(int level) {
+ super.onTrimMemory(level);
+
+ if (level >= TRIM_MEMORY_MODERATE) {
+ mThumbnails.evictAll();
+ } else if (level >= TRIM_MEMORY_BACKGROUND) {
+ mThumbnails.trimToSize(mThumbnails.size() / 2);
+ }
+ }
+
+ private BroadcastReceiver mPackageReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ // TODO: narrow changed/removed to only packages that have backends
+ mRoots.update();
+ }
+ };
+}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
final Context context = parent.getContext();
+ final RootsCache roots = DocumentsApplication.getRootsCache(context);
if (convertView == null) {
final LayoutInflater inflater = LayoutInflater.from(context);
final View summaryList = convertView.findViewById(R.id.summary_list);
final DocumentStack stack = getItem(position);
- final Root root = RootsCache.findRoot(context, stack.peek());
+ final Root root = roots.findRoot(stack.peek());
icon.setImageDrawable(root != null ? root.icon : null);
final StringBuilder builder = new StringBuilder();
public class RootsCache {
// TODO: cache roots in local provider to avoid spinning up backends
+ // TODO: root updates should trigger UI refresh
- private static boolean sCached = false;
+ private final Context mContext;
/** Map from authority to cached info */
- private static HashMap<String, DocumentsProviderInfo> sProviders = Maps.newHashMap();
+ private HashMap<String, DocumentsProviderInfo> mProviders = Maps.newHashMap();
/** Map from (authority+rootId) to cached info */
- private static HashMap<Pair<String, String>, Root> sRoots = Maps.newHashMap();
+ private HashMap<Pair<String, String>, Root> mRoots = Maps.newHashMap();
- public static ArrayList<Root> sRootsList = Lists.newArrayList();
+ public ArrayList<Root> mRootsList = Lists.newArrayList();
- private static Root sRecentsRoot;
+ private Root mRecentsRoot;
+
+ public RootsCache(Context context) {
+ mContext = context;
+ update();
+ }
/**
* Gather roots from all known storage providers.
*/
- private static void ensureCache(Context context) {
- if (sCached) return;
- sCached = true;
-
- sProviders.clear();
- sRoots.clear();
- sRootsList.clear();
+ @GuardedBy("ActivityThread")
+ public void update() {
+ mProviders.clear();
+ mRoots.clear();
+ mRootsList.clear();
{
// Create special root for recents
- final Root root = Root.buildRecents(context);
- sRootsList.add(root);
- sRecentsRoot = root;
+ final Root root = Root.buildRecents(mContext);
+ mRootsList.add(root);
+ mRecentsRoot = root;
}
// Query for other storage backends
- final PackageManager pm = context.getPackageManager();
+ final PackageManager pm = mContext.getPackageManager();
final List<ProviderInfo> providers = pm.queryContentProviders(
null, -1, PackageManager.GET_META_DATA);
for (ProviderInfo providerInfo : providers) {
if (providerInfo.metaData != null && providerInfo.metaData.containsKey(
DocumentsContract.META_DATA_DOCUMENT_PROVIDER)) {
final DocumentsProviderInfo info = DocumentsProviderInfo.parseInfo(
- context, providerInfo);
+ mContext, providerInfo);
if (info == null) {
Log.w(TAG, "Missing info for " + providerInfo);
continue;
}
- sProviders.put(info.providerInfo.authority, info);
+ mProviders.put(info.providerInfo.authority, info);
try {
// TODO: remove deprecated customRoots flag
// TODO: populate roots on background thread, and cache results
final Uri uri = DocumentsContract.buildRootsUri(providerInfo.authority);
- final Cursor cursor = context.getContentResolver()
+ final Cursor cursor = mContext.getContentResolver()
.query(uri, null, null, null, null);
try {
while (cursor.moveToNext()) {
- final Root root = Root.fromCursor(context, info, cursor);
- sRoots.put(Pair.create(info.providerInfo.authority, root.rootId), root);
- sRootsList.add(root);
+ final Root root = Root.fromCursor(mContext, info, cursor);
+ mRoots.put(Pair.create(info.providerInfo.authority, root.rootId), root);
+ mRootsList.add(root);
}
} finally {
cursor.close();
}
@GuardedBy("ActivityThread")
- public static DocumentsProviderInfo findProvider(Context context, String authority) {
- ensureCache(context);
- return sProviders.get(authority);
+ public DocumentsProviderInfo findProvider(String authority) {
+ return mProviders.get(authority);
}
@GuardedBy("ActivityThread")
- public static Root findRoot(Context context, String authority, String rootId) {
- ensureCache(context);
- return sRoots.get(Pair.create(authority, rootId));
+ public Root findRoot(String authority, String rootId) {
+ return mRoots.get(Pair.create(authority, rootId));
}
@GuardedBy("ActivityThread")
- public static Root findRoot(Context context, Document doc) {
+ public Root findRoot(Document doc) {
final String authority = doc.uri.getAuthority();
final String rootId = DocumentsContract.getRootId(doc.uri);
- return findRoot(context, authority, rootId);
+ return findRoot(authority, rootId);
}
@GuardedBy("ActivityThread")
- public static Root getRecentsRoot(Context context) {
- ensureCache(context);
- return sRecentsRoot;
+ public Root getRecentsRoot() {
+ return mRecentsRoot;
}
@GuardedBy("ActivityThread")
- public static Collection<Root> getRoots(Context context) {
- ensureCache(context);
- return sRootsList;
+ public Collection<Root> getRoots() {
+ return mRootsList;
}
@GuardedBy("ActivityThread")
- public static Drawable resolveDocumentIcon(Context context, String authority, String mimeType) {
+ public Drawable resolveDocumentIcon(Context context, String authority, String mimeType) {
// Custom icons take precedence
- ensureCache(context);
- final DocumentsProviderInfo info = sProviders.get(authority);
+ final DocumentsProviderInfo info = mProviders.get(authority);
if (info != null) {
for (Icon icon : info.customIcons) {
if (MimePredicate.mimeMatches(icon.mimeType, mimeType)) {
public View onCreateView(
LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
final Context context = inflater.getContext();
+ final RootsCache roots = DocumentsApplication.getRootsCache(context);
final View view = inflater.inflate(R.layout.fragment_roots, container, false);
mList = (ListView) view.findViewById(android.R.id.list);
mList.setOnItemClickListener(mItemListener);
final Intent includeApps = getArguments().getParcelable(EXTRA_INCLUDE_APPS);
- mAdapter = new SectionedRootsAdapter(context, RootsCache.getRoots(context), includeApps);
+ mAdapter = new SectionedRootsAdapter(context, roots.getRoots(), includeApps);
return view;
}
public View onCreateView(
LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
final Context context = inflater.getContext();
+ final RootsCache roots = DocumentsApplication.getRootsCache(context);
final View view = inflater.inflate(R.layout.fragment_save, container, false);
final ImageView icon = (ImageView) view.findViewById(android.R.id.icon);
- icon.setImageDrawable(RootsCache.resolveDocumentIcon(
+ icon.setImageDrawable(roots.resolveDocumentIcon(
context, null, getArguments().getString(EXTRA_MIME_TYPE)));
mDisplayName = (EditText) view.findViewById(android.R.id.title);
package com.android.documentsui;
-import android.app.ActivityManager;
-import android.content.Context;
import android.graphics.Bitmap;
import android.net.Uri;
import android.util.LruCache;
public class ThumbnailCache extends LruCache<Uri, Bitmap> {
- private static ThumbnailCache sCache;
-
- public static ThumbnailCache get(Context context) {
- if (sCache == null) {
- final ActivityManager am = (ActivityManager) context.getSystemService(
- Context.ACTIVITY_SERVICE);
- final int memoryClassBytes = am.getMemoryClass() * 1024 * 1024;
- sCache = new ThumbnailCache(memoryClassBytes / 4);
- }
- return sCache;
- }
-
public ThumbnailCache(int maxSizeBytes) {
super(maxSizeBytes);
}
return Documents.MIME_TYPE_DIR.equals(mimeType);
}
+ public boolean isGridPreferred() {
+ return (flags & Documents.FLAG_PREFERS_GRID) != 0;
+ }
+
+ public boolean isDeleteSupported() {
+ return (flags & Documents.FLAG_SUPPORTS_DELETE) != 0;
+ }
+
private static String getCursorString(Cursor cursor, String columnName) {
final int index = cursor.getColumnIndex(columnName);
return (index != -1) ? cursor.getString(index) : null;