Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Conversation

@shihaohong
Copy link

@shihaohong shihaohong commented Aug 26, 2019

Description

Adds a platform channel that allows the Flutter framework to set system gesture exclusion rects for Android Q+.

The corresponding framework branch used to test this behavior is https://github.com/shihaohong/flutter/tree/set-exclusion-rects.

Demo

Demo (exclude top-left corner of app):
resized-gif

Sample code:

                SystemGestureExclusionRects.setSystemGestureExclusionRects([
                  {
                    "top": 0,
                    "right": 500,
                    "bottom": 500,
                    "left": 0,
                  },
                ]);

Related Issues

Related to flutter/flutter#32748

Testing

Testing is blocked for Android SDK Q+ (29+). Will track for follow up updates to unit tests on flutter/flutter#38626

result.success(null);
break;
case "SystemGestures.setSystemGestureExclusionRects":
if (arguments instanceof JSONArray) {
Copy link
Contributor

Choose a reason for hiding this comment

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

subjective, optional: Consider early returning here with a guard clause instead to reduce nesting.

https://testing.googleblog.com/2017/06/code-health-reduce-nesting-reduce.html

JSONArray inputRects = (JSONArray) arguments;
ArrayList<Rect> decodedRects = new ArrayList<Rect>();
for (int i = 0; i < inputRects.length(); i++) {
JSONObject rect = inputRects.getJSONObject(i);
Copy link
Contributor

Choose a reason for hiding this comment

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

subjective, optional: pretty much every other method here has a decodeFoo helper method for parsing the JSON arguments, I think that would probably also make sense here and make it a little easier to read.

Copy link
Author

@shihaohong shihaohong Aug 26, 2019

Choose a reason for hiding this comment

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

Quick question about this, I originally attempted to do that, but ran into the issue where I would to do a try...catch block in the helper method as well to catch JSONExceptions. In the event that happens, do I simple return null and handle it in the original function to send a result.error? (see my previous commit)

Copy link
Contributor

Choose a reason for hiding this comment

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

I'd declare the helper method as throws JSONException instead of trying to have it handle the exceptions itself. Then I'd catch the exceptions and convert them to result.error in the top level here. That seems like a better separation of concerns to me because this is the level where we handle result and passing the output into it normally, so it makes sense to me to catch any parsing exceptions and convert it into an error for result here. decodeSystemUiOverlays and decodeAppSwitcherDescription are doing this already too.

Copy link
Author

Choose a reason for hiding this comment

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

Please disregard my original comment. It compiles just fine with the decodeRects helper method. I think I originally had a nested try/catch block and it was complaining about that instead.

}

private void setSystemGestureExclusionRects(ArrayList<Rect> rects) {
if (Build.VERSION.SDK_INT >= 29) {
Copy link
Contributor

Choose a reason for hiding this comment

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

optional, subjective: This could also be a guard clause.

clipboard.setPrimaryClip(clip);
}

private void setSystemGestureExclusionRects(ArrayList<Rect> rects) {
Copy link
Contributor

Choose a reason for hiding this comment

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

I think the rest of the PR besides this method could be tested, even with the SDK limitations. Even though this is never called, I think you could check that the arguments are parsed safely in PlatformChannel. What do you think?

Copy link
Author

Choose a reason for hiding this comment

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

That makes sense! I'll give it a shot

@PieterAelse
Copy link

There's a limit of 200dp for exclusion height: https://android-developers.googleblog.com/2019/08/final-beta-update-official-android-q.html

We've made further refinements to Gesture Navigation in Beta 6 based on user feedback. First, to ensure reliable and consistent operation, there's a 200dp vertical app exclusion limit for the Back gesture.

Will there be anything on the Flutter side for this? I don't think Google is throwing an exception or anything, but the least thing possible is mention it in the Flutter method documentation.
Also, as far as I can see the 500 from the example is pixels and not dp?

@shihaohong
Copy link
Author

Hi @PieterAelse, I'm aware of both points that there's a limit of 200dp and that my example uses pixels instead of dp. I will document the limit and also include the device pixel ratio as an argument when I create the framework-side PR

@shihaohong shihaohong added the Work in progress (WIP) Not ready (yet) for review! label Aug 27, 2019
@shihaohong shihaohong requested a review from mklim August 29, 2019 19:58
@shihaohong shihaohong removed the Work in progress (WIP) Not ready (yet) for review! label Aug 29, 2019
Copy link
Contributor

@mklim mklim left a comment

Choose a reason for hiding this comment

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

LGTM. Thanks for adding tests!

@VisibleForTesting
protected class PlatformMethodCallHandler implements MethodChannel.MethodCallHandler {
@Override
public void onMethodCall(@NonNull MethodCall call, @NonNull MethodChannel.Result result) {
Copy link
Contributor

Choose a reason for hiding this comment

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

I wish the diff were better here. I spot checked it, assuming that nothing in this was changed from the original besides the new method call.

break;
}

Log.v("Got here", arguments.toString());
Copy link
Contributor

Choose a reason for hiding this comment

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

This log probably isn't useful and should be removed, even at the verbose level.

Copy link
Author

Choose a reason for hiding this comment

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

This was an artifact from when I was testing my tests. I'll remove it!

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=<test_class_name>]`.
5. Build and run with `testing/run_tests.py [--type=java] [--java-filter=<test_class_name>]`.
Copy link
Contributor

Choose a reason for hiding this comment

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

Thanks for updating this!

@shihaohong shihaohong merged commit 7024722 into flutter:master Aug 29, 2019
@shihaohong shihaohong deleted the set-exclusion-rects branch August 29, 2019 21:00
@Nullable
private PlatformMessageHandler platformMessageHandler;

private final MethodChannel.MethodCallHandler parsingMethodCallHandler = new MethodChannel.MethodCallHandler() {
Copy link
Contributor

Choose a reason for hiding this comment

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

@shihaohong why was this moved?

* decodes incoming arguments, if needed, into a format that is necessary for the API.
*/
@VisibleForTesting
protected class PlatformMethodCallHandler implements MethodChannel.MethodCallHandler {
Copy link
Contributor

Choose a reason for hiding this comment

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

I'd like for us to avoid non-static inner classes. I think in this case I'd like for us to revert the movement of this handler definition back to where it was. But in future cases where we do define inner classes, they should be static to avoid the possibility of accidentally leaking references to the outer class.

Copy link
Author

Choose a reason for hiding this comment

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

I had a discussion with @mklim and we felt that it was difficult to read an inline class definition within another class. I'll revert this in a subsequent PR

@RunWith(RobolectricTestRunner.class)
public class PlatformChannelTest {
@Test
public void setSystemExclusionRectsSendsSuccessMessageToFramework() throws JSONException {
Copy link
Contributor

Choose a reason for hiding this comment

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

Please name all tests as itDoesSomethingWhenSomethingHappens or as close to that as possible. This helps ensure that we writing unit tests here instead of integration tests.

);
}

private class ResultsMock implements Result {
Copy link
Contributor

Choose a reason for hiding this comment

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

Please make all inner classes static to avoid hidden references that can cause leaks and complications.

public class PlatformChannelTest {
@Test
public void setSystemExclusionRectsSendsSuccessMessageToFramework() throws JSONException {
DartExecutor dartExecutor = mock(DartExecutor.class);
Copy link
Contributor

Choose a reason for hiding this comment

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

Please denote with comments in each test the part that is setup vs execution vs verification so that developers can more easily check the part they're interested in.

int bottom = 250;
int left = 0;

ResultsMock resultsMock = mock(ResultsMock.class);
Copy link
Contributor

Choose a reason for hiding this comment

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

Can't you just mock(Result.class) instead of introducing ResultsMock? Or does Mockito not allow that?

Copy link
Contributor

@matthew-carroll matthew-carroll left a comment

Choose a reason for hiding this comment

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

I just got back today from a trip so I couldn't review this before merging, but I added a few comments with requests for change.

@shihaohong
Copy link
Author

@matthew-carroll How should I address your review suggestions? Should I make a separate PR addressing them?

@matthew-carroll
Copy link
Contributor

Yeah, I think that would be fine.

engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request Aug 29, 2019
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request Aug 30, 2019
engine-flutter-autoroll added a commit to flutter/flutter that referenced this pull request Aug 30, 2019
[email protected]:flutter/engine.git/compare/9a17d8e45197...101e03c

git log 9a17d8e..101e03c --no-merges --oneline
2019-08-29 [email protected] Return a JSON value for the Skia channel (flutter/engine#11717)
2019-08-29 [email protected] Android 10+ View.setSystemGestureExclusionRects (flutter/engine#11441)
2019-08-29 [email protected] Roll src/third_party/dart 35382f9b14..05c28c6115 (flutter/engine#11702)
2019-08-29 [email protected] Roll src/third_party/skia ca8b07cf8a59..3783375c4d41 (2 commits) (flutter/engine#11712)


If this roll has caused a breakage, revert this CL and stop the roller
using the controls here:
https://autoroll.skia.org/r/flutter-engine-flutter-autoroll
Please CC [email protected] on the revert to ensure that a human
is aware of the problem.

To report a problem with the AutoRoller itself, please file a bug:
https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug

Documentation for the AutoRoller is here:
https://skia.googlesource.com/buildbot/+/master/autoroll/README.md
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request Aug 30, 2019
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request Aug 30, 2019
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request Aug 30, 2019
GaryQian pushed a commit to flutter/flutter that referenced this pull request Aug 31, 2019
* 37c5510 Roll src/third_party/skia ca8b07cf8a59..3783375c4d41 (2 commits) (flutter/engine#11712)

* 74a3c73 Roll src/third_party/dart 35382f9b14..05c28c6115 (flutter/engine#11702)

* 7024722 Android 10+ View.setSystemGestureExclusionRects (flutter/engine#11441)

* 101e03c Return a JSON value for the Skia channel (flutter/engine#11717)

* dce8a34 Revert "Notify framework to clear input connection when app is backgrounded (#35054) (#9498)" (flutter/engine#11720)

* 1b1f781 Quote the font family name whenever setting the font-family property. (flutter/engine#11722)

* 260f88d Roll src/third_party/skia 3783375c4d41..165ca3f85b7a (8 commits) (flutter/engine#11725)

* e620012 Roll src/third_party/dart 05c28c6115..1573f4e877 (14 commits)

* 81e010f last flutter web sync: cc38319841 (flutter/engine#11732)

* 1235439 Roll src/third_party/dart 1573f4e877..fd48ea3432 (16 commits)

* cf5d2a6 Add wasm to sky_engine (flutter/engine#11736)

* 118b5f3 Roll src/third_party/dart fd48ea3432..a873bc5db3 (7 commits)

* a7d59aa Roll src/third_party/skia 165ca3f85b7a..ba0a2c7ad992 (1 commits) (flutter/engine#11745)

* 8401ce9 Roll src/third_party/dart a873bc5db3..35df96a2e2 (1 commits)

* ff3dffa Roll src/third_party/skia ba0a2c7ad992..7409b73fa546 (3 commits) (flutter/engine#11756)

* 70626c0 Roll src/third_party/skia 7409b73fa546..575699569e91 (1 commits) (flutter/engine#11766)

* 292d844 Roll src/third_party/dart 35df96a2e2..d4342b9021 (4 commits)
shihaohong pushed a commit that referenced this pull request Sep 5, 2019
…from #11441 (#11804)

* Improve variable naming and javadoc for setSystemGestureExclusionRects

* Remove variables from setSystemGestureExclusionRects tests

* Split test for two behaviors into two separate tests for setSystemGestureExclusionRects success case
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants