Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
5d197bd
SecurityException: Permission Denial
hamdikahloun Sep 20, 2020
01f2153
SecurityException: Permission Denial
hamdikahloun Sep 20, 2020
9e4c909
Update PlatformPlugin.java
hamdikahloun Sep 20, 2020
795da8a
Update PlatformPlugin.java
hamdikahloun Sep 20, 2020
dce34fd
Merge branch 'master' into hamdikahloun-patch-SecurityException
hamdikahloun Sep 20, 2020
9443f65
Update PlatformPlugin.java
hamdikahloun Sep 20, 2020
8046589
Update PlatformPlugin.java
hamdikahloun Sep 28, 2020
6b74aa6
Update PlatformPlugin.java
hamdikahloun Sep 28, 2020
f1326fb
Update PlatformPlugin.java
hamdikahloun Sep 28, 2020
3a1fb98
TAG & Log
hamdikahloun Sep 29, 2020
8187b1a
SecurityException for Build Tools 29 and below
hamdikahloun Sep 29, 2020
1a28095
Add Test Uri ClipData
hamdikahloun Sep 29, 2020
ccd25ef
Add Test for Null Uri ClipData
hamdikahloun Sep 29, 2020
8f5417c
Update PlatformPluginTest.java
hamdikahloun Sep 29, 2020
d9ea4ae
Update PlatformPluginTest.java
hamdikahloun Sep 29, 2020
9668074
Update PlatformPluginTest.java
hamdikahloun Sep 29, 2020
b51174b
Update PlatformPluginTest.java
hamdikahloun Sep 29, 2020
7d5a882
Update PlatformPluginTest.java
hamdikahloun Sep 29, 2020
075248d
Update PlatformPluginTest.java
hamdikahloun Sep 29, 2020
a67c6be
Update PlatformPluginTest.java
hamdikahloun Sep 29, 2020
e57ea8a
Update PlatformPluginTest.java
hamdikahloun Sep 29, 2020
ccc1bb3
Update PlatformPluginTest.java
hamdikahloun Sep 30, 2020
051e3bd
Update PlatformPluginTest.java
hamdikahloun Sep 30, 2020
c87294f
platformPlugin_getClipboardData: assertEquals Test
hamdikahloun Oct 8, 2020
00b6be8
Update PlatformPluginTest.java
hamdikahloun Oct 8, 2020
8d04b8c
Update PlatformPluginTest.java
hamdikahloun Oct 8, 2020
5ebfcf4
Update shell/platform/android/io/flutter/plugin/platform/PlatformPlug…
dnfield Oct 8, 2020
06ca28b
Update PlatformPlugin.java
hamdikahloun Oct 8, 2020
e06d03b
Merge remote-tracking branch 'upstream/master' into hamdikahloun-patc…
hamdikahloun Oct 8, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import android.content.ClipboardManager;
import android.content.Context;
import android.os.Build;
import android.util.Log;
Comment thread
dnfield marked this conversation as resolved.
Outdated
import android.view.HapticFeedbackConstants;
import android.view.SoundEffectConstants;
import android.view.View;
Expand All @@ -18,6 +19,7 @@
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import io.flutter.embedding.engine.systemchannels.PlatformChannel;
import java.io.FileNotFoundException;
import java.util.List;

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

