Skip to content

[Android] Add onUserLeaveHint support to ReactActivityDelegate #42741

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

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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 @@ -105,6 +105,12 @@ public void onNewIntent(Intent intent) {
}
}

@Override
public void onUserLeaveHint() {
super.onUserLeaveHint();
mDelegate.onUserLeaveHint();
}

@Override
public void requestPermissions(
String[] permissions, int requestCode, PermissionListener listener) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,10 @@ protected void loadApp(String appKey) {
getPlainActivity().setContentView(mReactDelegate.getReactRootView());
}

protected void onUserLeaveHint() {
mReactDelegate.onUserLeaveHint();
}

protected void onPause() {
mReactDelegate.onHostPause();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,16 @@ public void onHostResume() {
}
}

public void onUserLeaveHint() {
if (ReactFeatureFlags.enableBridgelessArchitecture) {
mReactHost.onHostLeaveHint(mActivity);
} else {
if (getReactNativeHost().hasInstance()) {
getReactNativeHost().getReactInstanceManager().onUserLeaveHint(mActivity);
}
}
}

public void onHostPause() {
if (ReactFeatureFlags.enableBridgelessArchitecture) {
mReactHost.onHostPause(mActivity);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,9 @@ interface ReactHost {
/** To be called when the host activity is resumed. */
fun onHostResume(activity: Activity?)

/** To be called when the host activity is about to go into the background as the result of user choice. */
fun onHostLeaveHint(activity: Activity?)

/** To be called when the host activity is paused. */
fun onHostPause(activity: Activity?)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -585,6 +585,38 @@ public void onHostPause() {
moveToBeforeResumeLifecycleState();
}

/**
* This method should be called from {@link Activity#onUserLeaveHint()}. It notifies all
* listening modules that the user is about to leave the activity. The passed Activity is has to
* be the current Activity.
*
* @param activity the activity being backgrounded as a result of user action
*/
@ThreadConfined(UI)
public void onUserLeaveHint(@Nullable Activity activity) {
if (mRequireActivity) {
Assertions.assertCondition(mCurrentActivity != null);
}

if (mCurrentActivity != null) {
Assertions.assertCondition(
activity == mCurrentActivity,
"Called onUserLeaveHint on an activity that is not the current activity, this is incorrect! "
+ "Current activity: "
+ mCurrentActivity.getClass().getSimpleName()
+ " "
+ "Leaving activity: "
+ activity.getClass().getSimpleName());
Comment on lines +601 to +609
Copy link
Contributor

Choose a reason for hiding this comment

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

@behenate Ok so one of our product was crashing on this assert
I haven't had the time to investigate what's going on, but practically we should understand if this assert is actually necessary.

That's the stacktrace:

02-01 14:38:52.320  4500  4522 V fb-android-monitor: java.lang.AssertionError
02-01 14:38:52.320  4500  4522 V fb-android-monitor: 	at com.facebook.infer.annotation.Assertions.assertCondition(Assertions.java:82)
02-01 14:38:52.320  4500  4522 V fb-android-monitor: 	at com.facebook.react.ReactInstanceManager.onUserLeaveHint(ReactInstanceManager.java:598)
02-01 14:38:52.320  4500  4522 V fb-android-monitor: 	at com.facebook.react.ReactDelegate.onUserLeaveHint(ReactDelegate.java:107)
02-01 14:38:52.320  4500  4522 V fb-android-monitor: 	at com.facebook.react.ReactActivityDelegate.onUserLeaveHint(ReactActivityDelegate.java:127)
02-01 14:38:52.320  4500  4522 V fb-android-monitor: 	at com.facebook.react.ReactActivity.onUserLeaveHint(ReactActivity.java:111)
02-01 14:38:52.320  4500  4522 V fb-android-monitor: 	at android.app.Activity.performUserLeaving(Activity.java:8189)
02-01 14:38:52.320  4500  4522 V fb-android-monitor: 	at android.app.Instrumentation.callActivityOnUserLeaving(Instrumentation.java:1520)
02-01 14:38:52.320  4500  4522 V fb-android-monitor: 	at android.app.ActivityThread.performUserLeavingActivity(ActivityThread.java:4659)
02-01 14:38:52.320  4500  4522 V fb-android-monitor: 	at android.app.ActivityThread.handlePauseActivity(ActivityThread.java:4643)
02-01 14:38:52.320  4500  4522 V fb-android-monitor: 	at android.app.servertransaction.PauseActivityItem.execute(PauseActivityItem.java:46)
02-01 14:38:52.320  4500  4522 V fb-android-monitor: 	at android.app.servertransaction.TransactionExecutor.executeLifecycleState(TransactionExecutor.java:176)
02-01 14:38:52.320  4500  4522 V fb-android-monitor: 	at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:97)
02-01 14:38:52.320  4500  4522 V fb-android-monitor: 	at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2066)
02-01 14:38:52.320  4500  4522 V fb-android-monitor: 	at android.os.Handler.dispatchMessage(Handler.java:106)
02-01 14:38:52.320  4500  4522 V fb-android-monitor: 	at android.os.Looper.loop(Looper.java:223)
02-01 14:38:52.320  4500  4522 V fb-android-monitor: 	at android.app.ActivityThread.main(ActivityThread.java:7656)
02-01 14:38:52.320  4500  4522 V fb-android-monitor: 	at java.lang.reflect.Method.invoke(Native Method)
02-01 14:38:52.320  4500  4522 V fb-android-monitor: 	at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
02-01 14:38:52.320  4500  4522 V fb-android-monitor: 	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)
02-01 14:38:52.320  4500  4522 V fb-android-monitor: 	at Z.init(unknown)

Could you resubmit 3b6c522 without this assert?

Copy link
Contributor

Choose a reason for hiding this comment

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

@behenate are you able to follow-up here?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@cortinico Sorry for no reply, I'm currently out of office until February 14th, I will follow up when I'm back :)

Copy link
Contributor

Choose a reason for hiding this comment

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

Sure no rush 👍


UiThreadUtil.assertOnUiThread();

ReactContext currentContext = getCurrentReactContext();
if (currentContext != null) {
currentContext.onUserLeaveHint(activity);
}
}
}

