Skip to content

Commit

Permalink
Platform channel for predictive back (#39208)
Browse files Browse the repository at this point in the history
Adds a platform channel method for enabling/disabling Android's predictive back feature.
  • Loading branch information
justinmc authored Jun 9, 2023
1 parent 071e1fb commit ff66711
Show file tree
Hide file tree
Showing 7 changed files with 62 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,8 @@ public class FlutterActivity extends Activity
implements FlutterActivityAndFragmentDelegate.Host, LifecycleOwner {
private static final String TAG = "FlutterActivity";

private boolean hasRegisteredBackCallback = false;

/**
* The ID of the {@code FlutterView} created by this activity.
*
Expand Down Expand Up @@ -643,8 +645,6 @@ protected void onCreate(@Nullable Bundle savedInstanceState) {

lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_CREATE);

registerOnBackInvokedCallback();

configureWindowForTransparency();

setContentView(createFlutterView());
Expand All @@ -668,6 +668,7 @@ public void registerOnBackInvokedCallback() {
getOnBackInvokedDispatcher()
.registerOnBackInvokedCallback(
OnBackInvokedDispatcher.PRIORITY_DEFAULT, onBackInvokedCallback);
hasRegisteredBackCallback = true;
}
}

Expand All @@ -681,6 +682,7 @@ public void registerOnBackInvokedCallback() {
public void unregisterOnBackInvokedCallback() {
if (Build.VERSION.SDK_INT >= 33) {
getOnBackInvokedDispatcher().unregisterOnBackInvokedCallback(onBackInvokedCallback);
hasRegisteredBackCallback = false;
}
}

Expand All @@ -698,6 +700,15 @@ public void onBackInvoked() {
}
: null;

@Override
public void setFrameworkHandlesBack(boolean frameworkHandlesBacks) {
if (frameworkHandlesBacks && !hasRegisteredBackCallback) {
registerOnBackInvokedCallback();
} else if (!frameworkHandlesBacks && hasRegisteredBackCallback) {
unregisterOnBackInvokedCallback();
}
}

/**
* Switches themes for this {@code Activity} from the theme used to launch this {@code Activity}
* to a "normal theme" that is intended for regular {@code Activity} operation.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1689,6 +1689,11 @@ boolean shouldDelayFirstAndroidViewDraw() {
return getArguments().getBoolean(ARG_SHOULD_DELAY_FIRST_ANDROID_VIEW_DRAW);
}

@Override
public void setFrameworkHandlesBack(boolean frameworkHandlesBacks) {
// Irrelevant to FlutterFragment.
}

private boolean stillAttachedForEvent(String event) {
if (delegate == null) {
Log.w(TAG, "FlutterFragment " + hashCode() + " " + event + " called after release.");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,13 @@ public void onMethodCall(@NonNull MethodCall call, @NonNull MethodChannel.Result
result.error("error", exception.getMessage(), null);
}
break;
case "SystemNavigator.setFrameworkHandlesBack":
{
boolean frameworkHandlesBacks = (boolean) arguments;
platformMessageHandler.setFrameworkHandlesBack(frameworkHandlesBacks);
result.success(null);
break;
}
case "SystemNavigator.pop":
platformMessageHandler.popSystemNavigator();
result.success(null);
Expand Down Expand Up @@ -509,6 +516,9 @@ public interface PlatformMessageHandler {
*/
void setSystemUiOverlayStyle(@NonNull SystemChromeStyle systemUiOverlayStyle);

/** The Flutter application would or would not like to handle navigation pop events itself. */
void setFrameworkHandlesBack(boolean frameworkHandlesBack);

/**
* The Flutter application would like to pop the top item off of the Android app's navigation
* back stack.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ public interface PlatformPluginDelegate {
* androidx.activity.OnBackPressedDispatcher} will be executed.
*/
boolean popSystemNavigator();

void setFrameworkHandlesBack(boolean frameworkHandlesBacks);
}

@VisibleForTesting
Expand Down Expand Up @@ -109,6 +111,11 @@ public void setSystemUiOverlayStyle(
setSystemChromeSystemUIOverlayStyle(systemUiOverlayStyle);
}

@Override
public void setFrameworkHandlesBack(boolean frameworkHandlesBacks) {
PlatformPlugin.this.setFrameworkHandlesBack(frameworkHandlesBacks);
}

@Override
public void popSystemNavigator() {
PlatformPlugin.this.popSystemNavigator();
Expand Down Expand Up @@ -475,6 +482,10 @@ private void setSystemChromeSystemUIOverlayStyle(
currentTheme = systemChromeStyle;
}

private void setFrameworkHandlesBack(boolean frameworkHandlesBacks) {
platformPluginDelegate.setFrameworkHandlesBack(frameworkHandlesBacks);
}

private void popSystemNavigator() {
if (platformPluginDelegate != null && platformPluginDelegate.popSystemNavigator()) {
// A custom behavior was executed by the delegate. Don't execute default behavior.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,14 +92,20 @@ public void flutterViewHasId() {
// test that directly exercises the OnBackInvoked APIs when API 33 is supported.
@Test
@TargetApi(33)
public void itRegistersOnBackInvokedCallbackOnCreate() {
public void itRegistersOnBackInvokedCallbackOnChangingFrameworkHandlesBack() {
Intent intent = FlutterActivityWithReportFullyDrawn.createDefaultIntent(ctx);
ActivityController<FlutterActivityWithReportFullyDrawn> activityController =
Robolectric.buildActivity(FlutterActivityWithReportFullyDrawn.class, intent);
FlutterActivityWithReportFullyDrawn activity = spy(activityController.get());

activity.onCreate(null);

verify(activity, times(0)).registerOnBackInvokedCallback();

activity.setFrameworkHandlesBack(false);
verify(activity, times(0)).registerOnBackInvokedCallback();

activity.setFrameworkHandlesBack(true);
verify(activity, times(1)).registerOnBackInvokedCallback();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -417,5 +417,8 @@ public void updateSystemUiOverlays() {}
public boolean popSystemNavigator() {
return false;
}

@Override
public void setFrameworkHandlesBack(boolean frameworkHandlesBacks) {}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -469,6 +469,19 @@ public void verifyWindowFlagsSetToStyleOverlays() {
| WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
}

@Test
public void setFrameworkHandlesBackFlutterActivity() {
Activity mockActivity = mock(Activity.class);
PlatformChannel mockPlatformChannel = mock(PlatformChannel.class);
PlatformPluginDelegate mockPlatformPluginDelegate = mock(PlatformPluginDelegate.class);
PlatformPlugin platformPlugin =
new PlatformPlugin(mockActivity, mockPlatformChannel, mockPlatformPluginDelegate);

platformPlugin.mPlatformMessageHandler.setFrameworkHandlesBack(true);

verify(mockPlatformPluginDelegate, times(1)).setFrameworkHandlesBack(true);
}

@Test
public void popSystemNavigatorFlutterActivity() {
Activity mockActivity = mock(Activity.class);
Expand Down

0 comments on commit ff66711

Please sign in to comment.