diff options
11 files changed, 104 insertions, 54 deletions
diff --git a/core/java/android/content/ContentProviderClient.java b/core/java/android/content/ContentProviderClient.java index 39b453d..0650798 100644 --- a/core/java/android/content/ContentProviderClient.java +++ b/core/java/android/content/ContentProviderClient.java @@ -26,6 +26,8 @@ import android.os.RemoteException; import android.os.ParcelFileDescriptor; import android.content.res.AssetFileDescriptor; +import dalvik.system.CloseGuard; + import java.io.FileNotFoundException; import java.util.ArrayList; @@ -49,6 +51,8 @@ public class ContentProviderClient { private final boolean mStable; private boolean mReleased; + private final CloseGuard mGuard = CloseGuard.get(); + /** * @hide */ @@ -58,6 +62,7 @@ public class ContentProviderClient { mContentResolver = contentResolver; mPackageName = contentResolver.mPackageName; mStable = stable; + mGuard.open("release"); } /** See {@link ContentProvider#query ContentProvider.query} */ @@ -324,6 +329,7 @@ public class ContentProviderClient { throw new IllegalStateException("Already released"); } mReleased = true; + mGuard.close(); if (mStable) { return mContentResolver.releaseProvider(mContentProvider); } else { @@ -332,6 +338,13 @@ public class ContentProviderClient { } } + @Override + protected void finalize() throws Throwable { + if (mGuard != null) { + mGuard.warnIfOpen(); + } + } + /** * Get a reference to the {@link ContentProvider} that is associated with this * client. If the {@link ContentProvider} is running in a different process then diff --git a/packages/DocumentsUI/AndroidManifest.xml b/packages/DocumentsUI/AndroidManifest.xml index 19a29f2..71a0567 100644 --- a/packages/DocumentsUI/AndroidManifest.xml +++ b/packages/DocumentsUI/AndroidManifest.xml @@ -11,7 +11,8 @@ <!-- TODO: allow rotation when state saving is in better shape --> <activity android:name=".DocumentsActivity" - android:theme="@style/Theme"> + android:theme="@style/Theme" + android:icon="@drawable/ic_doc_text"> <intent-filter android:priority="100"> <action android:name="android.intent.action.OPEN_DOCUMENT" /> <category android:name="android.intent.category.DEFAULT" /> diff --git a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java index 457bb19..6d2f9b9 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java +++ b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java @@ -87,8 +87,8 @@ import libcore.io.IoUtils; import java.io.FileNotFoundException; import java.io.IOException; import java.util.Arrays; -import java.util.HashMap; import java.util.Collection; +import java.util.HashMap; import java.util.List; public class DocumentsActivity extends Activity { @@ -96,6 +96,8 @@ public class DocumentsActivity extends Activity { private static final String EXTRA_STATE = "state"; + private static final int CODE_FORWARD = 42; + private boolean mShowAsDialog; private SearchView mSearchView; @@ -843,11 +845,24 @@ public class DocumentsActivity extends Activity { public void onAppPicked(ResolveInfo info) { final Intent intent = new Intent(getIntent()); - intent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT); + intent.setFlags(intent.getFlags() & ~Intent.FLAG_ACTIVITY_FORWARD_RESULT); intent.setComponent(new ComponentName( info.activityInfo.applicationInfo.packageName, info.activityInfo.name)); - startActivity(intent); - finish(); + startActivityForResult(intent, CODE_FORWARD); + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + Log.d(TAG, "onActivityResult() code=" + resultCode); + + // 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) { + setResult(resultCode, data); + finish(); + } else { + super.onActivityResult(requestCode, resultCode, data); + } } public void onDocumentPicked(DocumentInfo doc) { diff --git a/packages/DocumentsUI/src/com/android/documentsui/RecentLoader.java b/packages/DocumentsUI/src/com/android/documentsui/RecentLoader.java index 3659c6e..e390456 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/RecentLoader.java +++ b/packages/DocumentsUI/src/com/android/documentsui/RecentLoader.java @@ -52,6 +52,7 @@ import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; public class RecentLoader extends AsyncTaskLoader<DirectoryResult> { + private static final boolean LOGD = true; public static final int MAX_OUTSTANDING_RECENTS = 2; @@ -63,7 +64,7 @@ public class RecentLoader extends AsyncTaskLoader<DirectoryResult> { /** * Maximum documents from a single root. */ - public static final int MAX_DOCS_FROM_ROOT = 24; + public static final int MAX_DOCS_FROM_ROOT = 64; private static final ExecutorService sExecutor = buildExecutor(); @@ -194,6 +195,11 @@ public class RecentLoader extends AsyncTaskLoader<DirectoryResult> { } } + if (LOGD) { + Log.d(TAG, "Found " + cursors.size() + " of " + mTasks.size() + " recent queries done"); + Log.d(TAG, sExecutor.toString()); + } + final DirectoryResult result = new DirectoryResult(); result.sortOrder = SORT_ORDER_LAST_MODIFIED; diff --git a/packages/DocumentsUI/src/com/android/documentsui/RecentsCreateFragment.java b/packages/DocumentsUI/src/com/android/documentsui/RecentsCreateFragment.java index 5076370..a396f79 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/RecentsCreateFragment.java +++ b/packages/DocumentsUI/src/com/android/documentsui/RecentsCreateFragment.java @@ -195,12 +195,9 @@ public class RecentsCreateFragment extends Fragment { final SpannableStringBuilder builder = new SpannableStringBuilder(); builder.append(stack.root.title); - appendDrawable(builder, crumb); for (int i = stack.size() - 2; i >= 0; i--) { + appendDrawable(builder, crumb); builder.append(stack.get(i).displayName); - if (i > 0) { - appendDrawable(builder, crumb); - } } title.setText(builder); title.setEllipsize(TruncateAt.MIDDLE); diff --git a/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java b/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java index 52d6cc8..15af8aa 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java +++ b/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java @@ -179,6 +179,8 @@ public class RootsCache { final Multimap<String, RootInfo> roots = ArrayListMultimap.create(); final HashSet<String> stoppedAuthorities = Sets.newHashSet(); + roots.put(mRecentsRoot.authority, mRecentsRoot); + final ContentResolver resolver = mContext.getContentResolver(); final PackageManager pm = mContext.getPackageManager(); final List<ProviderInfo> providers = pm.queryContentProviders( diff --git a/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java b/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java index df9bce1..d602622 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java +++ b/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java @@ -253,6 +253,7 @@ public class RootsFragment extends Fragment { } private static class SectionedRootsAdapter extends SectionedListAdapter { + private final RootsAdapter mRecent; private final RootsAdapter mServices; private final RootsAdapter mShortcuts; private final RootsAdapter mDevices; @@ -260,12 +261,18 @@ public class RootsFragment extends Fragment { public SectionedRootsAdapter( Context context, Collection<RootInfo> roots, Intent includeApps) { + mRecent = new RootsAdapter(context); mServices = new RootsAdapter(context); mShortcuts = new RootsAdapter(context); mDevices = new RootsAdapter(context); mApps = new AppsAdapter(context); for (RootInfo root : roots) { + if (root.authority == null) { + mRecent.add(root); + continue; + } + switch (root.rootType) { case Root.ROOT_TYPE_SERVICE: mServices.add(root); @@ -297,15 +304,18 @@ public class RootsFragment extends Fragment { mShortcuts.sort(comp); mDevices.sort(comp); + if (mRecent.getCount() > 0) { + addSection(mRecent); + } + if (mServices.getCount() > 0) { + addSection(mServices); + } if (mShortcuts.getCount() > 0) { addSection(mShortcuts); } if (mDevices.getCount() > 0) { addSection(mDevices); } - if (mServices.getCount() > 0) { - addSection(mServices); - } if (mApps.getCount() > 0) { addSection(mApps); } @@ -315,12 +325,6 @@ public class RootsFragment extends Fragment { public static class RootComparator implements Comparator<RootInfo> { @Override public int compare(RootInfo lhs, RootInfo rhs) { - if (lhs.authority == null) { - return -1; - } else if (rhs.authority == null) { - return 1; - } - final int score = DocumentInfo.compareToIgnoreCaseNullable(lhs.title, rhs.title); if (score != 0) { return score; diff --git a/packages/DocumentsUI/src/com/android/documentsui/SettingsActivity.java b/packages/DocumentsUI/src/com/android/documentsui/SettingsActivity.java index a85f6a9..d423e3f 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/SettingsActivity.java +++ b/packages/DocumentsUI/src/com/android/documentsui/SettingsActivity.java @@ -22,6 +22,7 @@ import android.content.Context; import android.os.Bundle; import android.preference.PreferenceFragment; import android.preference.PreferenceManager; +import android.view.MenuItem; public class SettingsActivity extends Activity { private static final String KEY_ADVANCED_DEVICES = "advancedDevices"; @@ -47,9 +48,19 @@ public class SettingsActivity extends Activity { final ActionBar bar = getActionBar(); if (bar != null) { bar.setDisplayShowHomeEnabled(false); + bar.setDisplayHomeAsUpEnabled(true); } } + @Override + public boolean onOptionsItemSelected(MenuItem item) { + if (item.getItemId() == android.R.id.home) { + finish(); + return true; + } + return super.onOptionsItemSelected(item); + } + public static class SettingsFragment extends PreferenceFragment { @Override public void onCreate(Bundle savedInstanceState) { diff --git a/packages/DocumentsUI/src/com/android/documentsui/model/DocumentInfo.java b/packages/DocumentsUI/src/com/android/documentsui/model/DocumentInfo.java index 681cc9b..08a8c13 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/model/DocumentInfo.java +++ b/packages/DocumentsUI/src/com/android/documentsui/model/DocumentInfo.java @@ -181,7 +181,7 @@ public class DocumentInfo implements Durable, Parcelable { @Override public String toString() { - return "Document{name=" + displayName + ", docId=" + documentId + "}"; + return "Document{docId=" + documentId + ", name=" + displayName + "}"; } public boolean isCreateSupported() { diff --git a/packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java b/packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java index a870c7b..014901a 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java +++ b/packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java @@ -185,7 +185,7 @@ public class RootInfo implements Durable, Parcelable { @Override public String toString() { - return "Root{title=" + title + ", rootId=" + rootId + "}"; + return "Root{authority=" + authority + ", rootId=" + rootId + ", title=" + title + "}"; } public Drawable loadIcon(Context context) { diff --git a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java index 3e2cd15..d6f477d 100644 --- a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java +++ b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java @@ -96,25 +96,6 @@ public class ExternalStorageProvider extends DocumentsProvider { 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; } @@ -230,14 +211,23 @@ public class ExternalStorageProvider extends DocumentsProvider { public String createDocument(String docId, String mimeType, String displayName) throws FileNotFoundException { final File parent = getFileForDocId(docId); - displayName = validateDisplayName(mimeType, displayName); + File file; - final File file = new File(parent, displayName); if (Document.MIME_TYPE_DIR.equals(mimeType)) { + file = new File(parent, displayName); if (!file.mkdir()) { throw new IllegalStateException("Failed to mkdir " + file); } } else { + displayName = removeExtension(mimeType, displayName); + file = new File(parent, addExtension(mimeType, displayName)); + + // If conflicting file, try adding counter suffix + int n = 0; + while (file.exists() && n++ < 32) { + file = new File(parent, addExtension(mimeType, displayName + " (" + n + ")")); + } + try { if (!file.createNewFile()) { throw new IllegalStateException("Failed to touch " + file); @@ -354,20 +344,31 @@ public class ExternalStorageProvider extends DocumentsProvider { return "application/octet-stream"; } - private static String validateDisplayName(String mimeType, String displayName) { - if (Document.MIME_TYPE_DIR.equals(mimeType)) { - return displayName; - } else { - // Try appending meaningful extension if needed - if (!mimeType.equals(getTypeForName(displayName))) { - final String extension = MimeTypeMap.getSingleton() - .getExtensionFromMimeType(mimeType); - if (extension != null) { - displayName += "." + extension; - } + /** + * Remove file extension from name, but only if exact MIME type mapping + * exists. This means we can reapply the extension later. + */ + private static String removeExtension(String mimeType, String name) { + final int lastDot = name.lastIndexOf('.'); + if (lastDot >= 0) { + final String extension = name.substring(lastDot + 1); + final String nameMime = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension); + if (mimeType.equals(nameMime)) { + return name.substring(0, lastDot); } + } + return name; + } - return displayName; + /** + * Add file extension to name, but only if exact MIME type mapping exists. + */ + private static String addExtension(String mimeType, String name) { + final String extension = MimeTypeMap.getSingleton() + .getExtensionFromMimeType(mimeType); + if (extension != null) { + return name + "." + extension; } + return name; } } |