diff options
author | Steve Kondik <steve@cyngn.com> | 2016-09-06 02:55:05 -0700 |
---|---|---|
committer | Steve Kondik <steve@cyngn.com> | 2016-09-06 02:55:05 -0700 |
commit | 578f0a0ed7870b5a8ed28c7c0198a798b389a682 (patch) | |
tree | 75750726ea3b9c8d0e9896e99d9013cd081a3d8c | |
parent | 0c04e1da60cf8af9e6681f48bf0b4b4b42a57d49 (diff) | |
download | android_packages_apps_CMFileManager-578f0a0ed7870b5a8ed28c7c0198a798b389a682.tar.gz android_packages_apps_CMFileManager-578f0a0ed7870b5a8ed28c7c0198a798b389a682.tar.bz2 android_packages_apps_CMFileManager-578f0a0ed7870b5a8ed28c7c0198a798b389a682.zip |
cmfm: Use FileProvider for serving files
* On N, apps can no longer share file:// uris to other packages.
Apps that wish to do this must use a FileProvider to
generate content uris which can then be shared.
* This patch only currently handles the external storage case and does
not consider arbitrary filesystem paths or root access. This could
be implemented in the future, if necessary. The common case of
opening a media file is a good start, though.
Change-Id: I83aef923dfa26173171a13c0881aeb43337b4e47
6 files changed, 43 insertions, 15 deletions
diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 7d00f0bc..46602187 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -76,6 +76,16 @@ android:authorities="com.cyanogenmod.filemanager.providers.index" android:name=".providers.MimeTypeIndexProvider"/> + <provider + android:name="android.support.v4.content.FileProvider" + android:authorities="com.cyanogenmod.filemanager.providers.file" + android:exported="false" + android:grantUriPermissions="true"> + <meta-data + android:name="android.support.FILE_PROVIDER_PATHS" + android:resource="@xml/provider_paths" /> + </provider> + <service android:name=".service.MimeTypeIndexService" android:label="@string/app_name"> diff --git a/res/xml/provider_paths.xml b/res/xml/provider_paths.xml new file mode 100644 index 00000000..4ff89311 --- /dev/null +++ b/res/xml/provider_paths.xml @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="utf-8"?> +<paths xmlns:android="http://schemas.android.com/apk/res/android"> + <external-path name="external_files" path="."/> +</paths> diff --git a/src/com/cyanogenmod/filemanager/activities/NavigationActivity.java b/src/com/cyanogenmod/filemanager/activities/NavigationActivity.java index e1e4a35f..675a8745 100755 --- a/src/com/cyanogenmod/filemanager/activities/NavigationActivity.java +++ b/src/com/cyanogenmod/filemanager/activities/NavigationActivity.java @@ -44,6 +44,7 @@ import android.os.Parcelable; import android.os.storage.StorageVolume; import android.provider.Settings; import android.support.v4.app.ActionBarDrawerToggle; +import android.support.v4.content.FileProvider; import android.support.v4.widget.DrawerLayout; import android.text.TextUtils; import android.util.Log; @@ -623,7 +624,10 @@ public class NavigationActivity extends Activity for (FileSystemObject f : selectedFiles) { //Beam ignores folders and system files if (!FileHelper.isDirectory(f) && !FileHelper.isSystemFile(f)) { - fileUri.add(Uri.fromFile(new File(f.getFullPath()))); + fileUri.add(FileProvider.getUriForFile( + NavigationActivity.this, + "com.cyanogenmod.filemanager.providers.file", + new File(f.getFullPath()))); } } if (fileUri.size() > 0) { diff --git a/src/com/cyanogenmod/filemanager/activities/PickerActivity.java b/src/com/cyanogenmod/filemanager/activities/PickerActivity.java index ba5fa53a..17707a66 100644 --- a/src/com/cyanogenmod/filemanager/activities/PickerActivity.java +++ b/src/com/cyanogenmod/filemanager/activities/PickerActivity.java @@ -34,6 +34,7 @@ import android.os.Bundle; import android.os.Environment; import android.os.Handler; import android.os.storage.StorageVolume; +import android.support.v4.content.FileProvider; import android.text.TextUtils; import android.util.DisplayMetrics; import android.util.Log; @@ -466,7 +467,8 @@ public class PickerActivity extends Activity if (getIntent().getType() != null) { intent.setType(getIntent().getType()); } - intent.setData(Uri.fromFile(src)); + intent.setData(FileProvider.getUriForFile(this, + "com.cyanogenmod.filemanager.providers.file", src)); intent.putExtras(extras); intent.setComponent(CROP_COMPONENT); try { @@ -572,7 +574,8 @@ public class PickerActivity extends Activity // Try to find the preferred uri scheme Uri result = MediaHelper.fileToContentUri(context, src); if (result == null) { - result = Uri.fromFile(src); + result = FileProvider.getUriForFile(context, + "com.cyanogenmod.filemanager.providers.file", src); } if (Intent.ACTION_PICK.equals(intent.getAction()) && intent.getData() != null) { diff --git a/src/com/cyanogenmod/filemanager/ui/dialogs/AssociationsDialog.java b/src/com/cyanogenmod/filemanager/ui/dialogs/AssociationsDialog.java index a90281dd..774b3383 100644 --- a/src/com/cyanogenmod/filemanager/ui/dialogs/AssociationsDialog.java +++ b/src/com/cyanogenmod/filemanager/ui/dialogs/AssociationsDialog.java @@ -166,7 +166,7 @@ public class AssociationsDialog implements OnItemClickListener { public void onClick(DialogInterface dialog, int which) { ResolveInfo ri = getSelected(); Intent intent = - IntentsActionPolicy.getIntentFromResolveInfo( + IntentsActionPolicy.getIntentFromResolveInfo(mContext, ri, AssociationsDialog.this.mRequestIntent); // Open the intent (and remember the action is the check is marked) diff --git a/src/com/cyanogenmod/filemanager/ui/policy/IntentsActionPolicy.java b/src/com/cyanogenmod/filemanager/ui/policy/IntentsActionPolicy.java index 67041bb8..3451ebe5 100755 --- a/src/com/cyanogenmod/filemanager/ui/policy/IntentsActionPolicy.java +++ b/src/com/cyanogenmod/filemanager/ui/policy/IntentsActionPolicy.java @@ -26,6 +26,7 @@ import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.net.Uri; import android.provider.MediaStore; +import android.support.v4.content.FileProvider; import android.util.Log; import android.widget.Toast; import com.cyanogenmod.filemanager.R; @@ -165,6 +166,8 @@ public final class IntentsActionPolicy extends ActionsPolicy { intent.setData(getUriFromFile(ctx, fso)); } + intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); + // Resolve the intent resolveIntent(ctx, intent, choose, onDismissListener); } catch (Exception e) { @@ -443,7 +446,8 @@ public final class IntentsActionPolicy extends ActionsPolicy { * @param request The requested intent * @return Intent The intent */ - public static final Intent getIntentFromResolveInfo(ResolveInfo ri, Intent request) { + public static final Intent getIntentFromResolveInfo(Context context, + ResolveInfo ri, Intent request) { Intent intent = getIntentFromComponentName( new ComponentName( @@ -473,7 +477,7 @@ public final class IntentsActionPolicy extends ActionsPolicy { } // Grant access to resources if needed - grantSecureAccessIfNeeded(intent, ri); + grantSecureAccessIfNeeded(context, intent, ri); return intent; } @@ -484,7 +488,8 @@ public final class IntentsActionPolicy extends ActionsPolicy { * @param intent The intent to grant access * @param ri The resolved info associated with the intent */ - public static final void grantSecureAccessIfNeeded(Intent intent, ResolveInfo ri) { + public static final void grantSecureAccessIfNeeded(Context context, + Intent intent, ResolveInfo ri) { // If this intent will be serve by the SecureResourceProvider then this uri must // be granted before we start it, only for external apps. The internal editor // must receive an file scheme uri @@ -492,32 +497,33 @@ public final class IntentsActionPolicy extends ActionsPolicy { String authority = null; if (uri != null) { authority = uri.getAuthority(); - grantSecureAccess(intent, authority, ri, uri); + grantSecureAccess(context, intent, authority, ri, uri); } else if (intent.getExtras() != null) { Object obj = intent.getExtras().get(Intent.EXTRA_STREAM); if (obj instanceof Uri) { uri = (Uri) intent.getExtras().get(Intent.EXTRA_STREAM); authority = uri.getAuthority(); - grantSecureAccess(intent, authority, ri, uri); + grantSecureAccess(context, intent, authority, ri, uri); } else if (obj instanceof ArrayList) { ArrayList<Uri> uris = (ArrayList<Uri>) intent.getExtras().get(Intent.EXTRA_STREAM); for (Uri u : uris) { authority = u.getAuthority(); - grantSecureAccess(intent, authority, ri, u); + grantSecureAccess(context, intent, authority, ri, u); } } } } - private static final void grantSecureAccess(Intent intent, String authority, ResolveInfo ri, - Uri uri) { + private static final void grantSecureAccess(Context context, Intent intent, + String authority, ResolveInfo ri, Uri uri) { if (authority != null && authority.equals(SecureResourceProvider.AUTHORITY)) { boolean isInternalEditor = isInternalEditor(ri); if (isInternalEditor) { // remove the authorization and change request to file scheme AuthorizationResource auth = SecureResourceProvider.revertAuthorization(uri); - intent.setData(Uri.fromFile(new File(auth.mFile.getFullPath()))); - + intent.setData(FileProvider.getUriForFile(context, + "com.cyanogenmod.filemanager.providers.file", + new File(auth.mFile.getFullPath()))); } else { // Grant access to the package SecureResourceProvider.grantAuthorizationUri(uri, @@ -661,7 +667,8 @@ public final class IntentsActionPolicy extends ActionsPolicy { final File file = new File(fso.getFullPath()); Uri uri = MediaHelper.fileToContentUri(ctx, file); if (uri == null) { - uri = Uri.fromFile(file); + uri = FileProvider.getUriForFile(ctx, + "com.cyanogenmod.filemanager.providers.file", file); } return uri; } |