Skip to content

Commit 0c1f24c

Browse files
GaryQiancfontas
authored andcommitted
Reland "Support basic back navigation in Android 13/API 33 flutter#35678" (flutter#36051)
1 parent 9b48507 commit 0c1f24c

File tree

3 files changed

+94
-4
lines changed

3 files changed

+94
-4
lines changed

shell/platform/android/io/flutter/embedding/android/FlutterActivity.java

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@
3535
import android.view.View;
3636
import android.view.Window;
3737
import android.view.WindowManager;
38+
import android.window.OnBackInvokedCallback;
39+
import android.window.OnBackInvokedDispatcher;
3840
import androidx.annotation.NonNull;
3941
import androidx.annotation.Nullable;
4042
import androidx.annotation.VisibleForTesting;
@@ -495,13 +497,61 @@ protected void onCreate(@Nullable Bundle savedInstanceState) {
495497

496498
lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_CREATE);
497499

500+
registerOnBackInvokedCallback();
501+
498502
configureWindowForTransparency();
499503

500504
setContentView(createFlutterView());
501505

502506
configureStatusBarForFullscreenFlutterExperience();
503507
}
504508

509+
/**
510+
* Registers the callback with OnBackInvokedDispatcher to capture back navigation gestures and
511+
* pass them to the framework.
512+
*
513+
* <p>This replaces the deprecated onBackPressed method override in order to support API 33's
514+
* predictive back navigation feature.
515+
*
516+
* <p>The callback must be unregistered in order to prevent unpredictable behavior once outside
517+
* the Flutter app.
518+
*/
519+
@VisibleForTesting
520+
public void registerOnBackInvokedCallback() {
521+
if (Build.VERSION.SDK_INT >= 33) {
522+
getOnBackInvokedDispatcher()
523+
.registerOnBackInvokedCallback(
524+
OnBackInvokedDispatcher.PRIORITY_DEFAULT, onBackInvokedCallback);
525+
}
526+
}
527+
528+
/**
529+
* Unregisters the callback from OnBackInvokedDispatcher.
530+
*
531+
* <p>This should be called when the activity is no longer in use to prevent unpredictable
532+
* behavior such as being stuck and unable to press back.
533+
*/
534+
@VisibleForTesting
535+
public void unregisterOnBackInvokedCallback() {
536+
if (Build.VERSION.SDK_INT >= 33) {
537+
getOnBackInvokedDispatcher().unregisterOnBackInvokedCallback(onBackInvokedCallback);
538+
}
539+
}
540+
541+
private final OnBackInvokedCallback onBackInvokedCallback =
542+
Build.VERSION.SDK_INT >= 33
543+
? new OnBackInvokedCallback() {
544+
// TODO(garyq): Remove SuppressWarnings annotation. This was added to workaround
545+
// a google3 bug where the linter is not properly running against API 33, causing
546+
// a failure here. See b/243609613 and https://github.com/flutter/flutter/issues/111295
547+
@SuppressWarnings("Override")
548+
@Override
549+
public void onBackInvoked() {
550+
onBackPressed();
551+
}
552+
}
553+
: null;
554+
505555
/**
506556
* Switches themes for this {@code Activity} from the theme used to launch this {@code Activity}
507557
* to a "normal theme" that is intended for regular {@code Activity} operation.
@@ -680,7 +730,9 @@ protected void onSaveInstanceState(Bundle outState) {
680730
*
681731
* <p>After calling, this activity should be disposed immediately and not be re-used.
682732
*/
683-
private void release() {
733+
@VisibleForTesting
734+
public void release() {
735+
unregisterOnBackInvokedCallback();
684736
if (delegate != null) {
685737
delegate.release();
686738
delegate = null;

shell/platform/android/test/io/flutter/embedding/android/FlutterActivityTest.java

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,36 @@ public void flutterViewHasId() {
8888
assertTrue(activity.findViewById(FlutterActivity.FLUTTER_VIEW_ID) instanceof FlutterView);
8989
}
9090

91+
// TODO(garyq): Robolectric does not yet support android api 33 yet. Switch to a robolectric
92+
// test that directly exercises the OnBackInvoked APIs when API 33 is supported.
93+
@Test
94+
@TargetApi(33)
95+
public void itRegistersOnBackInvokedCallbackOnCreate() {
96+
Intent intent = FlutterActivityWithReportFullyDrawn.createDefaultIntent(ctx);
97+
ActivityController<FlutterActivityWithReportFullyDrawn> activityController =
98+
Robolectric.buildActivity(FlutterActivityWithReportFullyDrawn.class, intent);
99+
FlutterActivityWithReportFullyDrawn activity = spy(activityController.get());
100+
101+
activity.onCreate(null);
102+
103+
verify(activity, times(1)).registerOnBackInvokedCallback();
104+
}
105+
106+
// TODO(garyq): Robolectric does not yet support android api 33 yet. Switch to a robolectric
107+
// test that directly exercises the OnBackInvoked APIs when API 33 is supported.
108+
@Test
109+
@TargetApi(33)
110+
public void itUnregistersOnBackInvokedCallbackOnRelease() {
111+
Intent intent = FlutterActivityWithReportFullyDrawn.createDefaultIntent(ctx);
112+
ActivityController<FlutterActivityWithReportFullyDrawn> activityController =
113+
Robolectric.buildActivity(FlutterActivityWithReportFullyDrawn.class, intent);
114+
FlutterActivityWithReportFullyDrawn activity = spy(activityController.get());
115+
116+
activity.release();
117+
118+
verify(activity, times(1)).unregisterOnBackInvokedCallback();
119+
}
120+
91121
@Test
92122
public void itCreatesDefaultIntentWithExpectedDefaults() {
93123
Intent intent = FlutterActivity.createDefaultIntent(ctx);
@@ -596,6 +626,14 @@ public void resetFullyDrawn() {
596626
}
597627
}
598628

629+
private class FlutterActivityWithMockBackInvokedHandling extends FlutterActivity {
630+
@Override
631+
public void registerOnBackInvokedCallback() {}
632+
633+
@Override
634+
public void unregisterOnBackInvokedCallback() {}
635+
}
636+
599637
private static final class FakeFlutterPlugin
600638
implements FlutterPlugin,
601639
ActivityAware,

shell/platform/android/test_runner/build.gradle

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -71,10 +71,10 @@ android {
7171
testImplementation "com.google.android.play:core:1.8.0"
7272
testImplementation "com.ibm.icu:icu4j:69.1"
7373
testImplementation "org.robolectric:robolectric:4.7.3"
74-
testImplementation "junit:junit:4.13"
75-
testImplementation "androidx.test.ext:junit:1.1.3"
74+
testImplementation "junit:junit:4.13.2"
75+
testImplementation "androidx.test.ext:junit:1.1.4-alpha07"
7676

77-
def mockitoVersion = "4.1.0"
77+
def mockitoVersion = "4.7.0"
7878
testImplementation "org.mockito:mockito-core:$mockitoVersion"
7979
testImplementation "org.mockito:mockito-inline:$mockitoVersion"
8080
testImplementation "org.mockito:mockito-android:$mockitoVersion"

0 commit comments

Comments
 (0)