Merge "Create unique files, root ordering, UI bugs." into klp-dev

This commit is contained in:
Jeff Sharkey
2013-09-22 19:55:19 +00:00
committed by Android (Google) Code Review
11 changed files with 105 additions and 55 deletions

View File

@@ -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

View File

@@ -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" />

View File

@@ -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) {

View File

@@ -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;

View File

@@ -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);

View File

@@ -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(

View File

@@ -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;

View File

@@ -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) {

View File

@@ -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() {

View File

@@ -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) {

View File

@@ -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 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;
}
}