Skip to content
Open
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
@@ -0,0 +1,29 @@
/*
* Copyright (c) Meta Platforms, Inc. and 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

import android.view.Window

/**
* Listener for receiving extra window creation and destruction events.
*
* This allows modules to react to new windows being added or removed, such as Dialog windows
* registered by Modal components. Modules like StatusBarModule can implement this interface to
* apply their configuration to all active windows.
*
* Third-party libraries can both implement this listener and emit window events through
* [ReactContext.onExtraWindowCreate] and [ReactContext.onExtraWindowDestroy].
*/
public interface ExtraWindowEventListener {

/** Called when a new [Window] is created (e.g. a Dialog window for a Modal). */
public fun onExtraWindowCreate(window: Window)

/** Called when a [Window] is destroyed (e.g. on Dialog window dismiss). */
public fun onExtraWindowDestroy(window: Window)
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import android.content.Intent;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.Window;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.facebook.common.logging.FLog;
Expand Down Expand Up @@ -48,6 +49,8 @@ public interface RCTDeviceEventEmitter extends JavaScriptModule {
new CopyOnWriteArraySet<>();
private final CopyOnWriteArraySet<ActivityEventListener> mActivityEventListeners =
new CopyOnWriteArraySet<>();
private final CopyOnWriteArraySet<ExtraWindowEventListener> mExtraWindowEventListeners =
new CopyOnWriteArraySet<>();
private final CopyOnWriteArraySet<WindowFocusChangeListener> mWindowFocusEventListeners =
new CopyOnWriteArraySet<>();
private final ScrollEndedListeners mScrollEndedListeners = new ScrollEndedListeners();
Expand Down Expand Up @@ -246,6 +249,14 @@ public void removeActivityEventListener(ActivityEventListener listener) {
mActivityEventListeners.remove(listener);
}

public void addExtraWindowEventListener(ExtraWindowEventListener listener) {
mExtraWindowEventListeners.add(listener);
}

public void removeExtraWindowEventListener(ExtraWindowEventListener listener) {
mExtraWindowEventListeners.remove(listener);
}

public void addWindowFocusChangeListener(WindowFocusChangeListener listener) {
mWindowFocusEventListeners.add(listener);
}
Expand Down Expand Up @@ -356,6 +367,30 @@ public void onActivityResult(
}
}

@ThreadConfined(UI)
public void onExtraWindowCreate(Window window) {
UiThreadUtil.assertOnUiThread();
for (ExtraWindowEventListener listener : mExtraWindowEventListeners) {
try {
listener.onExtraWindowCreate(window);
} catch (RuntimeException e) {
handleException(e);
}
}
}

@ThreadConfined(UI)
public void onExtraWindowDestroy(Window window) {
UiThreadUtil.assertOnUiThread();
for (ExtraWindowEventListener listener : mExtraWindowEventListeners) {
try {
listener.onExtraWindowDestroy(window);
} catch (RuntimeException e) {
handleException(e);
}
}
}

@ThreadConfined(UI)
public void onWindowFocusChange(boolean hasFocus) {
UiThreadUtil.assertOnUiThread();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,10 @@ package com.facebook.react.uimanager

import android.app.Activity
import android.content.Context
import android.view.Window
import com.facebook.react.bridge.Callback
import com.facebook.react.bridge.CatalystInstance
import com.facebook.react.bridge.ExtraWindowEventListener
import com.facebook.react.bridge.JavaScriptContextHolder
import com.facebook.react.bridge.JavaScriptModule
import com.facebook.react.bridge.LifecycleEventListener
Expand Down Expand Up @@ -67,6 +69,22 @@ public class ThemedReactContext(
reactApplicationContext.removeLifecycleEventListener(listener)
}

override fun addExtraWindowEventListener(listener: ExtraWindowEventListener) {
reactApplicationContext.addExtraWindowEventListener(listener)
}

override fun removeExtraWindowEventListener(listener: ExtraWindowEventListener) {
reactApplicationContext.removeExtraWindowEventListener(listener)
}

override fun onExtraWindowCreate(window: Window) {
reactApplicationContext.onExtraWindowCreate(window)
}

override fun onExtraWindowDestroy(window: Window) {
reactApplicationContext.onExtraWindowDestroy(window)
}

override fun hasCurrentActivity(): Boolean = reactApplicationContext.hasCurrentActivity()

override fun getCurrentActivity(): Activity? = reactApplicationContext.getCurrentActivity()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,9 @@ public class ReactModalHostView(context: ThemedReactContext) :
UiThreadUtil.assertOnUiThread()

dialog?.let { nonNullDialog ->
nonNullDialog.window?.let { window ->
(context as ThemedReactContext).onExtraWindowDestroy(window)
}
if (nonNullDialog.isShowing) {
val dialogContext =
ContextUtils.findContextOfType(nonNullDialog.context, Activity::class.java)
Expand Down Expand Up @@ -341,6 +344,7 @@ public class ReactModalHostView(context: ThemedReactContext) :
newDialog.show()
updateSystemAppearance()
window.clearFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE)
(context as ThemedReactContext).onExtraWindowCreate(window)
}
}

Expand Down
Loading