Merge "Create unique files, root ordering, UI bugs." into klp-dev
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.ParcelFileDescriptor;
import android.content.res.AssetFileDescriptor;
+import dalvik.system.CloseGuard;
+
import java.io.FileNotFoundException;
import java.util.ArrayList;
@@ -49,6 +51,8 @@
private final boolean mStable;
private boolean mReleased;
+ private final CloseGuard mGuard = CloseGuard.get();
+
/**
* @hide
*/
@@ -58,6 +62,7 @@
mContentResolver = contentResolver;
mPackageName = contentResolver.mPackageName;
mStable = stable;
+ mGuard.open("release");
}
/** See {@link ContentProvider#query ContentProvider.query} */
@@ -324,6 +329,7 @@
throw new IllegalStateException("Already released");
}
mReleased = true;
+ mGuard.close();
if (mStable) {
return mContentResolver.releaseProvider(mContentProvider);
} else {
@@ -332,6 +338,13 @@
}
}
+ @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 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 @@
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 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.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 @@
/**
* 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 @@
}
}
+ 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 @@
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 @@
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 @@
}
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 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 @@
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 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.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 @@
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 @@
@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 @@
@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 f468abc..0ef5f56 100644
--- a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
+++ b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
@@ -96,25 +96,6 @@
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 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 @@
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 displayName;
}
+ return name;
+ }
+
+ /**
+ * 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;
}
}