Feature to listen on window focus events (#25039)
Summary: Addressed issue: https://github.com/facebook/react-native/issues/24149 On Android, activity's lifecycle events are not triggered when the user pulls down the Status Bar (opening Notification Drawer). In order to know that, you need to override [onWindowFocusChanged method](https://developer.android.com/reference/android/app/Activity.html#onWindowFocusChanged(boolean)). ## Changelog [Android] [Added] - Adds a new listener for `onWindowFocusChanged` [JavaScript] [Added] - New event, `focusChanged`, to listen on focus gain/loss Pull Request resolved: https://github.com/facebook/react-native/pull/25039 Differential Revision: D15644954 Pulled By: cpojer fbshipit-source-id: 823acffc4287bec4bf56e9f5ffcac65c01cf13d3
This commit is contained in:
Родитель
bf8d918681
Коммит
d45818fe47
|
@ -25,6 +25,7 @@ const invariant = require('invariant');
|
|||
*/
|
||||
class AppState extends NativeEventEmitter {
|
||||
_eventHandlers: Object;
|
||||
_supportedEvents = ['change', 'memoryWarning', 'blur', 'focus'];
|
||||
currentState: ?string;
|
||||
isAvailable: boolean;
|
||||
|
||||
|
@ -32,10 +33,10 @@ class AppState extends NativeEventEmitter {
|
|||
super(NativeAppState);
|
||||
|
||||
this.isAvailable = true;
|
||||
this._eventHandlers = {
|
||||
change: new Map(),
|
||||
memoryWarning: new Map(),
|
||||
};
|
||||
this._eventHandlers = this._supportedEvents.reduce((handlers, key) => {
|
||||
handlers[key] = new Map();
|
||||
return handlers;
|
||||
}, {});
|
||||
|
||||
this.currentState = NativeAppState.getConstants().initialAppState;
|
||||
|
||||
|
@ -75,22 +76,43 @@ class AppState extends NativeEventEmitter {
|
|||
*/
|
||||
addEventListener(type: string, handler: Function) {
|
||||
invariant(
|
||||
['change', 'memoryWarning'].indexOf(type) !== -1,
|
||||
this._supportedEvents.indexOf(type) !== -1,
|
||||
'Trying to subscribe to unknown event: "%s"',
|
||||
type,
|
||||
);
|
||||
if (type === 'change') {
|
||||
this._eventHandlers[type].set(
|
||||
handler,
|
||||
this.addListener('appStateDidChange', appStateData => {
|
||||
handler(appStateData.app_state);
|
||||
}),
|
||||
);
|
||||
} else if (type === 'memoryWarning') {
|
||||
this._eventHandlers[type].set(
|
||||
handler,
|
||||
this.addListener('memoryWarning', handler),
|
||||
);
|
||||
|
||||
switch (type) {
|
||||
case 'change': {
|
||||
this._eventHandlers[type].set(
|
||||
handler,
|
||||
this.addListener('appStateDidChange', appStateData => {
|
||||
handler(appStateData.app_state);
|
||||
}),
|
||||
);
|
||||
break;
|
||||
}
|
||||
case 'memoryWarning': {
|
||||
this._eventHandlers[type].set(
|
||||
handler,
|
||||
this.addListener('memoryWarning', handler),
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
||||
case 'blur':
|
||||
case 'focus': {
|
||||
this._eventHandlers[type].set(
|
||||
handler,
|
||||
this.addListener('appStateFocusChange', hasFocus => {
|
||||
if (type === 'blur' && !hasFocus) {
|
||||
handler();
|
||||
}
|
||||
if (type === 'focus' && hasFocus) {
|
||||
handler();
|
||||
}
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -101,7 +123,7 @@ class AppState extends NativeEventEmitter {
|
|||
*/
|
||||
removeEventListener(type: string, handler: Function) {
|
||||
invariant(
|
||||
['change', 'memoryWarning'].indexOf(type) !== -1,
|
||||
this._supportedEvents.indexOf(type) !== -1,
|
||||
'Trying to remove listener for unknown event: "%s"',
|
||||
type,
|
||||
);
|
||||
|
|
|
@ -125,6 +125,12 @@ public abstract class ReactActivity extends AppCompatActivity
|
|||
mDelegate.onRequestPermissionsResult(requestCode, permissions, grantResults);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWindowFocusChanged(boolean hasFocus) {
|
||||
super.onWindowFocusChanged(hasFocus);
|
||||
mDelegate.onWindowFocusChanged(hasFocus);
|
||||
}
|
||||
|
||||
protected final ReactNativeHost getReactNativeHost() {
|
||||
return mDelegate.getReactNativeHost();
|
||||
}
|
||||
|
|
|
@ -182,6 +182,12 @@ public class ReactActivityDelegate {
|
|||
return false;
|
||||
}
|
||||
|
||||
public void onWindowFocusChanged(boolean hasFocus) {
|
||||
if (getReactNativeHost().hasInstance()) {
|
||||
getReactNativeHost().getReactInstanceManager().onWindowFocusChange(hasFocus);
|
||||
}
|
||||
}
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.M)
|
||||
public void requestPermissions(
|
||||
String[] permissions,
|
||||
|
|
|
@ -703,6 +703,15 @@ public class ReactInstanceManager {
|
|||
}
|
||||
}
|
||||
|
||||
@ThreadConfined(UI)
|
||||
public void onWindowFocusChange(boolean hasFocus) {
|
||||
UiThreadUtil.assertOnUiThread();
|
||||
ReactContext currentContext = getCurrentReactContext();
|
||||
if (currentContext != null) {
|
||||
currentContext.onWindowFocusChange(hasFocus);
|
||||
}
|
||||
}
|
||||
|
||||
@ThreadConfined(UI)
|
||||
public void showDevOptionsDialog() {
|
||||
UiThreadUtil.assertOnUiThread();
|
||||
|
|
|
@ -36,6 +36,8 @@ public class ReactContext extends ContextWrapper {
|
|||
new CopyOnWriteArraySet<>();
|
||||
private final CopyOnWriteArraySet<ActivityEventListener> mActivityEventListeners =
|
||||
new CopyOnWriteArraySet<>();
|
||||
private final CopyOnWriteArraySet<WindowFocusChangeListener> mWindowFocusEventListeners =
|
||||
new CopyOnWriteArraySet<>();
|
||||
|
||||
private LifecycleState mLifecycleState = LifecycleState.BEFORE_CREATE;
|
||||
|
||||
|
@ -196,6 +198,14 @@ public class ReactContext extends ContextWrapper {
|
|||
mActivityEventListeners.remove(listener);
|
||||
}
|
||||
|
||||
public void addWindowFocusChangeListener(WindowFocusChangeListener listener) {
|
||||
mWindowFocusEventListeners.add(listener);
|
||||
}
|
||||
|
||||
public void removeWindowFocusChangeListener(WindowFocusChangeListener listener) {
|
||||
mWindowFocusEventListeners.remove(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Should be called by the hosting Fragment in {@link Fragment#onResume}
|
||||
*/
|
||||
|
@ -281,6 +291,17 @@ public class ReactContext extends ContextWrapper {
|
|||
}
|
||||
}
|
||||
|
||||
public void onWindowFocusChange(boolean hasFocus) {
|
||||
UiThreadUtil.assertOnUiThread();
|
||||
for (WindowFocusChangeListener listener : mWindowFocusEventListeners) {
|
||||
try {
|
||||
listener.onWindowFocusChange(hasFocus);
|
||||
} catch (RuntimeException e) {
|
||||
handleException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void assertOnUiQueueThread() {
|
||||
Assertions.assertNotNull(mUiMessageQueueThread).assertIsOnThread();
|
||||
}
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
// Copyright (c) Facebook, Inc. and its affiliates.
|
||||
|
||||
// This source code is licensed under the MIT license found in the
|
||||
// LICENSE file in the root directory of this source tree.
|
||||
|
||||
|
||||
package com.facebook.react.bridge;
|
||||
|
||||
|
||||
/*
|
||||
* Listener for receiving window focus events.
|
||||
*/
|
||||
public interface WindowFocusChangeListener {
|
||||
void onWindowFocusChange(boolean hasFocus);
|
||||
}
|
|
@ -13,6 +13,7 @@ import com.facebook.react.bridge.LifecycleEventListener;
|
|||
import com.facebook.react.bridge.ReactApplicationContext;
|
||||
import com.facebook.react.bridge.ReactContextBaseJavaModule;
|
||||
import com.facebook.react.bridge.ReactMethod;
|
||||
import com.facebook.react.bridge.WindowFocusChangeListener;
|
||||
import com.facebook.react.bridge.WritableMap;
|
||||
import com.facebook.react.common.LifecycleState;
|
||||
import com.facebook.react.module.annotations.ReactModule;
|
||||
|
@ -23,7 +24,7 @@ import java.util.Map;
|
|||
|
||||
@ReactModule(name = AppStateModule.NAME)
|
||||
public class AppStateModule extends ReactContextBaseJavaModule
|
||||
implements LifecycleEventListener {
|
||||
implements LifecycleEventListener, WindowFocusChangeListener {
|
||||
|
||||
protected static final String NAME = "AppState";
|
||||
|
||||
|
@ -37,6 +38,7 @@ public class AppStateModule extends ReactContextBaseJavaModule
|
|||
public AppStateModule(ReactApplicationContext reactContext) {
|
||||
super(reactContext);
|
||||
reactContext.addLifecycleEventListener(this);
|
||||
reactContext.addWindowFocusChangeListener(this);
|
||||
mAppState = (reactContext.getLifecycleState() == LifecycleState.RESUMED ?
|
||||
APP_STATE_ACTIVE : APP_STATE_BACKGROUND);
|
||||
}
|
||||
|
@ -76,6 +78,12 @@ public class AppStateModule extends ReactContextBaseJavaModule
|
|||
// catalyst instance is going to be immediately dropped, and all JS calls with it.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWindowFocusChange(boolean hasFocus) {
|
||||
getReactApplicationContext().getJSModule(RCTDeviceEventEmitter.class)
|
||||
.emit("appStateFocusChange", hasFocus);
|
||||
}
|
||||
|
||||
private WritableMap createAppStateEventMap() {
|
||||
WritableMap appState = Arguments.createMap();
|
||||
appState.putString("app_state", mAppState);
|
||||
|
|
Загрузка…
Ссылка в новой задаче