Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Platform channel for predictive back #39208

Merged
merged 22 commits into from
Jun 9, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
9b25e71
Log everywhere I see onBackPressed... And it doesn't log anything!
justinmc Jan 27, 2023
b10efe3
Just hackily remove all usage of onBack, and predictive back does wor…
justinmc Jan 27, 2023
75d8e38
Undid all of the commenting and deleting and located the one call tha…
justinmc Jan 27, 2023
e8a5130
No logging verbose
justinmc Jan 27, 2023
9c0e7cc
WIP A platform channel API to declare that the nav stack is empty
justinmc Jan 28, 2023
205d1e5
navigationStackIsEmpty method to enable predictive back
justinmc Feb 1, 2023
66d1f84
Migrate to updateNavigationStackStatus, works for inner routes
justinmc Feb 9, 2023
9e8e230
Clean up logs and todos
justinmc Feb 9, 2023
0ed2bec
Rename hasMultiple to frameworkHandlesPop for clarity
justinmc Mar 7, 2023
2afbbad
Merge branch 'main' into predictive-back-root
justinmc Mar 7, 2023
8aeba57
Analyzer fix
justinmc Mar 7, 2023
5e89211
WIP some debugging
justinmc Apr 7, 2023
015f2a5
Merge branch 'main' into predictive-back-root
justinmc Apr 7, 2023
b7b2f17
Merge branch 'main' into predictive-back-root
justinmc May 12, 2023
6bc7d5e
Rename to frameworkHandlesBacks
justinmc May 26, 2023
01a22a2
Clean up
justinmc May 26, 2023
6f22009
Confirmed that it works on my old (API 24) samsung device
justinmc May 26, 2023
440a6ee
I dont think I need to modify flutterfragment(activity)
justinmc May 30, 2023
e075275
Tests and empty implementation for FlutterFragment
justinmc Jun 2, 2023
af98e2c
Merge remote-tracking branch 'upstream/main' into predictive-back-root
justinmc Jun 5, 2023
1db22e5
More specific name for hasRegisteredCallback
justinmc Jun 7, 2023
4701d66
Backs to Back
justinmc Jun 7, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Now that this is removed, it means that by default, Flutter will not handle back gestures. So if you start up a Flutter app that does nothing, has no Navigator or WidgetsApp etc., root predictive back will work. The framework will have to first call setFrameworkHandlesBacks in order to prevent predictive back and to handle back gestures itself. This will be handled automatically in Flutter apps that use WidgetsApp.


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