/**
* Call this from {@link Activity#onPause()}. This notifies any listening modules so they can do
* any necessary cleanup. The passed Activity is the current Activity being paused. This will
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,7 @@ public interface ActivityEventListener {

/** Called when a new intent is passed to the activity */
void onNewIntent(Intent intent);

/** Called when host activity receives an {@link Activity#onUserLeaveHint()} call. */
default void onUserLeaveHint(Activity activity) {};
}
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,19 @@ public void onHostResume(@Nullable Activity activity) {
ReactMarker.logMarker(ReactMarkerConstants.ON_HOST_RESUME_END);
}

@ThreadConfined(UI)
public void onUserLeaveHint(@Nullable Activity activity) {
ReactMarker.logMarker(ReactMarkerConstants.ON_USER_LEAVE_HINT_START);
for (ActivityEventListener listener : mActivityEventListeners) {
try {
listener.onUserLeaveHint(activity);
} catch (RuntimeException e) {
handleException(e);
}
}
ReactMarker.logMarker(ReactMarkerConstants.ON_USER_LEAVE_HINT_END);
}

@ThreadConfined(UI)
public void onNewIntent(@Nullable Activity activity, Intent intent) {
UiThreadUtil.assertOnUiThread();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ public enum ReactMarkerConstants {
INITIALIZE_MODULE_END,
ON_HOST_RESUME_START,
ON_HOST_RESUME_END,
ON_USER_LEAVE_HINT_START,
ON_USER_LEAVE_HINT_END,
ON_HOST_PAUSE_START,
ON_HOST_PAUSE_END,
CONVERT_CONSTANTS_START,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,18 @@ public void onHostResume(final @Nullable Activity activity) {
mReactLifecycleStateManager.moveToOnHostResume(currentContext, getCurrentActivity());
}

@ThreadConfined(UI)
@Override
public void onHostLeaveHint(final @Nullable Activity activity) {
final String method = "onUserLeaveHint(activity)";
log(method);

ReactContext currentContext = getCurrentReactContext();
if (currentContext != null) {
currentContext.onUserLeaveHint(activity);
}
}

@ThreadConfined(UI)
@Override
public void onHostPause(final @Nullable Activity activity) {
Expand Down