Skip to content

Commit b2ace0c

Browse files
SecurityException: Permission Denial (flutter#21290)
Fix `java.lang.SecurityException: Permission Denial: reading com.android.providers.media.MediaProvider` Fixes flutter#66108 Co-authored-by: Dan Field <dfield@gmail.com>
1 parent 9ab40c2 commit b2ace0c

File tree

2 files changed

+48
-6
lines changed

2 files changed

+48
-6
lines changed

shell/platform/android/io/flutter/plugin/platform/PlatformPlugin.java

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,9 @@
1717
import androidx.annotation.NonNull;
1818
import androidx.annotation.Nullable;
1919
import androidx.annotation.VisibleForTesting;
20+
import io.flutter.Log;
2021
import io.flutter.embedding.engine.systemchannels.PlatformChannel;
22+
import java.io.FileNotFoundException;
2123
import java.util.List;
2224

2325
/** Android implementation of the platform plugin. */
@@ -29,6 +31,7 @@ public class PlatformPlugin {
2931
private final PlatformChannel platformChannel;
3032
private PlatformChannel.SystemChromeStyle currentTheme;
3133
private int mEnabledOverlays;
34+
private static final String TAG = "PlatformPlugin";
3235

3336
@VisibleForTesting
3437
final PlatformChannel.PlatformMessageHandler mPlatformMessageHandler =
@@ -283,11 +286,25 @@ private CharSequence getClipboardData(PlatformChannel.ClipboardContentFormat for
283286

284287
if (!clipboard.hasPrimaryClip()) return null;
285288

286-
ClipData clip = clipboard.getPrimaryClip();
287-
if (clip == null) return null;
288-
289-
if (format == null || format == PlatformChannel.ClipboardContentFormat.PLAIN_TEXT) {
290-
return clip.getItemAt(0).coerceToText(activity);
289+
try {
290+
ClipData clip = clipboard.getPrimaryClip();
291+
if (clip == null) return null;
292+
if (format == null || format == PlatformChannel.ClipboardContentFormat.PLAIN_TEXT) {
293+
ClipData.Item item = clip.getItemAt(0);
294+
if (item.getUri() != null)
295+
activity.getContentResolver().openTypedAssetFileDescriptor(item.getUri(), "text/*", null);
296+
return item.coerceToText(activity);
297+
}
298+
} catch (SecurityException e) {
299+
Log.w(
300+
TAG,
301+
"Attempted to get clipboard data that requires additional permission(s).\n"
302+
+ "See the exception details for which permission(s) are required, and consider adding them to your Android Manifest as described in:\n"
303+
+ "https://developer.android.com/guide/topics/permissions/overview",
304+
e);
305+
return null;
306+
} catch (FileNotFoundException e) {
307+
return null;
291308
}
292309

293310
return null;

shell/platform/android/test/io/flutter/plugin/platform/PlatformPluginTest.java

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package io.flutter.plugin.platform;
22

3+
import static org.junit.Assert.assertEquals;
34
import static org.junit.Assert.assertFalse;
45
import static org.junit.Assert.assertNotNull;
56
import static org.junit.Assert.assertNull;
@@ -10,11 +11,17 @@
1011
import android.app.Activity;
1112
import android.content.ClipData;
1213
import android.content.ClipboardManager;
14+
import android.content.ContentResolver;
1315
import android.content.Context;
16+
import android.media.RingtoneManager;
17+
import android.net.Uri;
1418
import android.view.View;
1519
import android.view.Window;
1620
import io.flutter.embedding.engine.systemchannels.PlatformChannel;
1721
import io.flutter.embedding.engine.systemchannels.PlatformChannel.ClipboardContentFormat;
22+
import java.io.ByteArrayInputStream;
23+
import java.io.IOException;
24+
import java.io.InputStream;
1825
import org.junit.Test;
1926
import org.junit.runner.RunWith;
2027
import org.robolectric.RobolectricTestRunner;
@@ -42,8 +49,9 @@ public void itIgnoresNewHapticEventsOnOldAndroidPlatforms() {
4249
platformPlugin.vibrateHapticFeedback(PlatformChannel.HapticFeedbackType.SELECTION_CLICK);
4350
}
4451

52+
@Config(sdk = 29)
4553
@Test
46-
public void platformPlugin_getClipboardData() {
54+
public void platformPlugin_getClipboardData() throws IOException {
4755
ClipboardManager clipboardManager =
4856
RuntimeEnvironment.application.getSystemService(ClipboardManager.class);
4957

@@ -61,6 +69,23 @@ public void platformPlugin_getClipboardData() {
6169
ClipData clip = ClipData.newPlainText("label", "Text");
6270
clipboardManager.setPrimaryClip(clip);
6371
assertNotNull(platformPlugin.mPlatformMessageHandler.getClipboardData(clipboardFormat));
72+
73+
ContentResolver contentResolver = RuntimeEnvironment.application.getContentResolver();
74+
Uri uri = Uri.parse("content://media/external_primary/images/media/");
75+
clip = ClipData.newUri(contentResolver, "URI", uri);
76+
clipboardManager.setPrimaryClip(clip);
77+
assertNull(platformPlugin.mPlatformMessageHandler.getClipboardData(clipboardFormat));
78+
79+
uri =
80+
RingtoneManager.getActualDefaultRingtoneUri(
81+
RuntimeEnvironment.application.getApplicationContext(), RingtoneManager.TYPE_RINGTONE);
82+
clip = ClipData.newUri(contentResolver, "URI", uri);
83+
clipboardManager.setPrimaryClip(clip);
84+
String uriData =
85+
platformPlugin.mPlatformMessageHandler.getClipboardData(clipboardFormat).toString();
86+
InputStream uriInputStream = contentResolver.openInputStream(uri);
87+
InputStream dataInputStream = new ByteArrayInputStream(uriData.getBytes());
88+
assertEquals(dataInputStream.read(), uriInputStream.read());
6489
}
6590

6691
@Test

0 commit comments

Comments
 (0)