From 7b7fa2578d60a2befaca908159f02d492514ff85 Mon Sep 17 00:00:00 2001 From: Shi Hao Hong Date: Fri, 23 Aug 2019 16:04:08 -0700 Subject: [PATCH 01/17] (WIP) setting up setSystemGestureExclusionRects platform channel --- .../systemchannels/PlatformChannel.java | 38 ++++++++++++++++++- .../plugin/platform/PlatformPlugin.java | 22 +++++++++++ 2 files changed, 59 insertions(+), 1 deletion(-) diff --git a/shell/platform/android/io/flutter/embedding/engine/systemchannels/PlatformChannel.java b/shell/platform/android/io/flutter/embedding/engine/systemchannels/PlatformChannel.java index 68eeb7c7506cc..13c4cc961c8f4 100644 --- a/shell/platform/android/io/flutter/embedding/engine/systemchannels/PlatformChannel.java +++ b/shell/platform/android/io/flutter/embedding/engine/systemchannels/PlatformChannel.java @@ -5,8 +5,10 @@ package io.flutter.embedding.engine.systemchannels; import android.content.pm.ActivityInfo; +import android.graphics.Rect; import android.support.annotation.NonNull; import android.support.annotation.Nullable; +import android.util.Log; import org.json.JSONArray; import org.json.JSONException; @@ -15,7 +17,6 @@ import java.util.ArrayList; import java.util.List; -import io.flutter.Log; import io.flutter.embedding.engine.dart.DartExecutor; import io.flutter.plugin.common.JSONMethodCodec; import io.flutter.plugin.common.MethodCall; @@ -118,6 +119,18 @@ public void onMethodCall(@NonNull MethodCall call, @NonNull MethodChannel.Result platformMessageHandler.popSystemNavigator(); result.success(null); break; + case "SystemGestures.setSystemGestureExclusionRects": + if (arguments instanceof JSONArray) { + Log.v(TAG, "passed check"); + JSONArray inputRects = (JSONArray) arguments; + Log.v(TAG, inputRects.getJSONObject(0).get("top").toString()); + ArrayList decodedRects = decodeRects(inputRects); + result.success(null); + } else { + String inputTypeError = "Input type is incorrect. Ensure that a List> is passed as the input."; + result.error("inputTypeError", inputTypeError, null); + } + break; case "Clipboard.getData": { String contentFormatName = (String) arguments; ClipboardContentFormat clipboardFormat = null; @@ -337,6 +350,26 @@ private SystemChromeStyle decodeSystemChromeStyle(@NonNull JSONObject encodedSty ); } + private ArrayList decodeRects(@NonNull JSONArray inputRects) { + ArrayList exclusionRects = new ArrayList(); + try { + for (int i = 0; i < inputRects.length(); i++) { + JSONObject rect = inputRects.getJSONObject(i); + + int top = rect.getInt("top"); + int right = rect.getInt("right"); + int bottom = rect.getInt("bottom"); + int left = rect.getInt("left"); + + Rect gestureRect = new Rect(left, top, right, bottom); + exclusionRects.add(gestureRect); + } + } catch (JSONException e) { + //some exception handler code. + } + return exclusionRects; + } + /** * Handler that receives platform messages sent from Flutter to Android * through a given {@link PlatformChannel}. @@ -420,6 +453,9 @@ public interface PlatformMessageHandler { * clipboard to the given {@code text}. */ void setClipboardData(@NonNull String text); + + /* TODO: Write docs */ + void setSystemGestureExclusionRects(@NonNull ArrayList rects); } /** diff --git a/shell/platform/android/io/flutter/plugin/platform/PlatformPlugin.java b/shell/platform/android/io/flutter/plugin/platform/PlatformPlugin.java index 0a9718a81c0b1..b8f6639dd7067 100644 --- a/shell/platform/android/io/flutter/plugin/platform/PlatformPlugin.java +++ b/shell/platform/android/io/flutter/plugin/platform/PlatformPlugin.java @@ -9,6 +9,7 @@ import android.content.ClipData; import android.content.ClipboardManager; import android.content.Context; +import android.graphics.Rect; import android.os.Build; import android.support.annotation.NonNull; import android.support.annotation.Nullable; @@ -17,8 +18,12 @@ import android.view.View; import android.view.Window; +import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import android.util.Log; + import io.flutter.embedding.engine.systemchannels.PlatformChannel; import io.flutter.plugin.common.ActivityLifecycleListener; @@ -84,6 +89,12 @@ public CharSequence getClipboardData(@Nullable PlatformChannel.ClipboardContentF public void setClipboardData(@NonNull String text) { PlatformPlugin.this.setClipboardData(text); } + + @Override + public void setSystemGestureExclusionRects(@NonNull ArrayList rects) { + Log.v("TAG", "WHAT IS THIS"); + PlatformPlugin.this.setSystemGestureExclusionRects(rects); + } }; public PlatformPlugin(Activity activity, PlatformChannel platformChannel) { @@ -272,4 +283,15 @@ private void setClipboardData(String text) { ClipData clip = ClipData.newPlainText("text label?", text); clipboard.setPrimaryClip(clip); } + + private void setSystemGestureExclusionRects(ArrayList rects) { + if (Build.VERSION.SDK_INT >= 29) { + Window window = activity.getWindow(); + View view = window.getDecorView(); + view.setSystemGestureExclusionRects(rects); + + List resultingRects = view.getSystemGestureExclusionRects(); + Log.v("results", resultingRects.toString()); + } + } } From 5245ad3b0f7bd4806eef41a59ffb06198daa6bcf Mon Sep 17 00:00:00 2001 From: Shi Hao Hong Date: Mon, 26 Aug 2019 09:56:30 -0700 Subject: [PATCH 02/17] SystemGesture.setSystemGestureExclusionRects --- .../systemchannels/PlatformChannel.java | 38 +++++++------------ 1 file changed, 14 insertions(+), 24 deletions(-) diff --git a/shell/platform/android/io/flutter/embedding/engine/systemchannels/PlatformChannel.java b/shell/platform/android/io/flutter/embedding/engine/systemchannels/PlatformChannel.java index 13c4cc961c8f4..d76c5e05a6b34 100644 --- a/shell/platform/android/io/flutter/embedding/engine/systemchannels/PlatformChannel.java +++ b/shell/platform/android/io/flutter/embedding/engine/systemchannels/PlatformChannel.java @@ -121,13 +121,23 @@ public void onMethodCall(@NonNull MethodCall call, @NonNull MethodChannel.Result break; case "SystemGestures.setSystemGestureExclusionRects": if (arguments instanceof JSONArray) { - Log.v(TAG, "passed check"); JSONArray inputRects = (JSONArray) arguments; - Log.v(TAG, inputRects.getJSONObject(0).get("top").toString()); - ArrayList decodedRects = decodeRects(inputRects); + ArrayList decodedRects = new ArrayList(); + for (int i = 0; i < inputRects.length(); i++) { + JSONObject rect = inputRects.getJSONObject(i); + + int top = rect.getInt("top"); + int right = rect.getInt("right"); + int bottom = rect.getInt("bottom"); + int left = rect.getInt("left"); + + Rect gestureRect = new Rect(left, top, right, bottom); + decodedRects.add(gestureRect); + } + platformMessageHandler.setSystemGestureExclusionRects(decodedRects); result.success(null); } else { - String inputTypeError = "Input type is incorrect. Ensure that a List> is passed as the input."; + String inputTypeError = "Input type is incorrect. Ensure that a List> is passed as the input for SystemGestureExclusionRects.setSystemGestureExclusionRects."; result.error("inputTypeError", inputTypeError, null); } break; @@ -350,26 +360,6 @@ private SystemChromeStyle decodeSystemChromeStyle(@NonNull JSONObject encodedSty ); } - private ArrayList decodeRects(@NonNull JSONArray inputRects) { - ArrayList exclusionRects = new ArrayList(); - try { - for (int i = 0; i < inputRects.length(); i++) { - JSONObject rect = inputRects.getJSONObject(i); - - int top = rect.getInt("top"); - int right = rect.getInt("right"); - int bottom = rect.getInt("bottom"); - int left = rect.getInt("left"); - - Rect gestureRect = new Rect(left, top, right, bottom); - exclusionRects.add(gestureRect); - } - } catch (JSONException e) { - //some exception handler code. - } - return exclusionRects; - } - /** * Handler that receives platform messages sent from Flutter to Android * through a given {@link PlatformChannel}. From b37fa16ccd802d4496bd0ead7df7497b6efc61bf Mon Sep 17 00:00:00 2001 From: Shi Hao Hong Date: Mon, 26 Aug 2019 09:59:03 -0700 Subject: [PATCH 03/17] Cleanup Log.v and unnecessary imports --- .../embedding/engine/systemchannels/PlatformChannel.java | 2 -- .../android/io/flutter/plugin/platform/PlatformPlugin.java | 6 ------ 2 files changed, 8 deletions(-) diff --git a/shell/platform/android/io/flutter/embedding/engine/systemchannels/PlatformChannel.java b/shell/platform/android/io/flutter/embedding/engine/systemchannels/PlatformChannel.java index d76c5e05a6b34..ae475c0b5ab13 100644 --- a/shell/platform/android/io/flutter/embedding/engine/systemchannels/PlatformChannel.java +++ b/shell/platform/android/io/flutter/embedding/engine/systemchannels/PlatformChannel.java @@ -8,7 +8,6 @@ import android.graphics.Rect; import android.support.annotation.NonNull; import android.support.annotation.Nullable; -import android.util.Log; import org.json.JSONArray; import org.json.JSONException; @@ -45,7 +44,6 @@ public void onMethodCall(@NonNull MethodCall call, @NonNull MethodChannel.Result String method = call.method; Object arguments = call.arguments; - Log.v(TAG, "Received '" + method + "' message."); try { switch (method) { case "SystemSound.play": diff --git a/shell/platform/android/io/flutter/plugin/platform/PlatformPlugin.java b/shell/platform/android/io/flutter/plugin/platform/PlatformPlugin.java index b8f6639dd7067..222ef8bd4be28 100644 --- a/shell/platform/android/io/flutter/plugin/platform/PlatformPlugin.java +++ b/shell/platform/android/io/flutter/plugin/platform/PlatformPlugin.java @@ -22,8 +22,6 @@ import java.util.HashMap; import java.util.List; -import android.util.Log; - import io.flutter.embedding.engine.systemchannels.PlatformChannel; import io.flutter.plugin.common.ActivityLifecycleListener; @@ -92,7 +90,6 @@ public void setClipboardData(@NonNull String text) { @Override public void setSystemGestureExclusionRects(@NonNull ArrayList rects) { - Log.v("TAG", "WHAT IS THIS"); PlatformPlugin.this.setSystemGestureExclusionRects(rects); } }; @@ -289,9 +286,6 @@ private void setSystemGestureExclusionRects(ArrayList rects) { Window window = activity.getWindow(); View view = window.getDecorView(); view.setSystemGestureExclusionRects(rects); - - List resultingRects = view.getSystemGestureExclusionRects(); - Log.v("results", resultingRects.toString()); } } } From c155aec66be98cdf74d06054a796228c443bff3e Mon Sep 17 00:00:00 2001 From: Shi Hao Hong Date: Mon, 26 Aug 2019 10:00:40 -0700 Subject: [PATCH 04/17] Add Javadoc --- .../embedding/engine/systemchannels/PlatformChannel.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/shell/platform/android/io/flutter/embedding/engine/systemchannels/PlatformChannel.java b/shell/platform/android/io/flutter/embedding/engine/systemchannels/PlatformChannel.java index ae475c0b5ab13..e6fb20d628222 100644 --- a/shell/platform/android/io/flutter/embedding/engine/systemchannels/PlatformChannel.java +++ b/shell/platform/android/io/flutter/embedding/engine/systemchannels/PlatformChannel.java @@ -442,7 +442,10 @@ public interface PlatformMessageHandler { */ void setClipboardData(@NonNull String text); - /* TODO: Write docs */ + /** + * The Flutter application would like to set the system gesture exclusion + * rects through the given {@code rects}. + */ void setSystemGestureExclusionRects(@NonNull ArrayList rects); } From 53e858bd0d7f47d391c539a6b33504cd2595d459 Mon Sep 17 00:00:00 2001 From: Shi Hao Hong Date: Mon, 26 Aug 2019 11:37:04 -0700 Subject: [PATCH 05/17] Reinclude accidentally removed log --- .../embedding/engine/systemchannels/PlatformChannel.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/shell/platform/android/io/flutter/embedding/engine/systemchannels/PlatformChannel.java b/shell/platform/android/io/flutter/embedding/engine/systemchannels/PlatformChannel.java index e6fb20d628222..f237a720689f5 100644 --- a/shell/platform/android/io/flutter/embedding/engine/systemchannels/PlatformChannel.java +++ b/shell/platform/android/io/flutter/embedding/engine/systemchannels/PlatformChannel.java @@ -16,6 +16,7 @@ import java.util.ArrayList; import java.util.List; +import io.flutter.Log; import io.flutter.embedding.engine.dart.DartExecutor; import io.flutter.plugin.common.JSONMethodCodec; import io.flutter.plugin.common.MethodCall; @@ -44,6 +45,7 @@ public void onMethodCall(@NonNull MethodCall call, @NonNull MethodChannel.Result String method = call.method; Object arguments = call.arguments; + Log.v(TAG, "Received '" + method + "' message."); try { switch (method) { case "SystemSound.play": From 8dc864692705eca2c211b691fbb4d24e0bf2c153 Mon Sep 17 00:00:00 2001 From: Shi Hao Hong Date: Mon, 26 Aug 2019 14:36:54 -0700 Subject: [PATCH 06/17] Use guard clauses, refactor decodeRects to its own function --- .../systemchannels/PlatformChannel.java | 43 +++++++++++-------- .../plugin/platform/PlatformPlugin.java | 10 +++-- 2 files changed, 32 insertions(+), 21 deletions(-) diff --git a/shell/platform/android/io/flutter/embedding/engine/systemchannels/PlatformChannel.java b/shell/platform/android/io/flutter/embedding/engine/systemchannels/PlatformChannel.java index f237a720689f5..301a72fd749fc 100644 --- a/shell/platform/android/io/flutter/embedding/engine/systemchannels/PlatformChannel.java +++ b/shell/platform/android/io/flutter/embedding/engine/systemchannels/PlatformChannel.java @@ -120,26 +120,15 @@ public void onMethodCall(@NonNull MethodCall call, @NonNull MethodChannel.Result result.success(null); break; case "SystemGestures.setSystemGestureExclusionRects": - if (arguments instanceof JSONArray) { - JSONArray inputRects = (JSONArray) arguments; - ArrayList decodedRects = new ArrayList(); - for (int i = 0; i < inputRects.length(); i++) { - JSONObject rect = inputRects.getJSONObject(i); - - int top = rect.getInt("top"); - int right = rect.getInt("right"); - int bottom = rect.getInt("bottom"); - int left = rect.getInt("left"); - - Rect gestureRect = new Rect(left, top, right, bottom); - decodedRects.add(gestureRect); - } - platformMessageHandler.setSystemGestureExclusionRects(decodedRects); - result.success(null); - } else { + if (!(arguments instanceof JSONArray)) { String inputTypeError = "Input type is incorrect. Ensure that a List> is passed as the input for SystemGestureExclusionRects.setSystemGestureExclusionRects."; result.error("inputTypeError", inputTypeError, null); } + + JSONArray inputRects = (JSONArray) arguments; + ArrayList decodedRects = decodeRects(inputRects); + platformMessageHandler.setSystemGestureExclusionRects(decodedRects); + result.success(null); break; case "Clipboard.getData": { String contentFormatName = (String) arguments; @@ -280,6 +269,26 @@ private int decodeOrientations(@NonNull JSONArray encodedOrientations) throws JS return ActivityInfo.SCREEN_ORIENTATION_PORTRAIT; } + private ArrayList decodeRects(@NonNull JSONArray inputRects) { + ArrayList exclusionRects = new ArrayList(); + try { + for (int i = 0; i < inputRects.length(); i++) { + JSONObject rect = inputRects.getJSONObject(i); + + int top = rect.getInt("top"); + int right = rect.getInt("right"); + int bottom = rect.getInt("bottom"); + int left = rect.getInt("left"); + + Rect gestureRect = new Rect(left, top, right, bottom); + exclusionRects.add(gestureRect); + } + } catch (JSONException e) { + //some exception handler code. + } + return exclusionRects; + } + @NonNull private AppSwitcherDescription decodeAppSwitcherDescription(@NonNull JSONObject encodedDescription) throws JSONException { int color = encodedDescription.getInt("primaryColor"); diff --git a/shell/platform/android/io/flutter/plugin/platform/PlatformPlugin.java b/shell/platform/android/io/flutter/plugin/platform/PlatformPlugin.java index 222ef8bd4be28..7a9c9c8059867 100644 --- a/shell/platform/android/io/flutter/plugin/platform/PlatformPlugin.java +++ b/shell/platform/android/io/flutter/plugin/platform/PlatformPlugin.java @@ -282,10 +282,12 @@ private void setClipboardData(String text) { } private void setSystemGestureExclusionRects(ArrayList rects) { - if (Build.VERSION.SDK_INT >= 29) { - Window window = activity.getWindow(); - View view = window.getDecorView(); - view.setSystemGestureExclusionRects(rects); + if (Build.VERSION.SDK_INT < 29) { + return; } + + Window window = activity.getWindow(); + View view = window.getDecorView(); + view.setSystemGestureExclusionRects(rects); } } From e4dac7ce20ae4dc44cbb565888d87187bb29c9a3 Mon Sep 17 00:00:00 2001 From: Shi Hao Hong Date: Mon, 26 Aug 2019 14:38:36 -0700 Subject: [PATCH 07/17] Add missing return statement to guard clause --- .../flutter/embedding/engine/systemchannels/PlatformChannel.java | 1 + 1 file changed, 1 insertion(+) diff --git a/shell/platform/android/io/flutter/embedding/engine/systemchannels/PlatformChannel.java b/shell/platform/android/io/flutter/embedding/engine/systemchannels/PlatformChannel.java index 301a72fd749fc..d95f48f6a416d 100644 --- a/shell/platform/android/io/flutter/embedding/engine/systemchannels/PlatformChannel.java +++ b/shell/platform/android/io/flutter/embedding/engine/systemchannels/PlatformChannel.java @@ -123,6 +123,7 @@ public void onMethodCall(@NonNull MethodCall call, @NonNull MethodChannel.Result if (!(arguments instanceof JSONArray)) { String inputTypeError = "Input type is incorrect. Ensure that a List> is passed as the input for SystemGestureExclusionRects.setSystemGestureExclusionRects."; result.error("inputTypeError", inputTypeError, null); + return; } JSONArray inputRects = (JSONArray) arguments; From 3df584ba569c61bc52c7de1a2dc703a4d8e1782b Mon Sep 17 00:00:00 2001 From: Shi Hao Hong Date: Mon, 26 Aug 2019 14:39:14 -0700 Subject: [PATCH 08/17] Replace return with break statement --- .../embedding/engine/systemchannels/PlatformChannel.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shell/platform/android/io/flutter/embedding/engine/systemchannels/PlatformChannel.java b/shell/platform/android/io/flutter/embedding/engine/systemchannels/PlatformChannel.java index d95f48f6a416d..76faceb83679f 100644 --- a/shell/platform/android/io/flutter/embedding/engine/systemchannels/PlatformChannel.java +++ b/shell/platform/android/io/flutter/embedding/engine/systemchannels/PlatformChannel.java @@ -123,7 +123,7 @@ public void onMethodCall(@NonNull MethodCall call, @NonNull MethodChannel.Result if (!(arguments instanceof JSONArray)) { String inputTypeError = "Input type is incorrect. Ensure that a List> is passed as the input for SystemGestureExclusionRects.setSystemGestureExclusionRects."; result.error("inputTypeError", inputTypeError, null); - return; + break; } JSONArray inputRects = (JSONArray) arguments; From 676192e65b713b1942b68520737a11d264319f28 Mon Sep 17 00:00:00 2001 From: Shi Hao Hong Date: Mon, 26 Aug 2019 16:22:15 -0700 Subject: [PATCH 09/17] (WIP) - adding PlatformChannelTest.java systemGestureExclusionRects tests --- shell/platform/android/BUILD.gn | 1 + shell/platform/android/test/README.md | 4 +- .../test/io/flutter/FlutterTestSuite.java | 2 + .../systemchannels/PlatformChannelTest.java | 110 ++++++++++++++++++ 4 files changed, 115 insertions(+), 2 deletions(-) create mode 100644 shell/platform/android/test/io/flutter/embedding/engine/systemchannels/PlatformChannelTest.java diff --git a/shell/platform/android/BUILD.gn b/shell/platform/android/BUILD.gn index 3d07b6a2cf58d..37f2ea049fc36 100644 --- a/shell/platform/android/BUILD.gn +++ b/shell/platform/android/BUILD.gn @@ -407,6 +407,7 @@ action("robolectric_tests") { "test/io/flutter/embedding/android/FlutterFragmentTest.java", "test/io/flutter/embedding/engine/FlutterEngineCacheTest.java", "test/io/flutter/embedding/engine/systemchannels/TextInputChannelTest.java", + "test/io/flutter/embedding/engine/systemchannels/PlatformChannelTest.java", "test/io/flutter/util/PreconditionsTest.java", ] diff --git a/shell/platform/android/test/README.md b/shell/platform/android/test/README.md index 8d72cef9396ff..88f7fc5c59d33 100644 --- a/shell/platform/android/test/README.md +++ b/shell/platform/android/test/README.md @@ -18,7 +18,7 @@ integration tests in other repos. 3. Add your class to the `@SuiteClasses` annotation in `FlutterTestSuite.java`. This makes sure the test is actually executed at run time. 4. Write your test. -5. Build and run with `testing/run_tests.py [--type=java] [filter=]`. +5. Build and run with `testing/run_tests.py [--type=java] [--java-filter=]`. ## Q&A @@ -84,7 +84,7 @@ Tags: robolectric_version: ``` -Then update the `DEPS` file (located at /src/flutter/DEPS) to use the new version by pointing to +Then update the `DEPS` file (located at /src/flutter/DEPS) to use the new version by pointing to your new `last_updated_at` tag. ``` diff --git a/shell/platform/android/test/io/flutter/FlutterTestSuite.java b/shell/platform/android/test/io/flutter/FlutterTestSuite.java index 6c95754ccb402..ffc41acac88d5 100644 --- a/shell/platform/android/test/io/flutter/FlutterTestSuite.java +++ b/shell/platform/android/test/io/flutter/FlutterTestSuite.java @@ -13,6 +13,7 @@ import io.flutter.embedding.android.FlutterFragmentTest; import io.flutter.embedding.engine.FlutterEngineCacheTest; import io.flutter.embedding.engine.systemchannels.TextInputChannelTest; +import io.flutter.embedding.engine.systemchannels.PlatformChannelTest; import io.flutter.util.PreconditionsTest; @RunWith(Suite.class) @@ -23,6 +24,7 @@ FlutterFragmentTest.class, // FlutterActivityAndFragmentDelegateTest.class, TODO(mklim): Fix and re-enable this FlutterEngineCacheTest.class, + PlatformChannelTest.class, TextInputChannelTest.class }) /** Runs all of the unit tests listed in the {@code @SuiteClasses} annotation. */ diff --git a/shell/platform/android/test/io/flutter/embedding/engine/systemchannels/PlatformChannelTest.java b/shell/platform/android/test/io/flutter/embedding/engine/systemchannels/PlatformChannelTest.java new file mode 100644 index 0000000000000..821e2559c251f --- /dev/null +++ b/shell/platform/android/test/io/flutter/embedding/engine/systemchannels/PlatformChannelTest.java @@ -0,0 +1,110 @@ +package io.flutter.embedding.engine.systemchannels; + +import org.hamcrest.Description; +import org.json.JSONArray; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentMatcher; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.annotation.Config; + +import java.nio.ByteBuffer; + +import io.flutter.embedding.engine.dart.DartExecutor; +import io.flutter.embedding.engine.systemchannels.PlatformChannel; +import io.flutter.plugin.common.MethodChannel.Result; +import io.flutter.plugin.common.JSONMethodCodec; +import io.flutter.plugin.common.MethodCall; + +import static org.mockito.Matchers.argThat; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +@Config(manifest=Config.NONE) +@RunWith(RobolectricTestRunner.class) +public class PlatformChannelTest { + @Test + public void itSendsSuccessMessageToFramework() { + DartExecutor dartExecutor = mock(DartExecutor.class); + ResultsMock resultsMock = mock(ResultsMock.class); + + PlatformChannel platformChannel = new PlatformChannel(dartExecutor); + + // invoke method with correct arguments + JSONArray inputRects = new JSONArray(); + platformChannel.channel.invokeMethod("SystemGestures.setSystemGestureExclusionRects", inputRects, resultsMock); + + verify(dartExecutor, times(1)).send( + eq("flutter/platform"), + ByteBufferMatcher.eqByteBuffer(JSONMethodCodec.INSTANCE.encodeMethodCall( + new MethodCall( + "SystemGestures.setSystemGestureExclusionRects", + inputRects + ) + )), + // TODO (create incoming result callback handler -- see MethodChannel.java) + ); + } + + @Test + public void itRequiresJSONArrayInput() { + + } + + @Test + public void itSendsJSONExceptionOnIncorrectDataShape() { + + } + + /** + * Mockito matcher that compares two {@link ByteBuffer}s by resetting both buffers and then + * utilizing their standard {@code equals()} method. + *

+ * This matcher will change the state of the expected and actual buffers. The exact change in + * state depends on where the comparison fails or succeeds. + */ + static class ByteBufferMatcher extends ArgumentMatcher { + static ByteBuffer eqByteBuffer(ByteBuffer expected) { + return argThat(new ByteBufferMatcher(expected)); + } + + private ByteBuffer expected; + + ByteBufferMatcher(ByteBuffer expected) { + this.expected = expected; + } + + @Override + public boolean matches(Object argument) { + if (!(argument instanceof ByteBuffer)) { + return false; + } + + // Reset the buffers for content comparison. + ((ByteBuffer) argument).position(0); + expected.position(0); + + return expected.equals(argument); + } + + // Implemented so that during a failure the expected value is + // shown in logs, rather than the name of this class. + @Override + public void describeTo(Description description) { + description.appendText(expected.toString()); + } + } +} + +class ResultsMock implements Result { + @Override + public void success(Object result) {} + + @Override + public void error(String errorCode, String errorMessage, Object errorDetails) {} + + @Override + public void notImplemented() {} +} \ No newline at end of file From 21577fbd62b91ea51253b2c74088415ad4e9877d Mon Sep 17 00:00:00 2001 From: Shi Hao Hong Date: Tue, 27 Aug 2019 16:32:59 -0700 Subject: [PATCH 10/17] (WIP) - PlatformChannel exploration --- .../systemchannels/PlatformChannel.java | 4 +- .../flutter/plugin/common/MethodChannel.java | 1 + .../systemchannels/PlatformChannelTest.java | 77 ++++++++++++++----- 3 files changed, 60 insertions(+), 22 deletions(-) diff --git a/shell/platform/android/io/flutter/embedding/engine/systemchannels/PlatformChannel.java b/shell/platform/android/io/flutter/embedding/engine/systemchannels/PlatformChannel.java index 76faceb83679f..eee5d098df165 100644 --- a/shell/platform/android/io/flutter/embedding/engine/systemchannels/PlatformChannel.java +++ b/shell/platform/android/io/flutter/embedding/engine/systemchannels/PlatformChannel.java @@ -4,6 +4,7 @@ package io.flutter.embedding.engine.systemchannels; +import android.util.Log; import android.content.pm.ActivityInfo; import android.graphics.Rect; import android.support.annotation.NonNull; @@ -16,7 +17,7 @@ import java.util.ArrayList; import java.util.List; -import io.flutter.Log; +// import io.flutter.Log; import io.flutter.embedding.engine.dart.DartExecutor; import io.flutter.plugin.common.JSONMethodCodec; import io.flutter.plugin.common.MethodCall; @@ -37,6 +38,7 @@ public class PlatformChannel { private final MethodChannel.MethodCallHandler parsingMethodCallHandler = new MethodChannel.MethodCallHandler() { @Override public void onMethodCall(@NonNull MethodCall call, @NonNull MethodChannel.Result result) { + Log.v(TAG, "was called onMethodCall here"); if (platformMessageHandler == null) { // If no explicit PlatformMessageHandler has been registered then we don't // need to forward this call to an API. Return. diff --git a/shell/platform/android/io/flutter/plugin/common/MethodChannel.java b/shell/platform/android/io/flutter/plugin/common/MethodChannel.java index 8bab6098b0055..427ba6ecb7edf 100644 --- a/shell/platform/android/io/flutter/plugin/common/MethodChannel.java +++ b/shell/platform/android/io/flutter/plugin/common/MethodChannel.java @@ -81,6 +81,7 @@ public MethodChannel(BinaryMessenger messenger, String name, MethodCodec codec) */ @UiThread public void invokeMethod(@NonNull String method, @Nullable Object arguments) { + Log.v(TAG, "called here"); invokeMethod(method, arguments, null); } diff --git a/shell/platform/android/test/io/flutter/embedding/engine/systemchannels/PlatformChannelTest.java b/shell/platform/android/test/io/flutter/embedding/engine/systemchannels/PlatformChannelTest.java index 821e2559c251f..99414834e82c5 100644 --- a/shell/platform/android/test/io/flutter/embedding/engine/systemchannels/PlatformChannelTest.java +++ b/shell/platform/android/test/io/flutter/embedding/engine/systemchannels/PlatformChannelTest.java @@ -1,7 +1,10 @@ package io.flutter.embedding.engine.systemchannels; +import android.util.Log; + import org.hamcrest.Description; import org.json.JSONArray; +import org.json.JSONObject; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentMatcher; @@ -12,6 +15,7 @@ import io.flutter.embedding.engine.dart.DartExecutor; import io.flutter.embedding.engine.systemchannels.PlatformChannel; +import io.flutter.embedding.engine.systemchannels.PlatformChannel.PlatformMessageHandler; import io.flutter.plugin.common.MethodChannel.Result; import io.flutter.plugin.common.JSONMethodCodec; import io.flutter.plugin.common.MethodCall; @@ -25,38 +29,69 @@ @Config(manifest=Config.NONE) @RunWith(RobolectricTestRunner.class) public class PlatformChannelTest { + // @Test + // public void itSendsSuccessMessageToFramework() { + // DartExecutor dartExecutor = mock(DartExecutor.class); + // ResultsMock resultsMock = mock(ResultsMock.class); + + // PlatformChannel platformChannel = new PlatformChannel(dartExecutor); + + // // invoke method with correct arguments + // JSONArray inputRects = new JSONArray(); + // platformChannel.channel.invokeMethod("SystemGestures.setSystemGestureExclusionRects", inputRects, resultsMock); + + // // verify(dartExecutor, times(1)).send( + // // eq("flutter/platform"), + // // ByteBufferMatcher.eqByteBuffer(JSONMethodCodec.INSTANCE.encodeMethodCall( + // // new MethodCall( + // // "SystemGestures.setSystemGestureExclusionRects", + // // inputRects + // // ) + // // )), + + // // // TODO (create incoming result callback handler -- see MethodChannel.java) + // // ); + // } + @Test - public void itSendsSuccessMessageToFramework() { + public void itRequiresJSONArrayInput() { DartExecutor dartExecutor = mock(DartExecutor.class); ResultsMock resultsMock = mock(ResultsMock.class); + PlatformMessageHandler platformMessageHandler = mock(PlatformMessageHandler.class); PlatformChannel platformChannel = new PlatformChannel(dartExecutor); + platformChannel.setPlatformMessageHandler(platformMessageHandler); - // invoke method with correct arguments - JSONArray inputRects = new JSONArray(); + // invoke method with incorrect shape + JSONObject inputRects = new JSONObject(); platformChannel.channel.invokeMethod("SystemGestures.setSystemGestureExclusionRects", inputRects, resultsMock); - verify(dartExecutor, times(1)).send( - eq("flutter/platform"), - ByteBufferMatcher.eqByteBuffer(JSONMethodCodec.INSTANCE.encodeMethodCall( - new MethodCall( - "SystemGestures.setSystemGestureExclusionRects", - inputRects - ) - )), - // TODO (create incoming result callback handler -- see MethodChannel.java) - ); - } - - @Test - public void itRequiresJSONArrayInput() { - + Log.v("test", "got to this point"); + + // verify(dartExecutor, times(1)).send( + // eq("flutter/platform"), + // ByteBufferMatcher.eqByteBuffer(JSONMethodCodec.INSTANCE.encodeMethodCall( + // new MethodCall( + // "SystemGestures.setSystemGestureExclusionRects", + // inputRects + // ) + // )), + // eq(null) + // ); + + // verify(platformChannel.channel, times(1)).send(); + // String inputTypeError = "Input type is incorrect. Ensure that a List> is passed as the input for SystemGestureExclusionRects.setSystemGestureExclusionRects."; + // verify(resultsMock, times(1)).error( + // "inputTypeError", + // inputTypeError, + // null + // ); } - @Test - public void itSendsJSONExceptionOnIncorrectDataShape() { + // @Test + // public void itSendsJSONExceptionOnIncorrectDataShape() { - } + // } /** * Mockito matcher that compares two {@link ByteBuffer}s by resetting both buffers and then From 87ddf16a8617e84f18c4bbc15faea0b9913294de Mon Sep 17 00:00:00 2001 From: Shi Hao Hong Date: Thu, 29 Aug 2019 11:35:25 -0700 Subject: [PATCH 11/17] (WIP) - Added first happy path test for systemGestureExclusionRects platform channel --- .../systemchannels/PlatformChannel.java | 279 +++++++++--------- .../systemchannels/PlatformChannelTest.java | 80 +++-- 2 files changed, 191 insertions(+), 168 deletions(-) diff --git a/shell/platform/android/io/flutter/embedding/engine/systemchannels/PlatformChannel.java b/shell/platform/android/io/flutter/embedding/engine/systemchannels/PlatformChannel.java index eee5d098df165..d97a0372c81ff 100644 --- a/shell/platform/android/io/flutter/embedding/engine/systemchannels/PlatformChannel.java +++ b/shell/platform/android/io/flutter/embedding/engine/systemchannels/PlatformChannel.java @@ -9,6 +9,7 @@ import android.graphics.Rect; import android.support.annotation.NonNull; import android.support.annotation.Nullable; +import android.support.annotation.VisibleForTesting; import org.json.JSONArray; import org.json.JSONException; @@ -34,142 +35,9 @@ public class PlatformChannel { public final MethodChannel channel; @Nullable private PlatformMessageHandler platformMessageHandler; - - private final MethodChannel.MethodCallHandler parsingMethodCallHandler = new MethodChannel.MethodCallHandler() { - @Override - public void onMethodCall(@NonNull MethodCall call, @NonNull MethodChannel.Result result) { - Log.v(TAG, "was called onMethodCall here"); - if (platformMessageHandler == null) { - // If no explicit PlatformMessageHandler has been registered then we don't - // need to forward this call to an API. Return. - return; - } - - String method = call.method; - Object arguments = call.arguments; - Log.v(TAG, "Received '" + method + "' message."); - try { - switch (method) { - case "SystemSound.play": - try { - SoundType soundType = SoundType.fromValue((String) arguments); - platformMessageHandler.playSystemSound(soundType); - result.success(null); - } catch (NoSuchFieldException exception) { - // The desired sound type does not exist. - result.error("error", exception.getMessage(), null); - } - break; - case "HapticFeedback.vibrate": - try { - HapticFeedbackType feedbackType = HapticFeedbackType.fromValue((String) arguments); - platformMessageHandler.vibrateHapticFeedback(feedbackType); - result.success(null); - } catch (NoSuchFieldException exception) { - // The desired feedback type does not exist. - result.error("error", exception.getMessage(), null); - } - break; - case "SystemChrome.setPreferredOrientations": - try { - int androidOrientation = decodeOrientations((JSONArray) arguments); - platformMessageHandler.setPreferredOrientations(androidOrientation); - result.success(null); - } catch (JSONException | NoSuchFieldException exception) { - // JSONException: One or more expected fields were either omitted or referenced an invalid type. - // NoSuchFieldException: One or more expected fields were either omitted or referenced an invalid type. - result.error("error", exception.getMessage(), null); - } - break; - case "SystemChrome.setApplicationSwitcherDescription": - try { - AppSwitcherDescription description = decodeAppSwitcherDescription((JSONObject) arguments); - platformMessageHandler.setApplicationSwitcherDescription(description); - result.success(null); - } catch (JSONException exception) { - // One or more expected fields were either omitted or referenced an invalid type. - result.error("error", exception.getMessage(), null); - } - break; - case "SystemChrome.setEnabledSystemUIOverlays": - try { - List overlays = decodeSystemUiOverlays((JSONArray) arguments); - platformMessageHandler.showSystemOverlays(overlays); - result.success(null); - } catch (JSONException | NoSuchFieldException exception) { - // JSONException: One or more expected fields were either omitted or referenced an invalid type. - // NoSuchFieldException: One or more of the overlay names are invalid. - result.error("error", exception.getMessage(), null); - } - break; - case "SystemChrome.restoreSystemUIOverlays": - platformMessageHandler.restoreSystemUiOverlays(); - result.success(null); - break; - case "SystemChrome.setSystemUIOverlayStyle": - try { - SystemChromeStyle systemChromeStyle = decodeSystemChromeStyle((JSONObject) arguments); - platformMessageHandler.setSystemUiOverlayStyle(systemChromeStyle); - result.success(null); - } catch (JSONException | NoSuchFieldException exception) { - // JSONException: One or more expected fields were either omitted or referenced an invalid type. - // NoSuchFieldException: One or more of the brightness names are invalid. - result.error("error", exception.getMessage(), null); - } - break; - case "SystemNavigator.pop": - platformMessageHandler.popSystemNavigator(); - result.success(null); - break; - case "SystemGestures.setSystemGestureExclusionRects": - if (!(arguments instanceof JSONArray)) { - String inputTypeError = "Input type is incorrect. Ensure that a List> is passed as the input for SystemGestureExclusionRects.setSystemGestureExclusionRects."; - result.error("inputTypeError", inputTypeError, null); - break; - } - - JSONArray inputRects = (JSONArray) arguments; - ArrayList decodedRects = decodeRects(inputRects); - platformMessageHandler.setSystemGestureExclusionRects(decodedRects); - result.success(null); - break; - case "Clipboard.getData": { - String contentFormatName = (String) arguments; - ClipboardContentFormat clipboardFormat = null; - if (contentFormatName != null) { - try { - clipboardFormat = ClipboardContentFormat.fromValue(contentFormatName); - } catch (NoSuchFieldException exception) { - // An unsupported content format was requested. Return failure. - result.error("error", "No such clipboard content format: " + contentFormatName, null); - } - } - - CharSequence clipboardContent = platformMessageHandler.getClipboardData(clipboardFormat); - if (clipboardContent != null) { - JSONObject response = new JSONObject(); - response.put("text", clipboardContent); - result.success(response); - } else { - result.success(null); - } - break; - } - case "Clipboard.setData": { - String clipboardContent = ((JSONObject) arguments).getString("text"); - platformMessageHandler.setClipboardData(clipboardContent); - result.success(null); - break; - } - default: - result.notImplemented(); - break; - } - } catch (JSONException e) { - result.error("error", "JSON error: " + e.getMessage(), null); - } - } - }; + @NonNull + @VisibleForTesting + protected final PlatformMethodCallHandler parsingMethodCallHandler = new PlatformMethodCallHandler(); /** * Constructs a {@code PlatformChannel} that connects Android to the Dart code @@ -622,6 +490,145 @@ public SystemChromeStyle( } } + // TODO(shihaohong): Add docs to describe what this is used for + @VisibleForTesting + protected class PlatformMethodCallHandler implements MethodChannel.MethodCallHandler { + @Override + public void onMethodCall(@NonNull MethodCall call, @NonNull MethodChannel.Result result) { + Log.v(TAG, "was called onMethodCall here" + call.method); + if (platformMessageHandler == null) { + // If no explicit PlatformMessageHandler has been registered then we don't + // need to forward this call to an API. Return. + return; + } + + String method = call.method; + Object arguments = call.arguments; + Log.v(TAG, "Received '" + method + "' message."); + try { + switch (method) { + case "SystemSound.play": + try { + SoundType soundType = SoundType.fromValue((String) arguments); + platformMessageHandler.playSystemSound(soundType); + result.success(null); + } catch (NoSuchFieldException exception) { + // The desired sound type does not exist. + result.error("error", exception.getMessage(), null); + } + break; + case "HapticFeedback.vibrate": + try { + HapticFeedbackType feedbackType = HapticFeedbackType.fromValue((String) arguments); + platformMessageHandler.vibrateHapticFeedback(feedbackType); + result.success(null); + } catch (NoSuchFieldException exception) { + // The desired feedback type does not exist. + result.error("error", exception.getMessage(), null); + } + break; + case "SystemChrome.setPreferredOrientations": + try { + int androidOrientation = decodeOrientations((JSONArray) arguments); + platformMessageHandler.setPreferredOrientations(androidOrientation); + result.success(null); + } catch (JSONException | NoSuchFieldException exception) { + // JSONException: One or more expected fields were either omitted or referenced an invalid type. + // NoSuchFieldException: One or more expected fields were either omitted or referenced an invalid type. + result.error("error", exception.getMessage(), null); + } + break; + case "SystemChrome.setApplicationSwitcherDescription": + try { + AppSwitcherDescription description = decodeAppSwitcherDescription((JSONObject) arguments); + platformMessageHandler.setApplicationSwitcherDescription(description); + result.success(null); + } catch (JSONException exception) { + // One or more expected fields were either omitted or referenced an invalid type. + result.error("error", exception.getMessage(), null); + } + break; + case "SystemChrome.setEnabledSystemUIOverlays": + try { + List overlays = decodeSystemUiOverlays((JSONArray) arguments); + platformMessageHandler.showSystemOverlays(overlays); + result.success(null); + } catch (JSONException | NoSuchFieldException exception) { + // JSONException: One or more expected fields were either omitted or referenced an invalid type. + // NoSuchFieldException: One or more of the overlay names are invalid. + result.error("error", exception.getMessage(), null); + } + break; + case "SystemChrome.restoreSystemUIOverlays": + platformMessageHandler.restoreSystemUiOverlays(); + result.success(null); + break; + case "SystemChrome.setSystemUIOverlayStyle": + try { + SystemChromeStyle systemChromeStyle = decodeSystemChromeStyle((JSONObject) arguments); + platformMessageHandler.setSystemUiOverlayStyle(systemChromeStyle); + result.success(null); + } catch (JSONException | NoSuchFieldException exception) { + // JSONException: One or more expected fields were either omitted or referenced an invalid type. + // NoSuchFieldException: One or more of the brightness names are invalid. + result.error("error", exception.getMessage(), null); + } + break; + case "SystemNavigator.pop": + platformMessageHandler.popSystemNavigator(); + result.success(null); + break; + case "SystemGestures.setSystemGestureExclusionRects": + if (!(arguments instanceof JSONArray)) { + String inputTypeError = "Input type is incorrect. Ensure that a List> is passed as the input for SystemGestureExclusionRects.setSystemGestureExclusionRects."; + result.error("inputTypeError", inputTypeError, null); + break; + } + + Log.v("Got here", arguments.toString()); + JSONArray inputRects = (JSONArray) arguments; + ArrayList decodedRects = decodeRects(inputRects); + platformMessageHandler.setSystemGestureExclusionRects(decodedRects); + result.success(null); + break; + case "Clipboard.getData": { + String contentFormatName = (String) arguments; + ClipboardContentFormat clipboardFormat = null; + if (contentFormatName != null) { + try { + clipboardFormat = ClipboardContentFormat.fromValue(contentFormatName); + } catch (NoSuchFieldException exception) { + // An unsupported content format was requested. Return failure. + result.error("error", "No such clipboard content format: " + contentFormatName, null); + } + } + + CharSequence clipboardContent = platformMessageHandler.getClipboardData(clipboardFormat); + if (clipboardContent != null) { + JSONObject response = new JSONObject(); + response.put("text", clipboardContent); + result.success(response); + } else { + result.success(null); + } + break; + } + case "Clipboard.setData": { + String clipboardContent = ((JSONObject) arguments).getString("text"); + platformMessageHandler.setClipboardData(clipboardContent); + result.success(null); + break; + } + default: + result.notImplemented(); + break; + } + } catch (JSONException e) { + result.error("error", "JSON error: " + e.getMessage(), null); + } + } + } + public enum Brightness { LIGHT("Brightness.light"), DARK("Brightness.dark"); diff --git a/shell/platform/android/test/io/flutter/embedding/engine/systemchannels/PlatformChannelTest.java b/shell/platform/android/test/io/flutter/embedding/engine/systemchannels/PlatformChannelTest.java index 99414834e82c5..34532e8cf2989 100644 --- a/shell/platform/android/test/io/flutter/embedding/engine/systemchannels/PlatformChannelTest.java +++ b/shell/platform/android/test/io/flutter/embedding/engine/systemchannels/PlatformChannelTest.java @@ -1,9 +1,11 @@ package io.flutter.embedding.engine.systemchannels; +import android.graphics.Rect; import android.util.Log; import org.hamcrest.Description; import org.json.JSONArray; +import org.json.JSONException; import org.json.JSONObject; import org.junit.Test; import org.junit.runner.RunWith; @@ -12,6 +14,7 @@ import org.robolectric.annotation.Config; import java.nio.ByteBuffer; +import java.util.ArrayList; import io.flutter.embedding.engine.dart.DartExecutor; import io.flutter.embedding.engine.systemchannels.PlatformChannel; @@ -29,44 +32,57 @@ @Config(manifest=Config.NONE) @RunWith(RobolectricTestRunner.class) public class PlatformChannelTest { - // @Test - // public void itSendsSuccessMessageToFramework() { - // DartExecutor dartExecutor = mock(DartExecutor.class); - // ResultsMock resultsMock = mock(ResultsMock.class); - - // PlatformChannel platformChannel = new PlatformChannel(dartExecutor); - - // // invoke method with correct arguments - // JSONArray inputRects = new JSONArray(); - // platformChannel.channel.invokeMethod("SystemGestures.setSystemGestureExclusionRects", inputRects, resultsMock); - - // // verify(dartExecutor, times(1)).send( - // // eq("flutter/platform"), - // // ByteBufferMatcher.eqByteBuffer(JSONMethodCodec.INSTANCE.encodeMethodCall( - // // new MethodCall( - // // "SystemGestures.setSystemGestureExclusionRects", - // // inputRects - // // ) - // // )), - - // // // TODO (create incoming result callback handler -- see MethodChannel.java) - // // ); - // } - @Test - public void itRequiresJSONArrayInput() { + public void itSendsSuccessMessageToFramework() throws JSONException { + Log.v("TAG", "testing here"); DartExecutor dartExecutor = mock(DartExecutor.class); - ResultsMock resultsMock = mock(ResultsMock.class); - PlatformMessageHandler platformMessageHandler = mock(PlatformMessageHandler.class); - PlatformChannel platformChannel = new PlatformChannel(dartExecutor); + PlatformMessageHandler platformMessageHandler = mock(PlatformMessageHandler.class); platformChannel.setPlatformMessageHandler(platformMessageHandler); - // invoke method with incorrect shape - JSONObject inputRects = new JSONObject(); - platformChannel.channel.invokeMethod("SystemGestures.setSystemGestureExclusionRects", inputRects, resultsMock); + int top = 0; + int right = 500; + int bottom = 250; + int left = 0; + + ResultsMock resultsMock = mock(ResultsMock.class); + JSONObject JsonRect = new JSONObject(); + + JsonRect.put("top", top); + JsonRect.put("right", right); + JsonRect.put("bottom", bottom); + JsonRect.put("left", left); + + JSONArray inputRects = new JSONArray(); + inputRects.put(JsonRect); + + ArrayList expectedDecodedRects = new ArrayList(); + Rect gestureRect = new Rect(left, top, right, bottom); + expectedDecodedRects.add(gestureRect); + + MethodCall callSystemGestureExclusionRects = new MethodCall( + "SystemGestures.setSystemGestureExclusionRects", + inputRects + ); + + platformChannel.parsingMethodCallHandler.onMethodCall(callSystemGestureExclusionRects, resultsMock); + verify(platformMessageHandler, times(1)).setSystemGestureExclusionRects(expectedDecodedRects); + verify(resultsMock, times(1)).success(null); + } + + @Test + public void itRequiresJSONArrayInput() { + // DartExecutor dartExecutor = mock(DartExecutor.class); + + + // PlatformChannel platformChannel = new PlatformChannel(dartExecutor); + // platformChannel.setPlatformMessageHandler(platformMessageHandler); + + // // invoke method with incorrect shape + // JSONObject inputRects = new JSONObject(); + // platformChannel.channel.invokeMethod("SystemGestures.setSystemGestureExclusionRects", inputRects, resultsMock); - Log.v("test", "got to this point"); + // Log.v("test", "got to this point"); // verify(dartExecutor, times(1)).send( // eq("flutter/platform"), From 13617ee4e884f9c7dbebb23f8ad408192eec8374 Mon Sep 17 00:00:00 2001 From: Shi Hao Hong Date: Thu, 29 Aug 2019 12:42:32 -0700 Subject: [PATCH 12/17] Added unit tests for setSystemGestureInsets platform channel --- .../systemchannels/PlatformChannel.java | 37 ++--- .../systemchannels/PlatformChannelTest.java | 126 +++++++----------- 2 files changed, 73 insertions(+), 90 deletions(-) diff --git a/shell/platform/android/io/flutter/embedding/engine/systemchannels/PlatformChannel.java b/shell/platform/android/io/flutter/embedding/engine/systemchannels/PlatformChannel.java index d97a0372c81ff..97a7da24c9e77 100644 --- a/shell/platform/android/io/flutter/embedding/engine/systemchannels/PlatformChannel.java +++ b/shell/platform/android/io/flutter/embedding/engine/systemchannels/PlatformChannel.java @@ -4,7 +4,6 @@ package io.flutter.embedding.engine.systemchannels; -import android.util.Log; import android.content.pm.ActivityInfo; import android.graphics.Rect; import android.support.annotation.NonNull; @@ -18,7 +17,7 @@ import java.util.ArrayList; import java.util.List; -// import io.flutter.Log; +import io.flutter.Log; import io.flutter.embedding.engine.dart.DartExecutor; import io.flutter.plugin.common.JSONMethodCodec; import io.flutter.plugin.common.MethodCall; @@ -140,23 +139,31 @@ private int decodeOrientations(@NonNull JSONArray encodedOrientations) throws JS return ActivityInfo.SCREEN_ORIENTATION_PORTRAIT; } - private ArrayList decodeRects(@NonNull JSONArray inputRects) { + private ArrayList decodeRects(@NonNull JSONArray inputRects) throws JSONException { ArrayList exclusionRects = new ArrayList(); - try { - for (int i = 0; i < inputRects.length(); i++) { - JSONObject rect = inputRects.getJSONObject(i); + for (int i = 0; i < inputRects.length(); i++) { + JSONObject rect = inputRects.getJSONObject(i); + int top; + int right; + int bottom; + int left; - int top = rect.getInt("top"); - int right = rect.getInt("right"); - int bottom = rect.getInt("bottom"); - int left = rect.getInt("left"); - - Rect gestureRect = new Rect(left, top, right, bottom); - exclusionRects.add(gestureRect); + try { + top = rect.getInt("top"); + right = rect.getInt("right"); + bottom = rect.getInt("bottom"); + left = rect.getInt("left"); + } catch (JSONException exception) { + throw new JSONException( + "Incorrect JSON data shape. To set system gesture exclusion rects, \n" + + "a JSONObject with top, right, bottom and left values need to be set to int values." + ); } - } catch (JSONException e) { - //some exception handler code. + + Rect gestureRect = new Rect(left, top, right, bottom); + exclusionRects.add(gestureRect); } + return exclusionRects; } diff --git a/shell/platform/android/test/io/flutter/embedding/engine/systemchannels/PlatformChannelTest.java b/shell/platform/android/test/io/flutter/embedding/engine/systemchannels/PlatformChannelTest.java index 34532e8cf2989..3d7ef656361ea 100644 --- a/shell/platform/android/test/io/flutter/embedding/engine/systemchannels/PlatformChannelTest.java +++ b/shell/platform/android/test/io/flutter/embedding/engine/systemchannels/PlatformChannelTest.java @@ -34,7 +34,6 @@ public class PlatformChannelTest { @Test public void itSendsSuccessMessageToFramework() throws JSONException { - Log.v("TAG", "testing here"); DartExecutor dartExecutor = mock(DartExecutor.class); PlatformChannel platformChannel = new PlatformChannel(dartExecutor); PlatformMessageHandler platformMessageHandler = mock(PlatformMessageHandler.class); @@ -46,6 +45,7 @@ public void itSendsSuccessMessageToFramework() throws JSONException { int left = 0; ResultsMock resultsMock = mock(ResultsMock.class); + JSONObject JsonRect = new JSONObject(); JsonRect.put("top", top); @@ -72,90 +72,66 @@ public void itSendsSuccessMessageToFramework() throws JSONException { @Test public void itRequiresJSONArrayInput() { - // DartExecutor dartExecutor = mock(DartExecutor.class); - - - // PlatformChannel platformChannel = new PlatformChannel(dartExecutor); - // platformChannel.setPlatformMessageHandler(platformMessageHandler); - - // // invoke method with incorrect shape - // JSONObject inputRects = new JSONObject(); - // platformChannel.channel.invokeMethod("SystemGestures.setSystemGestureExclusionRects", inputRects, resultsMock); - - // Log.v("test", "got to this point"); - - // verify(dartExecutor, times(1)).send( - // eq("flutter/platform"), - // ByteBufferMatcher.eqByteBuffer(JSONMethodCodec.INSTANCE.encodeMethodCall( - // new MethodCall( - // "SystemGestures.setSystemGestureExclusionRects", - // inputRects - // ) - // )), - // eq(null) - // ); - - // verify(platformChannel.channel, times(1)).send(); - // String inputTypeError = "Input type is incorrect. Ensure that a List> is passed as the input for SystemGestureExclusionRects.setSystemGestureExclusionRects."; - // verify(resultsMock, times(1)).error( - // "inputTypeError", - // inputTypeError, - // null - // ); + DartExecutor dartExecutor = mock(DartExecutor.class); + PlatformChannel platformChannel = new PlatformChannel(dartExecutor); + PlatformMessageHandler platformMessageHandler = mock(PlatformMessageHandler.class); + platformChannel.setPlatformMessageHandler(platformMessageHandler); + + ResultsMock resultsMock = mock(ResultsMock.class); + String nonJsonInput = "Non-JSON"; + MethodCall callSystemGestureExclusionRects = new MethodCall( + "SystemGestures.setSystemGestureExclusionRects", + nonJsonInput + ); + platformChannel.parsingMethodCallHandler.onMethodCall(callSystemGestureExclusionRects, resultsMock); + + String inputTypeError = "Input type is incorrect. Ensure that a List> is passed as the input for SystemGestureExclusionRects.setSystemGestureExclusionRects."; + verify(resultsMock, times(1)).error( + "inputTypeError", + inputTypeError, + null + ); } - // @Test - // public void itSendsJSONExceptionOnIncorrectDataShape() { + @Test + public void itSendsJSONExceptionOnIncorrectDataShape() throws JSONException { + DartExecutor dartExecutor = mock(DartExecutor.class); + PlatformChannel platformChannel = new PlatformChannel(dartExecutor); + PlatformMessageHandler platformMessageHandler = mock(PlatformMessageHandler.class); + platformChannel.setPlatformMessageHandler(platformMessageHandler); - // } + int top = 0; + int right = 500; - /** - * Mockito matcher that compares two {@link ByteBuffer}s by resetting both buffers and then - * utilizing their standard {@code equals()} method. - *

- * This matcher will change the state of the expected and actual buffers. The exact change in - * state depends on where the comparison fails or succeeds. - */ - static class ByteBufferMatcher extends ArgumentMatcher { - static ByteBuffer eqByteBuffer(ByteBuffer expected) { - return argThat(new ByteBufferMatcher(expected)); - } + ResultsMock resultsMock = mock(ResultsMock.class); + JSONObject jsonObject = new JSONObject(); + jsonObject.put("arg1", top); + jsonObject.put("arg2", right); + JSONArray inputArray = new JSONArray(); + inputArray.put(jsonObject); - private ByteBuffer expected; + MethodCall callSystemGestureExclusionRects = new MethodCall( + "SystemGestures.setSystemGestureExclusionRects", + inputArray + ); - ByteBufferMatcher(ByteBuffer expected) { - this.expected = expected; - } + platformChannel.parsingMethodCallHandler.onMethodCall(callSystemGestureExclusionRects, resultsMock); + verify(resultsMock, times(1)).error( + "error", + "JSON error: Incorrect JSON data shape. To set system gesture exclusion rects, \n" + + "a JSONObject with top, right, bottom and left values need to be set to int values.", + null + ); + } + private class ResultsMock implements Result { @Override - public boolean matches(Object argument) { - if (!(argument instanceof ByteBuffer)) { - return false; - } - - // Reset the buffers for content comparison. - ((ByteBuffer) argument).position(0); - expected.position(0); + public void success(Object result) {} - return expected.equals(argument); - } + @Override + public void error(String errorCode, String errorMessage, Object errorDetails) {} - // Implemented so that during a failure the expected value is - // shown in logs, rather than the name of this class. @Override - public void describeTo(Description description) { - description.appendText(expected.toString()); - } + public void notImplemented() {} } } - -class ResultsMock implements Result { - @Override - public void success(Object result) {} - - @Override - public void error(String errorCode, String errorMessage, Object errorDetails) {} - - @Override - public void notImplemented() {} -} \ No newline at end of file From cdd4e6adcf187ffcbcf6e896cae44a4b31dabc86 Mon Sep 17 00:00:00 2001 From: Shi Hao Hong Date: Thu, 29 Aug 2019 12:47:00 -0700 Subject: [PATCH 13/17] Code clean-up --- .../flutter/plugin/common/MethodChannel.java | 1 - .../systemchannels/PlatformChannelTest.java | 23 +++++++------------ 2 files changed, 8 insertions(+), 16 deletions(-) diff --git a/shell/platform/android/io/flutter/plugin/common/MethodChannel.java b/shell/platform/android/io/flutter/plugin/common/MethodChannel.java index 427ba6ecb7edf..8bab6098b0055 100644 --- a/shell/platform/android/io/flutter/plugin/common/MethodChannel.java +++ b/shell/platform/android/io/flutter/plugin/common/MethodChannel.java @@ -81,7 +81,6 @@ public MethodChannel(BinaryMessenger messenger, String name, MethodCodec codec) */ @UiThread public void invokeMethod(@NonNull String method, @Nullable Object arguments) { - Log.v(TAG, "called here"); invokeMethod(method, arguments, null); } diff --git a/shell/platform/android/test/io/flutter/embedding/engine/systemchannels/PlatformChannelTest.java b/shell/platform/android/test/io/flutter/embedding/engine/systemchannels/PlatformChannelTest.java index 3d7ef656361ea..c71bf734805c5 100644 --- a/shell/platform/android/test/io/flutter/embedding/engine/systemchannels/PlatformChannelTest.java +++ b/shell/platform/android/test/io/flutter/embedding/engine/systemchannels/PlatformChannelTest.java @@ -1,30 +1,23 @@ package io.flutter.embedding.engine.systemchannels; import android.graphics.Rect; -import android.util.Log; -import org.hamcrest.Description; -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.ArgumentMatcher; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.annotation.Config; - -import java.nio.ByteBuffer; import java.util.ArrayList; import io.flutter.embedding.engine.dart.DartExecutor; import io.flutter.embedding.engine.systemchannels.PlatformChannel; import io.flutter.embedding.engine.systemchannels.PlatformChannel.PlatformMessageHandler; import io.flutter.plugin.common.MethodChannel.Result; -import io.flutter.plugin.common.JSONMethodCodec; import io.flutter.plugin.common.MethodCall; -import static org.mockito.Matchers.argThat; -import static org.mockito.Matchers.eq; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.annotation.Config; + import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; From 773a7e9a7c6e513b6eaeedc991ae31e26aac2312 Mon Sep 17 00:00:00 2001 From: Shi Hao Hong Date: Thu, 29 Aug 2019 12:56:51 -0700 Subject: [PATCH 14/17] Add docs --- .../engine/systemchannels/PlatformChannel.java | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/shell/platform/android/io/flutter/embedding/engine/systemchannels/PlatformChannel.java b/shell/platform/android/io/flutter/embedding/engine/systemchannels/PlatformChannel.java index 97a7da24c9e77..7819673446b08 100644 --- a/shell/platform/android/io/flutter/embedding/engine/systemchannels/PlatformChannel.java +++ b/shell/platform/android/io/flutter/embedding/engine/systemchannels/PlatformChannel.java @@ -139,6 +139,12 @@ private int decodeOrientations(@NonNull JSONArray encodedOrientations) throws JS return ActivityInfo.SCREEN_ORIENTATION_PORTRAIT; } + /** + * Decodes a JSONArray of rectangle data into an ArrayList. + * + * @throws JSONException if {@code inputRects} does not contain expected keys and value types. + */ + @NonNull private ArrayList decodeRects(@NonNull JSONArray inputRects) throws JSONException { ArrayList exclusionRects = new ArrayList(); for (int i = 0; i < inputRects.length(); i++) { @@ -497,7 +503,11 @@ public SystemChromeStyle( } } - // TODO(shihaohong): Add docs to describe what this is used for + /** + * A handler of incoming platform channel method calls received from Flutter. + * It first determines the platform's API to be called. If it exists, it then + * decodes incoming arguments, if needed, into a format that is necessary for the API. + */ @VisibleForTesting protected class PlatformMethodCallHandler implements MethodChannel.MethodCallHandler { @Override From 2dca1602dc50d8527aec1cd4da04aadca9cc54e0 Mon Sep 17 00:00:00 2001 From: Shi Hao Hong Date: Thu, 29 Aug 2019 13:03:20 -0700 Subject: [PATCH 15/17] Fix android/BUILD.gn ordering --- shell/platform/android/BUILD.gn | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shell/platform/android/BUILD.gn b/shell/platform/android/BUILD.gn index 37f2ea049fc36..722001e437a80 100644 --- a/shell/platform/android/BUILD.gn +++ b/shell/platform/android/BUILD.gn @@ -406,8 +406,8 @@ action("robolectric_tests") { "test/io/flutter/embedding/android/FlutterActivityTest.java", "test/io/flutter/embedding/android/FlutterFragmentTest.java", "test/io/flutter/embedding/engine/FlutterEngineCacheTest.java", - "test/io/flutter/embedding/engine/systemchannels/TextInputChannelTest.java", "test/io/flutter/embedding/engine/systemchannels/PlatformChannelTest.java", + "test/io/flutter/embedding/engine/systemchannels/TextInputChannelTest.java", "test/io/flutter/util/PreconditionsTest.java", ] From 57a3bf5c9db66a74adce8e2fdc523561fc28ddc8 Mon Sep 17 00:00:00 2001 From: Shi Hao Hong Date: Thu, 29 Aug 2019 13:24:57 -0700 Subject: [PATCH 16/17] Remove remnant Log.v calls --- .../embedding/engine/systemchannels/PlatformChannel.java | 2 -- .../embedding/engine/systemchannels/PlatformChannelTest.java | 4 ---- 2 files changed, 6 deletions(-) diff --git a/shell/platform/android/io/flutter/embedding/engine/systemchannels/PlatformChannel.java b/shell/platform/android/io/flutter/embedding/engine/systemchannels/PlatformChannel.java index 7819673446b08..0ad84d74db89b 100644 --- a/shell/platform/android/io/flutter/embedding/engine/systemchannels/PlatformChannel.java +++ b/shell/platform/android/io/flutter/embedding/engine/systemchannels/PlatformChannel.java @@ -512,7 +512,6 @@ public SystemChromeStyle( protected class PlatformMethodCallHandler implements MethodChannel.MethodCallHandler { @Override public void onMethodCall(@NonNull MethodCall call, @NonNull MethodChannel.Result result) { - Log.v(TAG, "was called onMethodCall here" + call.method); if (platformMessageHandler == null) { // If no explicit PlatformMessageHandler has been registered then we don't // need to forward this call to an API. Return. @@ -602,7 +601,6 @@ public void onMethodCall(@NonNull MethodCall call, @NonNull MethodChannel.Result break; } - Log.v("Got here", arguments.toString()); JSONArray inputRects = (JSONArray) arguments; ArrayList decodedRects = decodeRects(inputRects); platformMessageHandler.setSystemGestureExclusionRects(decodedRects); diff --git a/shell/platform/android/test/io/flutter/embedding/engine/systemchannels/PlatformChannelTest.java b/shell/platform/android/test/io/flutter/embedding/engine/systemchannels/PlatformChannelTest.java index c71bf734805c5..1268c05b0d04d 100644 --- a/shell/platform/android/test/io/flutter/embedding/engine/systemchannels/PlatformChannelTest.java +++ b/shell/platform/android/test/io/flutter/embedding/engine/systemchannels/PlatformChannelTest.java @@ -38,14 +38,11 @@ public void itSendsSuccessMessageToFramework() throws JSONException { int left = 0; ResultsMock resultsMock = mock(ResultsMock.class); - JSONObject JsonRect = new JSONObject(); - JsonRect.put("top", top); JsonRect.put("right", right); JsonRect.put("bottom", bottom); JsonRect.put("left", left); - JSONArray inputRects = new JSONArray(); inputRects.put(JsonRect); @@ -107,7 +104,6 @@ public void itSendsJSONExceptionOnIncorrectDataShape() throws JSONException { "SystemGestures.setSystemGestureExclusionRects", inputArray ); - platformChannel.parsingMethodCallHandler.onMethodCall(callSystemGestureExclusionRects, resultsMock); verify(resultsMock, times(1)).error( "error", From fc972baacda97e3ac0e1f1595dbd6060d9f028a6 Mon Sep 17 00:00:00 2001 From: Shi Hao Hong Date: Thu, 29 Aug 2019 13:33:00 -0700 Subject: [PATCH 17/17] Fix test naming in PlatformChannelTest.java --- .../engine/systemchannels/PlatformChannelTest.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/shell/platform/android/test/io/flutter/embedding/engine/systemchannels/PlatformChannelTest.java b/shell/platform/android/test/io/flutter/embedding/engine/systemchannels/PlatformChannelTest.java index 1268c05b0d04d..31d7d71c39fd8 100644 --- a/shell/platform/android/test/io/flutter/embedding/engine/systemchannels/PlatformChannelTest.java +++ b/shell/platform/android/test/io/flutter/embedding/engine/systemchannels/PlatformChannelTest.java @@ -26,7 +26,7 @@ @RunWith(RobolectricTestRunner.class) public class PlatformChannelTest { @Test - public void itSendsSuccessMessageToFramework() throws JSONException { + public void setSystemExclusionRectsSendsSuccessMessageToFramework() throws JSONException { DartExecutor dartExecutor = mock(DartExecutor.class); PlatformChannel platformChannel = new PlatformChannel(dartExecutor); PlatformMessageHandler platformMessageHandler = mock(PlatformMessageHandler.class); @@ -61,7 +61,7 @@ public void itSendsSuccessMessageToFramework() throws JSONException { } @Test - public void itRequiresJSONArrayInput() { + public void setSystemExclusionRectsRequiresJSONArrayInput() { DartExecutor dartExecutor = mock(DartExecutor.class); PlatformChannel platformChannel = new PlatformChannel(dartExecutor); PlatformMessageHandler platformMessageHandler = mock(PlatformMessageHandler.class); @@ -84,7 +84,7 @@ public void itRequiresJSONArrayInput() { } @Test - public void itSendsJSONExceptionOnIncorrectDataShape() throws JSONException { + public void setSystemExclusionRectsSendsJSONExceptionOnIncorrectDataShape() throws JSONException { DartExecutor dartExecutor = mock(DartExecutor.class); PlatformChannel platformChannel = new PlatformChannel(dartExecutor); PlatformMessageHandler platformMessageHandler = mock(PlatformMessageHandler.class);