diff options
| author | Jorge Ruesga <jorge@ruesga.com> | 2013-11-15 01:41:32 +0100 |
|---|---|---|
| committer | Jorge Ruesga <jorge@ruesga.com> | 2013-11-15 01:41:32 +0100 |
| commit | f0ff624a4fe2fd5651ad6b79e02050e0c01acdac (patch) | |
| tree | dc7267578bf7652637818a982fd976641ec1e675 | |
| parent | d60e42f5aaf303449ce7ae6b15bcb1484a4b68cf (diff) | |
| download | android_packages_apps_CMFileManager-f0ff624a4fe2fd5651ad6b79e02050e0c01acdac.tar.gz android_packages_apps_CMFileManager-f0ff624a4fe2fd5651ad6b79e02050e0c01acdac.tar.bz2 android_packages_apps_CMFileManager-f0ff624a4fe2fd5651ad6b79e02050e0c01acdac.zip | |
Select content uris vs file uris when open or send files
Change-Id: I1e576ccc3d14f9e02bd0148f530133065bfc20bf
JIRA: CYAN-2649
Issue: https://jira.cyanogenmod.org/browse/CYAN-2649
Signed-off-by: Jorge Ruesga <jorge@ruesga.com>
4 files changed, 166 insertions, 11 deletions
diff --git a/src/com/cyanogenmod/filemanager/activities/EditorActivity.java b/src/com/cyanogenmod/filemanager/activities/EditorActivity.java index 2a6b9d87..68f91f31 100644 --- a/src/com/cyanogenmod/filemanager/activities/EditorActivity.java +++ b/src/com/cyanogenmod/filemanager/activities/EditorActivity.java @@ -28,6 +28,7 @@ import android.content.IntentFilter; import android.content.res.Configuration; import android.graphics.Typeface; import android.graphics.drawable.Drawable; +import android.net.Uri; import android.os.AsyncTask; import android.os.Bundle; import android.os.Handler; @@ -78,6 +79,7 @@ import com.cyanogenmod.filemanager.util.DialogHelper; import com.cyanogenmod.filemanager.util.ExceptionUtil; import com.cyanogenmod.filemanager.util.ExceptionUtil.OnRelaunchCommandResult; import com.cyanogenmod.filemanager.util.FileHelper; +import com.cyanogenmod.filemanager.util.MediaHelper; import com.cyanogenmod.filemanager.util.ResourcesHelper; import java.io.ByteArrayInputStream; @@ -907,7 +909,7 @@ public class EditorActivity extends Activity implements TextWatcher { this.mReadOnly = false; // Read the intent and check that is has a valid request - String path = getIntent().getData().getPath(); + String path = uriToPath(this, getIntent().getData()); if (path == null || path.length() == 0) { DialogHelper.showToast( this, R.string.editor_invalid_file_msg, Toast.LENGTH_SHORT); @@ -1509,4 +1511,18 @@ public class EditorActivity extends Activity implements TextWatcher { theme.setTextColor(this, editor, "text_color"); //$NON-NLS-1$ } + /** + * Method that resolves the content uri to a valid system path + * + * @param ctx The current context + * @param uri The content uri + * @return String The system path + */ + private static String uriToPath(Context ctx, Uri uri) { + File file = MediaHelper.contentUriToFile(ctx.getContentResolver(), uri); + if (file == null) { + file = new File(uri.getPath()); + } + return file.getAbsolutePath(); + } } diff --git a/src/com/cyanogenmod/filemanager/activities/PickerActivity.java b/src/com/cyanogenmod/filemanager/activities/PickerActivity.java index f548b413..fdf50993 100644 --- a/src/com/cyanogenmod/filemanager/activities/PickerActivity.java +++ b/src/com/cyanogenmod/filemanager/activities/PickerActivity.java @@ -21,6 +21,7 @@ import android.app.AlertDialog; import android.content.ActivityNotFoundException; import android.content.BroadcastReceiver; import android.content.ComponentName; +import android.content.ContentResolver; import android.content.Context; import android.content.DialogInterface; import android.content.DialogInterface.OnCancelListener; @@ -60,6 +61,7 @@ import com.cyanogenmod.filemanager.ui.widgets.NavigationView.OnFilePickedListene import com.cyanogenmod.filemanager.util.DialogHelper; import com.cyanogenmod.filemanager.util.ExceptionUtil; import com.cyanogenmod.filemanager.util.FileHelper; +import com.cyanogenmod.filemanager.util.MediaHelper; import com.cyanogenmod.filemanager.util.MimeTypeHelper; import com.cyanogenmod.filemanager.util.StorageHelper; @@ -428,7 +430,7 @@ public class PickerActivity extends Activity // Return the picked file, as expected (this activity should fill the intent data // and return RESULT_OK result) Intent result = new Intent(); - result.setData(getResultUriForFileFromIntent(src, getIntent())); + result.setData(getResultUriForFileFromIntent(getContentResolver(), src, getIntent())); setResult(Activity.RESULT_OK, result); finish(); @@ -490,8 +492,12 @@ public class PickerActivity extends Activity return file.getParentFile(); } - private static Uri getResultUriForFileFromIntent(File src, Intent intent) { - Uri result = Uri.fromFile(src); + private static Uri getResultUriForFileFromIntent(ContentResolver cr, File src, Intent intent) { + // Try to find the preferred uri scheme + Uri result = MediaHelper.fileToContentUri(cr, src); + if (result == null) { + result = Uri.fromFile(src); + } if (Intent.ACTION_PICK.equals(intent.getAction()) && intent.getData() != null) { String scheme = intent.getData().getScheme(); diff --git a/src/com/cyanogenmod/filemanager/ui/policy/IntentsActionPolicy.java b/src/com/cyanogenmod/filemanager/ui/policy/IntentsActionPolicy.java index c0711c50..852d2984 100644 --- a/src/com/cyanogenmod/filemanager/ui/policy/IntentsActionPolicy.java +++ b/src/com/cyanogenmod/filemanager/ui/policy/IntentsActionPolicy.java @@ -17,6 +17,7 @@ package com.cyanogenmod.filemanager.ui.policy; import android.content.ComponentName; +import android.content.ContentResolver; import android.content.Context; import android.content.DialogInterface.OnCancelListener; import android.content.DialogInterface.OnDismissListener; @@ -37,6 +38,7 @@ import com.cyanogenmod.filemanager.ui.dialogs.AssociationsDialog; import com.cyanogenmod.filemanager.util.DialogHelper; import com.cyanogenmod.filemanager.util.ExceptionUtil; import com.cyanogenmod.filemanager.util.FileHelper; +import com.cyanogenmod.filemanager.util.MediaHelper; import com.cyanogenmod.filemanager.util.MimeTypeHelper; import com.cyanogenmod.filemanager.util.MimeTypeHelper.MimeTypeCategory; import com.cyanogenmod.filemanager.util.ResourcesHelper; @@ -99,9 +101,9 @@ public final class IntentsActionPolicy extends ActionsPolicy { String mime = MimeTypeHelper.getMimeType(ctx, fso); File file = new File(fso.getFullPath()); if (mime != null) { - intent.setDataAndType(Uri.fromFile(file), mime); + intent.setDataAndType(getUriFromFile(ctx, file), mime); } else { - intent.setData(Uri.fromFile(file)); + intent.setData(getUriFromFile(ctx, file)); } // Resolve the intent @@ -138,7 +140,7 @@ public final class IntentsActionPolicy extends ActionsPolicy { intent.setAction(android.content.Intent.ACTION_SEND); intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); intent.setType(MimeTypeHelper.getMimeType(ctx, fso)); - Uri uri = Uri.fromFile(new File(fso.getFullPath())); + Uri uri = getUriFromFile(ctx, new File(fso.getFullPath())); intent.putExtra(Intent.EXTRA_STREAM, uri); // Resolve the intent @@ -199,7 +201,7 @@ public final class IntentsActionPolicy extends ActionsPolicy { lastMimeType = mimeType; // Add the uri - uris.add(Uri.fromFile(new File(fso.getFullPath()))); + uris.add(getUriFromFile(ctx, new File(fso.getFullPath()))); } if (sameMimeType) { intent.setType(lastMimeType); @@ -580,4 +582,19 @@ public final class IntentsActionPolicy extends ActionsPolicy { }); return pref.get(0); } + + /** + * Method that returns the best Uri for the file (content uri, file uri, ...) + * + * @param ctx The current context + * @param file The file to resolve + */ + private static Uri getUriFromFile(Context ctx, File file) { + ContentResolver cr = ctx.getContentResolver(); + Uri uri = MediaHelper.fileToContentUri(cr, file); + if (uri == null) { + uri = Uri.fromFile(file); + } + return uri; + } } diff --git a/src/com/cyanogenmod/filemanager/util/MediaHelper.java b/src/com/cyanogenmod/filemanager/util/MediaHelper.java index db818db3..bb6a9c6b 100644 --- a/src/com/cyanogenmod/filemanager/util/MediaHelper.java +++ b/src/com/cyanogenmod/filemanager/util/MediaHelper.java @@ -22,6 +22,7 @@ import android.net.Uri; import android.os.UserHandle; import android.provider.BaseColumns; import android.provider.MediaStore; +import android.provider.MediaStore.MediaColumns; import android.text.TextUtils; import java.io.File; @@ -33,6 +34,13 @@ import java.util.Map; */ public final class MediaHelper { + private static final String EMULATED_STORAGE_SOURCE = System.getenv("EMULATED_STORAGE_SOURCE"); + private static final String EMULATED_STORAGE_TARGET = System.getenv("EMULATED_STORAGE_TARGET"); + private static final String EXTERNAL_STORAGE = System.getenv("EXTERNAL_STORAGE"); + + private static final String INTERNAL_VOLUME = "internal"; + private static final String EXTERNAL_VOLUME = "external"; + /** * URIs that are relevant for determining album art; * useful for content observer registration @@ -98,9 +106,117 @@ public final class MediaHelper { return null; } - private static final String EMULATED_STORAGE_SOURCE = System.getenv("EMULATED_STORAGE_SOURCE"); - private static final String EMULATED_STORAGE_TARGET = System.getenv("EMULATED_STORAGE_TARGET"); - private static final String EXTERNAL_STORAGE = System.getenv("EXTERNAL_STORAGE"); + /** + * Method that converts a file reference to a content uri reference + * + * @param cr A content resolver + * @param file The file reference + * @return Uri The content uri or null if file not exists in the media database + */ + public static Uri fileToContentUri(ContentResolver cr, File file) { + // Normalize the path to ensure media search + final String normalizedPath = normalizeMediaPath(file.getAbsolutePath()); + + // Check in external and internal storages + Uri uri = fileToContentUri(cr, normalizedPath, EXTERNAL_VOLUME); + if (uri != null) { + return uri; + } + uri = fileToContentUri(cr, normalizedPath, INTERNAL_VOLUME); + if (uri != null) { + return uri; + } + return null; + } + + /** + * Method that converts a file reference to a content uri reference + * + * @param cr A content resolver + * @param path The path to search + * @param volume The volume + * @return Uri The content uri or null if file not exists in the media database + */ + private static Uri fileToContentUri(ContentResolver cr, String path, String volume) { + final String[] projection = {BaseColumns._ID, MediaStore.Files.FileColumns.MEDIA_TYPE}; + final String where = MediaColumns.DATA + " = ?"; + Uri baseUri = MediaStore.Files.getContentUri(volume); + Cursor c = cr.query(baseUri, projection, where, new String[]{path}, null); + try { + if (c != null && c.moveToNext()) { + int type = c.getInt(c.getColumnIndexOrThrow( + MediaStore.Files.FileColumns.MEDIA_TYPE)); + if (type != 0) { + // Do not force to use content uri for no media files + long id = c.getLong(c.getColumnIndexOrThrow(BaseColumns._ID)); + return Uri.withAppendedPath(baseUri, String.valueOf(id)); + } + } + } finally { + if (c != null) { + c.close(); + } + } + return null; + } + + /** + * Method that converts a content uri to a file system path + * + * @param cr The content resolver + * @param uri The content uri + * @return File The file reference + */ + public static File contentUriToFile(ContentResolver cr, Uri uri) { + // Sanity checks + if (uri == null || uri.getScheme() == null || uri.getScheme().compareTo("content") != 0) { + return null; + } + + // Retrieve the request id + long id = 0; + try { + id = Long.parseLong(new File(uri.getPath()).getName()); + } catch (NumberFormatException nfex) { + return null; + } + + // Check in external and internal storages + File file = mediaIdToFile(cr, id, EXTERNAL_VOLUME); + if (file != null) { + return file; + } + file = mediaIdToFile(cr, id, INTERNAL_VOLUME); + if (file != null) { + return file; + } + return null; + } + + /** + * Method that converts a content uri to a file system path + * + * @param cr The content resolver + * @param id The media database id + * @param volume The volume + * @return File The file reference + */ + private static File mediaIdToFile(ContentResolver cr, long id, String volume) { + final String[] projection = {MediaColumns.DATA}; + final String where = MediaColumns._ID + " = ?"; + Uri baseUri = MediaStore.Files.getContentUri(volume); + Cursor c = cr.query(baseUri, projection, where, new String[]{String.valueOf(id)}, null); + try { + if (c != null && c.moveToNext()) { + return new File(c.getString(c.getColumnIndexOrThrow(MediaColumns.DATA))); + } + } finally { + if (c != null) { + c.close(); + } + } + return null; + } /** * Method that converts a not standard media mount path to a standard media path |