@VisibleForTesting
final PlatformChannel.PlatformMessageHandler mPlatformMessageHandler =
Expand Down Expand Up @@ -283,11 +286,25 @@ private CharSequence getClipboardData(PlatformChannel.ClipboardContentFormat for

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

ClipData clip = clipboard.getPrimaryClip();
if (clip == null) return null;

if (format == null || format == PlatformChannel.ClipboardContentFormat.PLAIN_TEXT) {
return clip.getItemAt(0).coerceToText(activity);
try {
ClipData clip = clipboard.getPrimaryClip();
if (clip == null) return null;
if (format == null || format == PlatformChannel.ClipboardContentFormat.PLAIN_TEXT) {
ClipData.Item item = clip.getItemAt(0);
if (item.getUri() != null)
activity.getContentResolver().openTypedAssetFileDescriptor(item.getUri(), "text/*", null);
return item.coerceToText(activity);
}
} catch (SecurityException e) {
Log.w(
TAG,
"Attempted to get clipboard data that requires additional permission(s).\n"
+ "See the exception details for which permission(s) are required, and consider adding them to your Android Manifest as described in:\n"
+ "https://developer.android.com/guide/topics/permissions/overview",
e);
return null;
} catch (FileNotFoundException e) {
return null;
}

return null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
import android.media.RingtoneManager;
import android.net.Uri;
import android.view.View;
import android.view.Window;
import io.flutter.embedding.engine.systemchannels.PlatformChannel;
Expand Down Expand Up @@ -61,6 +63,18 @@ public void platformPlugin_getClipboardData() {
ClipData clip = ClipData.newPlainText("label", "Text");
clipboardManager.setPrimaryClip(clip);
assertNotNull(platformPlugin.mPlatformMessageHandler.getClipboardData(clipboardFormat));

Uri uri = Uri.parse("content://media/external_primary/images/media/");
clip = ClipData.newUri(fakeActivity.getContentResolver(), "URI", uri);
clipboardManager.setPrimaryClip(clip);
assertNull(platformPlugin.mPlatformMessageHandler.getClipboardData(clipboardFormat));

uri =
RingtoneManager.getActualDefaultRingtoneUri(
fakeActivity.getApplicationContext(), RingtoneManager.TYPE_RINGTONE);
clip = ClipData.newUri(fakeActivity.getContentResolver(), "URI", uri);
clipboardManager.setPrimaryClip(clip);
assertNotNull(platformPlugin.mPlatformMessageHandler.getClipboardData(clipboardFormat));

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we do better than assertNotNull here? Maybe assert the data is the string we expect?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@danafergan

It's not possible, The Uri will be converted to InputStreamReader in coerceToText function:

 if (uri != null) {
                // First see if the URI can be opened as a plain text stream
                // (of any sub-type).  If so, this is the best textual
                // representation for it.
                final ContentResolver resolver = context.getContentResolver();
                AssetFileDescriptor descr = null;
                FileInputStream stream = null;
                InputStreamReader reader = null;
                try {
                    try {
                        // Ask for a stream of the desired type.
                        descr = resolver.openTypedAssetFileDescriptor(uri, "text/*", null);
                    } catch (SecurityException e) {
                        Log.w("ClipData", "Failure opening stream", e);
                    } catch (FileNotFoundException|RuntimeException e) {
                        // Unable to open content URI as text...  not really an
                        // error, just something to ignore.
                    }
                    if (descr != null) {
                        try {
                            stream = descr.createInputStream();
                            reader = new InputStreamReader(stream, "UTF-8");

                            // Got it...  copy the stream into a local string and return it.
                            final StringBuilder builder = new StringBuilder(128);
                            char[] buffer = new char[8192];
                            int len;
                            while ((len=reader.read(buffer)) > 0) {
                                builder.append(buffer, 0, len);
                            }
                            return builder.toString();
                        } catch (IOException e) {
                            // Something bad has happened.
                            Log.w("ClipData", "Failure loading text", e);
                            return e.toString();
                        }
                    }
                } finally {
                    IoUtils.closeQuietly(descr);
                    IoUtils.closeQuietly(stream);
                    IoUtils.closeQuietly(reader);
                }

                // If we couldn't open the URI as a stream, use the URI itself as a textual
                // representation (but not for "content", "android.resource" or "file" schemes).
                final String scheme = uri.getScheme();
                if (SCHEME_CONTENT.equals(scheme)
                        || SCHEME_ANDROID_RESOURCE.equals(scheme)
                        || SCHEME_FILE.equals(scheme)) {
                    return "";
                }
                return uri.toString();
            }

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can't we just read the inputstream and make sure it contains what we'd expect?

@hamdikahloun hamdikahloun Sep 30, 2020

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dnfield wdyt :

assertEquals
..............
..............

uri = RingtoneManager.getActualDefaultRingtoneUri...........

String value = platformPlugin.mPlatformMessageHandler.getClipboardData(clipboardFormat).toString();

assertEquals(getExpectedValue(uri, resolver), value);

String getExpectedValue(Uri uri, ContentResolver resolver) throws IOException {
    AssetFileDescriptor descr = null;
    FileInputStream stream = null;
    InputStreamReader reader = null;
    try {
      try {
        descr = resolver.openTypedAssetFileDescriptor(uri, "text/*", null);
      } catch (SecurityException e) {
        return null;
      } catch (FileNotFoundException | RuntimeException e) {
        return null;
      }
      if (descr != null) {
        try {
          stream = descr.createInputStream();
          reader = new InputStreamReader(stream, "UTF-8");

          final StringBuilder builder = new StringBuilder(128);
          char[] buffer = new char[8192];
          int len;
          while ((len = reader.read(buffer)) > 0) {
            builder.append(buffer, 0, len);
          }
          return builder.toString();
        } catch (IOException e) {
          return e.toString();
        }
      }
    } finally {
      if (descr != null) descr.close();
      if (stream != null) stream.close();
      if (reader != null) reader.close();
    }

    // If we couldn't open the URI as a stream, use the URI itself as a textual
    // representation (but not for "content", "android.resource" or "file" schemes).
    final String scheme = uri.getScheme();
    if (SCHEME_CONTENT.equals(scheme)
        || SCHEME_ANDROID_RESOURCE.equals(scheme)
        || SCHEME_FILE.equals(scheme)) {
      return "";
    }
    return uri.toString();
  }

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure. If there's something slightly less complicated where we can just check that it's an InputStream and that its contents are sane that's probably fine too.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will test with another Build Tools version and I will come back with feedback

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dnfield Test Updated. Thanks

}

@Test
Expand Down