From 6e8198fd61df2677768dc6f93b16e3beb65e59da Mon Sep 17 00:00:00 2001 From: tarikpo Date: Mon, 2 Dec 2024 20:45:26 +0100 Subject: [PATCH 1/3] added logs --- .../android/.project | 28 ++++++++++++++++ .../ExternalDisplayHelper.java | 18 +++++++++++ .../RNExternalDisplayPackage.java | 9 ++++++ .../RNExternalDisplayView.java | 32 +++++++++++++++++++ .../RNExternalDisplayManager.java | 21 ++++++++++++ .../RNExternalDisplayModule.java | 4 +++ 6 files changed, 112 insertions(+) create mode 100644 packages/react-native-external-display/android/.project diff --git a/packages/react-native-external-display/android/.project b/packages/react-native-external-display/android/.project new file mode 100644 index 00000000..c55ce2f6 --- /dev/null +++ b/packages/react-native-external-display/android/.project @@ -0,0 +1,28 @@ + + + react-native-external-display + Project react-native-external-display created by Buildship. + + + + + org.eclipse.buildship.core.gradleprojectbuilder + + + + + + org.eclipse.buildship.core.gradleprojectnature + + + + 1733156198568 + + 30 + + org.eclipse.core.resources.regexFilterMatcher + node_modules|\.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__ + + + + diff --git a/packages/react-native-external-display/android/src/main/java/com/externaldisplay/ExternalDisplayHelper.java b/packages/react-native-external-display/android/src/main/java/com/externaldisplay/ExternalDisplayHelper.java index 6ec288af..a52cf98b 100644 --- a/packages/react-native-external-display/android/src/main/java/com/externaldisplay/ExternalDisplayHelper.java +++ b/packages/react-native-external-display/android/src/main/java/com/externaldisplay/ExternalDisplayHelper.java @@ -17,6 +17,7 @@ import java.util.Map; import java.util.HashMap; +import android.util.Log; import com.facebook.react.bridge.LifecycleEventListener; import com.facebook.react.bridge.ReactApplicationContext; @@ -25,17 +26,24 @@ class ExternalDisplayScreen extends Presentation { ExternalDisplayScreen(Context ctx, Display display) { super(ctx, display); + Log.d("RNExternalDisplayEvent", "ExternalDisplayScreen init"); + } @Override protected void onCreate(Bundle savedInstanceState) { + Log.d("RNExternalDisplayEvent", "ExternalDisplayScreen onCreate"); + super.onCreate(savedInstanceState); } } @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1) class ExternalDisplayHelper implements DisplayManager.DisplayListener { + public static Map getScreenInfo(Display[] displays) { + Log.d("RNExternalDisplayEvent", "ExternalDisplayScreen getScreenInfo"); + HashMap info = new HashMap(); for (Display display : displays) { int displayId = display.getDisplayId(); @@ -74,25 +82,35 @@ public ExternalDisplayHelper(Context context, Listener listener) { } public Display getDisplay(int displayId) { + Log.d("RNExternalDisplayEvent", "ExternalDisplayScreen getDisplay"); + return dm.getDisplay(displayId); } public Display[] getDisplays() { + Log.d("RNExternalDisplayEvent", "ExternalDisplayScreen getDisplays"); + return dm.getDisplays(DisplayManager.DISPLAY_CATEGORY_PRESENTATION); } @Override public void onDisplayAdded(int displayId) { + Log.d("RNExternalDisplayEvent", "ExternalDisplayScreen onDisplayAdded"); + listener.onDisplayAdded(getDisplays(), displayId); } @Override public void onDisplayChanged(int displayId) { + Log.d("RNExternalDisplayEvent", "ExternalDisplayScreen onDisplayChanged"); + listener.onDisplayChanged(getDisplays(), displayId); } @Override public void onDisplayRemoved(int displayId) { + Log.d("RNExternalDisplayEvent", "ExternalDisplayScreen onDisplayRemoved"); + listener.onDisplayRemoved(getDisplays(), displayId); } } diff --git a/packages/react-native-external-display/android/src/main/java/com/externaldisplay/RNExternalDisplayPackage.java b/packages/react-native-external-display/android/src/main/java/com/externaldisplay/RNExternalDisplayPackage.java index 93a92e7f..94c19eb8 100644 --- a/packages/react-native-external-display/android/src/main/java/com/externaldisplay/RNExternalDisplayPackage.java +++ b/packages/react-native-external-display/android/src/main/java/com/externaldisplay/RNExternalDisplayPackage.java @@ -7,6 +7,7 @@ import com.facebook.react.module.model.ReactModuleInfoProvider; import com.facebook.react.TurboReactPackage; import com.facebook.react.uimanager.ViewManager; +import android.util.Log; import java.util.ArrayList; import java.util.Collections; @@ -15,11 +16,15 @@ import java.util.Map; import android.util.Log; +import com.externaldisplay.RNExternalDisplayManager; +import com.externaldisplay.RNExternalDisplayModule; public class RNExternalDisplayPackage extends TurboReactPackage { @Override public List createViewManagers(ReactApplicationContext reactContext) { + Log.d("RNExternalDisplayEvent", "RNExternalDisplayPackage createViewManagers"); + List viewManagers = new ArrayList<>(); viewManagers.add(new RNExternalDisplayManager(reactContext)); return viewManagers; @@ -28,6 +33,8 @@ public List createViewManagers(ReactApplicationContext reactContext @Nullable @Override public NativeModule getModule(String name, ReactApplicationContext reactContext) { + Log.d("RNExternalDisplayEvent", "RNExternalDisplayPackage getModule"); + if (name.equals(RNExternalDisplayModule.REACT_CLASS)) { return new com.externaldisplay.RNExternalDisplayModule(reactContext); } else { @@ -37,6 +44,8 @@ public NativeModule getModule(String name, ReactApplicationContext reactContext) @Override public ReactModuleInfoProvider getReactModuleInfoProvider() { + Log.d("RNExternalDisplayEvent", "RNExternalDisplayPackage getReactModuleInfoProvider"); + return () -> { final Map moduleInfos = new HashMap<>(); boolean isTurboModule = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED; diff --git a/packages/react-native-external-display/android/src/main/java/com/externaldisplay/RNExternalDisplayView.java b/packages/react-native-external-display/android/src/main/java/com/externaldisplay/RNExternalDisplayView.java index f2ae98fc..c411774f 100644 --- a/packages/react-native-external-display/android/src/main/java/com/externaldisplay/RNExternalDisplayView.java +++ b/packages/react-native-external-display/android/src/main/java/com/externaldisplay/RNExternalDisplayView.java @@ -9,6 +9,7 @@ import android.widget.LinearLayout; import com.facebook.common.logging.FLog; import com.facebook.react.common.ReactConstants; +import android.util.Log; import android.view.Display; import android.util.DisplayMetrics; @@ -30,11 +31,15 @@ public RNExternalDisplayView(Context context, ExternalDisplayHelper helper) { ((ReactContext) context).addLifecycleEventListener(this); this.context = context; this.helper = helper; + Log.d("RNExternalDisplayEvent", "RNExternalDisplayView init"); + } @Override public void addView(View child, int index) { subviews.add(index, child); + Log.d("RNExternalDisplayEvent", "RNExternalDisplayView addView"); + updateScreen(); } @@ -44,22 +49,30 @@ protected void onLayout(boolean changed, int l, int t, int r, int b) { @Override public int getChildCount() { + Log.d("RNExternalDisplayEvent", "RNExternalDisplayView getChildCount"); + return subviews.size(); } @Override public View getChildAt(int index) { + Log.d("RNExternalDisplayEvent", "RNExternalDisplayView getChildAt"); + return subviews.get(index); } @Override public void removeView(View view) { + Log.d("RNExternalDisplayEvent", "RNExternalDisplayView removeView"); + super.removeView(view); } @Override public void removeViewAt(int index) { View child = getChildAt(index); + Log.d("RNExternalDisplayEvent", "RNExternalDisplayView removeViewAt"); + super.removeView(child); subviews.remove(index); if (wrap != null) { @@ -72,6 +85,8 @@ public void removeViewAt(int index) { } public void onDropInstance() { + Log.d("RNExternalDisplayEvent", "RNExternalDisplayView onDropInstance"); + ((ReactContext) getContext()).removeLifecycleEventListener(this); if (wrap != null && wrap.getChildCount() > 0) { for (int i = 0; i < wrap.getChildCount(); i++) { @@ -89,6 +104,8 @@ public void addChildrenForAccessibility(ArrayList outChildren) { @Override public void onHostResume() { + Log.d("RNExternalDisplayEvent", "RNExternalDisplayView onHostResume"); + if (displayScreen == null && !pausedWithDisplayScreen) { return; } @@ -98,6 +115,8 @@ public void onHostResume() { @Override public void onHostPause() { + Log.d("RNExternalDisplayEvent", "RNExternalDisplayView onHostPause"); + if (displayScreen == null) { return; } @@ -112,11 +131,16 @@ public void onHostPause() { @Override public void onHostDestroy() { + Log.d("RNExternalDisplayEvent", "RNExternalDisplayView onHostDestroy"); + onDropInstance(); } public void updateScreen() { + Log.d("RNExternalDisplayEvent", "RNExternalDisplayView updateScreen"); + if (getChildCount() == 0) return; + if (screen > 0) { Display display = helper.getDisplay(screen); if (display != null) { @@ -159,6 +183,8 @@ public void updateScreen() { } private void destroyScreen() { + Log.d("RNExternalDisplayEvent", "RNExternalDisplayView destroyScreen"); + if (displayScreen != null) { displayScreen.hide(); displayScreen.dismiss(); @@ -168,6 +194,8 @@ private void destroyScreen() { } public void setScreen(String screen) { + Log.d("RNExternalDisplayEvent", "RNExternalDisplayView setScreen"); + if (getChildCount() > 0 && wrap != null && wrap.getChildCount() > 0) { for (int i = 0; i < wrap.getChildCount(); i++) { wrap.removeViewAt(i); @@ -191,10 +219,14 @@ public void setScreen(String screen) { } public int getScreen() { + Log.d("RNExternalDisplayEvent", "RNExternalDisplayView getScreen"); + return this.screen; } public void setFallbackInMainScreen(boolean value) { + Log.d("RNExternalDisplayEvent", "RNExternalDisplayView setFallbackInMainScreen"); + this.fallbackInMainScreen = value; } } diff --git a/packages/react-native-external-display/android/src/oldarch/java/com/externaldisplay/RNExternalDisplayManager.java b/packages/react-native-external-display/android/src/oldarch/java/com/externaldisplay/RNExternalDisplayManager.java index 787a5447..5ed4479c 100644 --- a/packages/react-native-external-display/android/src/oldarch/java/com/externaldisplay/RNExternalDisplayManager.java +++ b/packages/react-native-external-display/android/src/oldarch/java/com/externaldisplay/RNExternalDisplayManager.java @@ -15,6 +15,7 @@ import android.util.DisplayMetrics; import android.view.Display; import android.graphics.Rect; +import android.util.Log; import javax.annotation.Nullable; import java.util.Map; @@ -29,6 +30,8 @@ public class RNExternalDisplayManager extends ViewGroupManager getConstants() { + Log.d("RNExternalDisplayEvent", "RNExternalDisplayModule getConstants"); + HashMap map = new HashMap(); map.put("SCREEN_INFO", ExternalDisplayHelper.getScreenInfo(dm.getDisplays())); return map; From a97159070d5af3cbd113c336536dae4cc87e8a43 Mon Sep 17 00:00:00 2001 From: tarikpo Date: Tue, 3 Dec 2024 10:03:37 +0100 Subject: [PATCH 2/3] decoupled the event logic from component logic. Events when a screen is connected/disconnected will be received even if the external view component is not rendered --- .../ExternalDisplayHelper.java | 171 ++++---- .../RNExternalDisplayPackage.java | 101 +++-- .../RNExternalDisplayView.java | 370 +++++++++--------- .../RNExternalDisplayManager.java | 158 +++----- .../RNExternalDisplayModule.java | 108 +++-- 5 files changed, 475 insertions(+), 433 deletions(-) diff --git a/packages/react-native-external-display/android/src/main/java/com/externaldisplay/ExternalDisplayHelper.java b/packages/react-native-external-display/android/src/main/java/com/externaldisplay/ExternalDisplayHelper.java index a52cf98b..6943d4e1 100644 --- a/packages/react-native-external-display/android/src/main/java/com/externaldisplay/ExternalDisplayHelper.java +++ b/packages/react-native-external-display/android/src/main/java/com/externaldisplay/ExternalDisplayHelper.java @@ -17,6 +17,7 @@ import java.util.Map; import java.util.HashMap; + import android.util.Log; import com.facebook.react.bridge.LifecycleEventListener; @@ -24,93 +25,119 @@ @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1) class ExternalDisplayScreen extends Presentation { - ExternalDisplayScreen(Context ctx, Display display) { - super(ctx, display); - Log.d("RNExternalDisplayEvent", "ExternalDisplayScreen init"); + ExternalDisplayScreen(Context ctx, Display display) { + super(ctx, display); + Log.d("RNExternalDisplayEvent", "ExternalDisplayScreen init"); - } + } - @Override - protected void onCreate(Bundle savedInstanceState) { - Log.d("RNExternalDisplayEvent", "ExternalDisplayScreen onCreate"); + @Override + protected void onCreate(Bundle savedInstanceState) { + Log.d("RNExternalDisplayEvent", "ExternalDisplayScreen onCreate"); - super.onCreate(savedInstanceState); - } + super.onCreate(savedInstanceState); + } } @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1) class ExternalDisplayHelper implements DisplayManager.DisplayListener { - - public static Map getScreenInfo(Display[] displays) { - Log.d("RNExternalDisplayEvent", "ExternalDisplayScreen getScreenInfo"); - - HashMap info = new HashMap(); - for (Display display : displays) { - int displayId = display.getDisplayId(); - if ( - display.getDisplayId() == Display.DEFAULT_DISPLAY || - (display.getFlags() & Display.FLAG_PRESENTATION) == 0 - ) { - continue; - } - HashMap data = new HashMap(); - DisplayMetrics displayMetrics = new DisplayMetrics(); - display.getMetrics(displayMetrics); - data.put("id", displayId); - data.put("width", displayMetrics.widthPixels); - data.put("height", displayMetrics.heightPixels); - info.put(String.valueOf(display.getDisplayId()), data); + private static final String TAG = "RNExternalDisplayEvent"; + private static ExternalDisplayHelper instance = null; + private DisplayManager dm = null; + private Listener listener = null; + private Display displays = null; + + // Private constructor to prevent direct instantiation + private ExternalDisplayHelper(Context context, Listener listener) { + this.listener = listener; + dm = (DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE); + if (dm != null) { + dm.registerDisplayListener(this, null); + } else { + } } - return info; - } - - public interface Listener { - void onDisplayAdded(Display[] displays, int displayId); - void onDisplayChanged(Display[] displays, int displayId); - void onDisplayRemoved(Display[] displays, int displayId); - } - - private Listener listener = null; - private DisplayManager dm = null; - private Display displays = null; - public ExternalDisplayHelper(Context context, Listener listener) { - this.listener = listener; - - dm = (DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE); - dm.registerDisplayListener(this, null); - } - - public Display getDisplay(int displayId) { - Log.d("RNExternalDisplayEvent", "ExternalDisplayScreen getDisplay"); - - return dm.getDisplay(displayId); - } + // Method to initialize the singleton instance + public static synchronized void initialize(Context context, Listener listener) { + if (instance == null) { + instance = new ExternalDisplayHelper(context.getApplicationContext(), listener); + } + } - public Display[] getDisplays() { - Log.d("RNExternalDisplayEvent", "ExternalDisplayScreen getDisplays"); + // Method to get the singleton instance + public static synchronized ExternalDisplayHelper getInstance() { + if (instance == null) { + throw new IllegalStateException("ExternalDisplayHelper is not initialized. Call initialize() first."); + } + return instance; + } - return dm.getDisplays(DisplayManager.DISPLAY_CATEGORY_PRESENTATION); - } + // Method to clean up the singleton instance + public static synchronized void destroy() { + if (instance != null && instance.dm != null) { + instance.dm.unregisterDisplayListener(instance); + instance = null; + } + } + public static Map getScreenInfo(Display[] displays) { + HashMap info = new HashMap<>(); + for (Display display : displays) { + int displayId = display.getDisplayId(); + if ( + display.getDisplayId() == Display.DEFAULT_DISPLAY || + (display.getFlags() & Display.FLAG_PRESENTATION) == 0 + ) { + continue; + } + HashMap data = new HashMap<>(); + DisplayMetrics displayMetrics = new DisplayMetrics(); + display.getMetrics(displayMetrics); + data.put("id", displayId); + data.put("width", displayMetrics.widthPixels); + data.put("height", displayMetrics.heightPixels); + info.put(String.valueOf(display.getDisplayId()), data); + } + return info; + } - @Override - public void onDisplayAdded(int displayId) { - Log.d("RNExternalDisplayEvent", "ExternalDisplayScreen onDisplayAdded"); + @Override + public void onDisplayAdded(int displayId) { + if (listener != null) { + listener.onDisplayAdded(getDisplays(), displayId); + } + } - listener.onDisplayAdded(getDisplays(), displayId); - } + @Override + public void onDisplayChanged(int displayId) { + if (listener != null) { + listener.onDisplayChanged(getDisplays(), displayId); + } + } - @Override - public void onDisplayChanged(int displayId) { - Log.d("RNExternalDisplayEvent", "ExternalDisplayScreen onDisplayChanged"); + @Override + public void onDisplayRemoved(int displayId) { + if (listener != null) { + listener.onDisplayRemoved(getDisplays(), displayId); + } + } - listener.onDisplayChanged(getDisplays(), displayId); - } + public Display getDisplay(int displayId) { + if (dm != null) { + return dm.getDisplay(displayId); + } + return null; + } - @Override - public void onDisplayRemoved(int displayId) { - Log.d("RNExternalDisplayEvent", "ExternalDisplayScreen onDisplayRemoved"); + public Display[] getDisplays() { + if (dm != null) { + return dm.getDisplays(DisplayManager.DISPLAY_CATEGORY_PRESENTATION); + } + return new Display[0]; + } - listener.onDisplayRemoved(getDisplays(), displayId); - } + public interface Listener { + void onDisplayAdded(Display[] displays, int displayId); + void onDisplayChanged(Display[] displays, int displayId); + void onDisplayRemoved(Display[] displays, int displayId); + } } diff --git a/packages/react-native-external-display/android/src/main/java/com/externaldisplay/RNExternalDisplayPackage.java b/packages/react-native-external-display/android/src/main/java/com/externaldisplay/RNExternalDisplayPackage.java index 94c19eb8..32589536 100644 --- a/packages/react-native-external-display/android/src/main/java/com/externaldisplay/RNExternalDisplayPackage.java +++ b/packages/react-native-external-display/android/src/main/java/com/externaldisplay/RNExternalDisplayPackage.java @@ -1,12 +1,14 @@ package com.externaldisplay; import androidx.annotation.Nullable; + import com.facebook.react.bridge.NativeModule; import com.facebook.react.bridge.ReactApplicationContext; import com.facebook.react.module.model.ReactModuleInfo; import com.facebook.react.module.model.ReactModuleInfoProvider; import com.facebook.react.TurboReactPackage; import com.facebook.react.uimanager.ViewManager; + import android.util.Log; import java.util.ArrayList; @@ -16,64 +18,61 @@ import java.util.Map; import android.util.Log; + import com.externaldisplay.RNExternalDisplayManager; import com.externaldisplay.RNExternalDisplayModule; public class RNExternalDisplayPackage extends TurboReactPackage { + private static final String TAG = "RNExternalDisplayEvent"; - @Override - public List createViewManagers(ReactApplicationContext reactContext) { - Log.d("RNExternalDisplayEvent", "RNExternalDisplayPackage createViewManagers"); - - List viewManagers = new ArrayList<>(); - viewManagers.add(new RNExternalDisplayManager(reactContext)); - return viewManagers; - } - @Nullable - @Override - public NativeModule getModule(String name, ReactApplicationContext reactContext) { - Log.d("RNExternalDisplayEvent", "RNExternalDisplayPackage getModule"); - - if (name.equals(RNExternalDisplayModule.REACT_CLASS)) { - return new com.externaldisplay.RNExternalDisplayModule(reactContext); - } else { - return null; + @Override + public List createViewManagers(ReactApplicationContext reactContext) { + List viewManagers = new ArrayList<>(); + viewManagers.add(new RNExternalDisplayManager(reactContext)); + return viewManagers; } - } - @Override - public ReactModuleInfoProvider getReactModuleInfoProvider() { - Log.d("RNExternalDisplayEvent", "RNExternalDisplayPackage getReactModuleInfoProvider"); + @Nullable + @Override + public NativeModule getModule(String name, ReactApplicationContext reactContext) { + if (name.equals(RNExternalDisplayModule.REACT_CLASS)) { + return new RNExternalDisplayModule(reactContext); + } else { + return null; + } + } - return () -> { - final Map moduleInfos = new HashMap<>(); - boolean isTurboModule = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED; - moduleInfos.put( - RNExternalDisplayModule.REACT_CLASS, - new ReactModuleInfo( - RNExternalDisplayModule.REACT_CLASS, - RNExternalDisplayModule.REACT_CLASS, - false, // canOverrideExistingModule - false, // needsEagerInit - true, // hasConstants - false, // isCxxModule - isTurboModule // isTurboModule - ) - ); - moduleInfos.put( - RNExternalDisplayManager.REACT_CLASS, - new ReactModuleInfo( - RNExternalDisplayManager.REACT_CLASS, - RNExternalDisplayManager.REACT_CLASS, - false, // canOverrideExistingModule - false, // needsEagerInit - true, // hasConstants - false, // isCxxModule - isTurboModule // isTurboModule - ) - ); - return moduleInfos; - }; - } + @Override + public ReactModuleInfoProvider getReactModuleInfoProvider() { + return () -> { + final Map moduleInfos = new HashMap<>(); + boolean isTurboModule = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED; + moduleInfos.put( + RNExternalDisplayModule.REACT_CLASS, + new ReactModuleInfo( + RNExternalDisplayModule.REACT_CLASS, + RNExternalDisplayModule.REACT_CLASS, + false, // canOverrideExistingModule + false, // needsEagerInit + true, // hasConstants + false, // isCxxModule + isTurboModule // isTurboModule + ) + ); + moduleInfos.put( + RNExternalDisplayManager.REACT_CLASS, + new ReactModuleInfo( + RNExternalDisplayManager.REACT_CLASS, + RNExternalDisplayManager.REACT_CLASS, + false, // canOverrideExistingModule + false, // needsEagerInit + true, // hasConstants + false, // isCxxModule + isTurboModule // isTurboModule + ) + ); + return moduleInfos; + }; + } } diff --git a/packages/react-native-external-display/android/src/main/java/com/externaldisplay/RNExternalDisplayView.java b/packages/react-native-external-display/android/src/main/java/com/externaldisplay/RNExternalDisplayView.java index c411774f..107e85e7 100644 --- a/packages/react-native-external-display/android/src/main/java/com/externaldisplay/RNExternalDisplayView.java +++ b/packages/react-native-external-display/android/src/main/java/com/externaldisplay/RNExternalDisplayView.java @@ -3,12 +3,16 @@ import android.content.Context; import android.view.View; import android.view.ViewGroup; + import com.facebook.react.ReactRootView; import com.facebook.react.bridge.LifecycleEventListener; import com.facebook.react.bridge.ReactContext; + import android.widget.LinearLayout; + import com.facebook.common.logging.FLog; import com.facebook.react.common.ReactConstants; + import android.util.Log; import android.view.Display; @@ -17,216 +21,214 @@ import java.util.ArrayList; public class RNExternalDisplayView extends ReactRootView implements LifecycleEventListener { - Context context; - private boolean fallbackInMainScreen = false; - private ExternalDisplayHelper helper; - private ExternalDisplayScreen displayScreen; - private int screen = -1; - private ArrayList subviews = new ArrayList(); - private ReactRootView wrap; - private boolean pausedWithDisplayScreen = false; - - public RNExternalDisplayView(Context context, ExternalDisplayHelper helper) { - super(context); - ((ReactContext) context).addLifecycleEventListener(this); - this.context = context; - this.helper = helper; - Log.d("RNExternalDisplayEvent", "RNExternalDisplayView init"); - - } - - @Override - public void addView(View child, int index) { - subviews.add(index, child); - Log.d("RNExternalDisplayEvent", "RNExternalDisplayView addView"); - - updateScreen(); - } - - @Override - protected void onLayout(boolean changed, int l, int t, int r, int b) { - } - - @Override - public int getChildCount() { - Log.d("RNExternalDisplayEvent", "RNExternalDisplayView getChildCount"); - - return subviews.size(); - } - - @Override - public View getChildAt(int index) { - Log.d("RNExternalDisplayEvent", "RNExternalDisplayView getChildAt"); - - return subviews.get(index); - } - - @Override - public void removeView(View view) { - Log.d("RNExternalDisplayEvent", "RNExternalDisplayView removeView"); - - super.removeView(view); - } - - @Override - public void removeViewAt(int index) { - View child = getChildAt(index); - Log.d("RNExternalDisplayEvent", "RNExternalDisplayView removeViewAt"); - - super.removeView(child); - subviews.remove(index); - if (wrap != null) { - for (int i = 0; i < wrap.getChildCount(); i++) { - if (i == index) { - wrap.removeViewAt(i); + private static final String TAG = "RNExternalDisplayEvent"; + private boolean fallbackInMainScreen = false; + private ExternalDisplayHelper helper; + private ExternalDisplayScreen displayScreen; + private int screen = -1; + private ArrayList subviews = new ArrayList(); + private ReactRootView wrap; + private boolean pausedWithDisplayScreen = false; + Context context; + + + public RNExternalDisplayView(Context context, ExternalDisplayHelper helper) { + super(context); + ((ReactContext) context).addLifecycleEventListener(this); + if (helper != null) { + this.helper = helper; + } else { + this.helper = null; } - } } - } - - public void onDropInstance() { - Log.d("RNExternalDisplayEvent", "RNExternalDisplayView onDropInstance"); - - ((ReactContext) getContext()).removeLifecycleEventListener(this); - if (wrap != null && wrap.getChildCount() > 0) { - for (int i = 0; i < wrap.getChildCount(); i++) { - wrap.removeViewAt(i); - } + /** + * Retrieves the singleton ExternalDisplayHelper instance. + * If not available, returns null. + * + * @param context The context. + * @return ExternalDisplayHelper instance or null. + */ + private ExternalDisplayHelper getDefaultHelper(Context context) { + try { + return ExternalDisplayHelper.getInstance(); + } catch (IllegalStateException e) { + return null; + } } - destroyScreen(); - } - @Override - public void addChildrenForAccessibility(ArrayList outChildren) { - // This solves an accessibility bug originally addressed in RN - // Reference: https://github.com/mybigday/react-native-external-display/issues/211 - } + @Override + public void addView(View child, int index) { + subviews.add(index, child); + updateScreen(); + } - @Override - public void onHostResume() { - Log.d("RNExternalDisplayEvent", "RNExternalDisplayView onHostResume"); + @Override + protected void onLayout(boolean changed, int l, int t, int r, int b) { + } - if (displayScreen == null && !pausedWithDisplayScreen) { - return; + @Override + public int getChildCount() { + return subviews.size(); } - pausedWithDisplayScreen = false; - updateScreen(); - } - @Override - public void onHostPause() { - Log.d("RNExternalDisplayEvent", "RNExternalDisplayView onHostPause"); + @Override + public View getChildAt(int index) { + return subviews.get(index); + } - if (displayScreen == null) { - return; + @Override + public void removeView(View view) { + super.removeView(view); } - pausedWithDisplayScreen = true; - if (wrap != null) { - for (int i = 0; i < wrap.getChildCount(); i++) { - wrap.removeViewAt(i); - } + + @Override + public void removeViewAt(int index) { + View child = getChildAt(index); + super.removeView(child); + subviews.remove(index); + if (wrap != null) { + for (int i = 0; i < wrap.getChildCount(); i++) { + if (i == index) { + wrap.removeViewAt(i); + } + } + } } - destroyScreen(); - } - @Override - public void onHostDestroy() { - Log.d("RNExternalDisplayEvent", "RNExternalDisplayView onHostDestroy"); + public void onDropInstance() { + ((ReactContext) getContext()).removeLifecycleEventListener(this); + if (wrap != null && wrap.getChildCount() > 0) { + for (int i = 0; i < wrap.getChildCount(); i++) { + wrap.removeViewAt(i); + } + } + destroyScreen(); + } - onDropInstance(); - } + @Override + public void addChildrenForAccessibility(ArrayList outChildren) { + // This solves an accessibility bug originally addressed in RN + // Reference: https://github.com/mybigday/react-native-external-display/issues/211 + } - public void updateScreen() { - Log.d("RNExternalDisplayEvent", "RNExternalDisplayView updateScreen"); + @Override + public void onHostResume() { + if (displayScreen == null && !pausedWithDisplayScreen) { + return; + } + pausedWithDisplayScreen = false; + updateScreen(); + } - if (getChildCount() == 0) return; - - if (screen > 0) { - Display display = helper.getDisplay(screen); - if (display != null) { + @Override + public void onHostPause() { if (displayScreen == null) { - displayScreen = new ExternalDisplayScreen(context, display); - wrap = new ReactRootView(context); - } else if (wrap.getChildCount() > 0) { - for (int i = 0; i < wrap.getChildCount(); i++) { - wrap.removeViewAt(i); - } - } - for (int i = 0; i < subviews.size(); i++) { - View subview = subviews.get(i); - if (subview.getParent() != null) { - // Make sure removed from parent - ((ViewGroup) subview.getParent()).removeView(subview); - } - wrap.addView(subview, i); + return; } - displayScreen.setContentView(wrap); - displayScreen.show(); - return; - } - } - if (fallbackInMainScreen == true) { - if (wrap != null) { - for (int i = 0; i < wrap.getChildCount(); i++) { - wrap.removeViewAt(i); + pausedWithDisplayScreen = true; + if (wrap != null) { + for (int i = 0; i < wrap.getChildCount(); i++) { + wrap.removeViewAt(i); + } } - } - for (int i = 0; i < subviews.size(); i++) { - View subview = subviews.get(i); - if (subview.getParent() != null) { - // Make sure removed from parent - ((ViewGroup) subview.getParent()).removeView(subview); - } - super.addView(subview, i); - } + destroyScreen(); } - } - private void destroyScreen() { - Log.d("RNExternalDisplayEvent", "RNExternalDisplayView destroyScreen"); - - if (displayScreen != null) { - displayScreen.hide(); - displayScreen.dismiss(); - displayScreen = null; - wrap = null; + @Override + public void onHostDestroy() { + onDropInstance(); } - } - public void setScreen(String screen) { - Log.d("RNExternalDisplayEvent", "RNExternalDisplayView setScreen"); + public void updateScreen() { + if (getChildCount() == 0) return; + + if (screen > 0 && helper != null) { + Display display = helper.getDisplay(screen); + if (display != null) { + if (displayScreen == null) { + displayScreen = new ExternalDisplayScreen(getContext(), display); + wrap = new ReactRootView(getContext()); + } else if (wrap.getChildCount() > 0) { + for (int i = 0; i < wrap.getChildCount(); i++) { + wrap.removeViewAt(i); + } + } + for (int i = 0; i < subviews.size(); i++) { + View subview = subviews.get(i); + if (subview.getParent() != null) { + // Make sure removed from parent + ((ViewGroup) subview.getParent()).removeView(subview); + } + wrap.addView(subview, i); + } + try { + displayScreen.setContentView(wrap); + displayScreen.show(); + } catch (Exception e) { + } + return; + }else { + Log.e(TAG, "Display with ID " + screen + " not found."); + } + } - if (getChildCount() > 0 && wrap != null && wrap.getChildCount() > 0) { - for (int i = 0; i < wrap.getChildCount(); i++) { - wrap.removeViewAt(i); - } - } else { - for (View subview : subviews) { - removeView(subview); - } - } - try { - int nextScreen = Integer.parseInt(screen); - if (nextScreen != this.screen) { - destroyScreen(); - } - this.screen = nextScreen; - } catch (NumberFormatException e) { - destroyScreen(); - this.screen = -1; + if (fallbackInMainScreen) { + if (wrap != null) { + for (int i = 0; i < wrap.getChildCount(); i++) { + wrap.removeViewAt(i); + } + } + for (int i = 0; i < subviews.size(); i++) { + View subview = subviews.get(i); + if (subview.getParent() != null) { + // Make sure removed from parent + ((ViewGroup) subview.getParent()).removeView(subview); + } + super.addView(subview, i); + } + } } - updateScreen(); - } - public int getScreen() { - Log.d("RNExternalDisplayEvent", "RNExternalDisplayView getScreen"); + private void destroyScreen() { + if (displayScreen != null) { + try { + displayScreen.hide(); + displayScreen.dismiss(); + } catch (Exception e) { + } + displayScreen = null; + wrap = null; + } + } - return this.screen; - } + public void setScreen(String screen) { + if (getChildCount() > 0 && wrap != null && wrap.getChildCount() > 0) { + for (int i = 0; i < wrap.getChildCount(); i++) { + wrap.removeViewAt(i); + } + } else { + for (View subview : subviews) { + removeView(subview); + } + } + try { + int nextScreen = Integer.parseInt(screen); + if (nextScreen != this.screen) { + destroyScreen(); + } + this.screen = nextScreen; + } catch (NumberFormatException e) { + destroyScreen(); + this.screen = -1; + } + updateScreen(); + } - public void setFallbackInMainScreen(boolean value) { - Log.d("RNExternalDisplayEvent", "RNExternalDisplayView setFallbackInMainScreen"); + public int getScreen() { + return this.screen; + } - this.fallbackInMainScreen = value; - } + public void setFallbackInMainScreen(boolean value) { + this.fallbackInMainScreen = value; + } } diff --git a/packages/react-native-external-display/android/src/oldarch/java/com/externaldisplay/RNExternalDisplayManager.java b/packages/react-native-external-display/android/src/oldarch/java/com/externaldisplay/RNExternalDisplayManager.java index 5ed4479c..98149dd0 100644 --- a/packages/react-native-external-display/android/src/oldarch/java/com/externaldisplay/RNExternalDisplayManager.java +++ b/packages/react-native-external-display/android/src/oldarch/java/com/externaldisplay/RNExternalDisplayManager.java @@ -16,117 +16,75 @@ import android.view.Display; import android.graphics.Rect; import android.util.Log; - +import com.externaldisplay.RNExternalDisplayModule; import javax.annotation.Nullable; + import java.util.Map; import java.util.HashMap; -public class RNExternalDisplayManager extends ViewGroupManager implements ExternalDisplayHelper.Listener { - public static final String REACT_CLASS = "RNExternalDisplay"; - private ExternalDisplayHelper helper; - private ReactApplicationContext reactContext; - private Map views = new HashMap(); - - public RNExternalDisplayManager(ReactApplicationContext reactContext) { - super(); - this.reactContext = reactContext; - Log.d("RNExternalDisplayEvent", "RNExternalDisplayManager init"); - - } - - @Override - public String getName() { - return REACT_CLASS; - } +public class RNExternalDisplayManager extends ViewGroupManager { + public static final String REACT_CLASS = "RNExternalDisplay"; + private static final String TAG = "RNExternalDisplayEvent"; + private ReactApplicationContext reactContext; + //private Map views = new HashMap(); - @Override - public RNExternalDisplayView createViewInstance(ThemedReactContext context) { - Log.d("RNExternalDisplayEvent", "RNExternalDisplayManager createViewInstance"); - - if (this.helper == null) { - this.helper = new ExternalDisplayHelper(reactContext, this); + public RNExternalDisplayManager(ReactApplicationContext reactContext) { + super(); + this.reactContext = reactContext; } - RNExternalDisplayView view = new RNExternalDisplayView(context, this.helper); - views.put(view, view); - return view; - } - - @Override - public void onDropViewInstance(RNExternalDisplayView view) { - Log.d("RNExternalDisplayEvent", "RNExternalDisplayManager onDropViewInstance"); - - views.remove(view); - super.onDropViewInstance(view); - view.onDropInstance(); - } - private void checkScreen() { - Log.d("RNExternalDisplayEvent", "RNExternalDisplayManager checkScreen"); - - int screenId = -1; - for (RNExternalDisplayView view : views.values()) { - int viewScreenId = view.getScreen(); - if (viewScreenId > 0 && screenId == viewScreenId) { - // TODO: Log to console - FLog.e(ReactConstants.TAG, "Detected two or more RNExternalDisplayView to register the same screen id: " + screenId); - } - if (viewScreenId > 0) { - screenId = viewScreenId; - } + @Override + public String getName() { + return REACT_CLASS; } - } - - @ReactProp(name = "screen") - public void setScreen(RNExternalDisplayView view, @Nullable String screen) { - Log.d("RNExternalDisplayEvent", "RNExternalDisplayManager setScreen"); - view.setScreen(screen); - checkScreen(); - } - - @ReactProp(name = "fallbackInMainScreen", defaultBoolean = false) - public void setFallbackInMainScreen(RNExternalDisplayView view, boolean fallbackInMainScreen) { - Log.d("RNExternalDisplayEvent", "RNExternalDisplayManager setFallbackInMainScreen"); - - view.setFallbackInMainScreen(fallbackInMainScreen); - } - - private void sendEvent(String eventName, @Nullable WritableMap params) { - Log.d("RNExternalDisplayEvent", "RNExternalDisplayManager sendEvent:"+eventName); - - reactContext - .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class) - .emit(eventName, params); - } + @Override + public RNExternalDisplayView createViewInstance(ThemedReactContext context) { + // Retrieve the module to access the helper + RNExternalDisplayModule module = context.getNativeModule(RNExternalDisplayModule.class); + ExternalDisplayHelper helper = null; + if (module != null) { + helper = module.getExternalDisplayHelper(); + } else { + } + + RNExternalDisplayView view = new RNExternalDisplayView(context, helper); + return view; + } - public void onDisplayAdded(Display[] displays, int displayId) { - Log.d("RNExternalDisplayEvent", "RNExternalDisplayManager onDisplayAdded:"+displayId); + @Override + public void onDropViewInstance(RNExternalDisplayView view) { + //views.remove(view); + super.onDropViewInstance(view); + view.onDropInstance(); + } +/* + private void checkScreen() { + Log.d("RNExternalDisplayEvent", "RNExternalDisplayManager checkScreen"); + + int screenId = -1; + for (RNExternalDisplayView view : views.values()) { + int viewScreenId = view.getScreen(); + if (viewScreenId > 0 && screenId == viewScreenId) { + // TODO: Log to console + FLog.e(ReactConstants.TAG, "Detected two or more RNExternalDisplayView to register the same screen id: " + screenId); + } + if (viewScreenId > 0) { + screenId = viewScreenId; + } + } + } - sendEvent( - "@RNExternalDisplay_screenDidConnect", - Arguments.makeNativeMap( - ExternalDisplayHelper.getScreenInfo(displays) - ) - ); - } - public void onDisplayChanged(Display[] displays, int displayId) { - Log.d("RNExternalDisplayEvent", "RNExternalDisplayManager onDisplayChanged:"+displayId); + */ - sendEvent( - "@RNExternalDisplay_screenDidChange", - Arguments.makeNativeMap( - ExternalDisplayHelper.getScreenInfo(displays) - ) - ); - } - public void onDisplayRemoved(Display[] displays, int displayId) { - Log.d("RNExternalDisplayEvent", "RNExternalDisplayManager onDisplayRemoved:"+displayId); + @ReactProp(name = "screen") + public void setScreen(RNExternalDisplayView view, String screen) { + view.setScreen(screen); + //checkScreen(); + } - sendEvent( - "@RNExternalDisplay_screenDidDisconnect", - Arguments.makeNativeMap( - ExternalDisplayHelper.getScreenInfo(displays) - ) - ); - } + @ReactProp(name = "fallbackInMainScreen", defaultBoolean = false) + public void setFallbackInMainScreen(RNExternalDisplayView view, boolean fallbackInMainScreen) { + view.setFallbackInMainScreen(fallbackInMainScreen); + } } diff --git a/packages/react-native-external-display/android/src/oldarch/java/com/externaldisplay/RNExternalDisplayModule.java b/packages/react-native-external-display/android/src/oldarch/java/com/externaldisplay/RNExternalDisplayModule.java index 28c368a7..2029f7d0 100644 --- a/packages/react-native-external-display/android/src/oldarch/java/com/externaldisplay/RNExternalDisplayModule.java +++ b/packages/react-native-external-display/android/src/oldarch/java/com/externaldisplay/RNExternalDisplayModule.java @@ -1,6 +1,7 @@ package com.externaldisplay; import android.content.Context; + import com.facebook.react.bridge.ReactApplicationContext; import com.facebook.react.bridge.ReactContextBaseJavaModule; import com.facebook.react.bridge.ReactMethod; @@ -12,29 +13,84 @@ import java.util.Map; import java.util.HashMap; -public class RNExternalDisplayModule extends ReactContextBaseJavaModule { - public static final String REACT_CLASS = "RNExternalDisplayEvent"; - private ReactApplicationContext reactContext = null; - private DisplayManager dm = null; - - public RNExternalDisplayModule(ReactApplicationContext context) { - super(context); - Log.d("RNExternalDisplayEvent", "RNExternalDisplayModule init"); - reactContext = context; - dm = (DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE); - } - - @Override - public String getName() { - return REACT_CLASS; - } - - @Override - public Map getConstants() { - Log.d("RNExternalDisplayEvent", "RNExternalDisplayModule getConstants"); - - HashMap map = new HashMap(); - map.put("SCREEN_INFO", ExternalDisplayHelper.getScreenInfo(dm.getDisplays())); - return map; - } -} \ No newline at end of file +import com.facebook.react.bridge.WritableMap; +import com.facebook.react.module.annotations.ReactModule; +import com.facebook.react.modules.core.DeviceEventManagerModule; +import com.facebook.react.bridge.Arguments; + +@ReactModule(name = RNExternalDisplayModule.REACT_CLASS) // Added Annotation +public class RNExternalDisplayModule extends ReactContextBaseJavaModule implements ExternalDisplayHelper.Listener { + public static final String REACT_CLASS = "RNExternalDisplayEvent"; + private static final String TAG = "RNExternalDisplayEvent"; + + private ReactApplicationContext reactContext = null; + + public RNExternalDisplayModule(ReactApplicationContext context) { + super(context); + this.reactContext = context; + // Initialize ExternalDisplayHelper singleton + ExternalDisplayHelper.initialize(context, this); + } + + @Override + public String getName() { + return REACT_CLASS; + } + + @Override + public Map getConstants() { + HashMap map = new HashMap<>(); + try { + map.put("SCREEN_INFO", ExternalDisplayHelper.getScreenInfo(ExternalDisplayHelper.getInstance().getDisplays())); + } catch (IllegalStateException e) { + map.put("SCREEN_INFO", new HashMap()); + } + return map; + } + + private void sendEvent(String eventName, WritableMap params) { + reactContext + .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class) + .emit(eventName, params); + } + + @Override + public void onDisplayAdded(Display[] displays, int displayId) { + sendEvent( + "@RNExternalDisplay_screenDidConnect", + Arguments.makeNativeMap(ExternalDisplayHelper.getScreenInfo(displays)) + ); + } + + @Override + public void onDisplayChanged(Display[] displays, int displayId) { + sendEvent( + "@RNExternalDisplay_screenDidChange", + Arguments.makeNativeMap(ExternalDisplayHelper.getScreenInfo(displays)) + ); + } + + @Override + public void onDisplayRemoved(Display[] displays, int displayId) { + sendEvent( + "@RNExternalDisplay_screenDidDisconnect", + Arguments.makeNativeMap(ExternalDisplayHelper.getScreenInfo(displays)) + ); + } + + @Override + public void onCatalystInstanceDestroy() { + super.onCatalystInstanceDestroy(); + // Clean up the ExternalDisplayHelper singleton + ExternalDisplayHelper.destroy(); + } + + // Optional: Provide a getter for ExternalDisplayHelper + public ExternalDisplayHelper getExternalDisplayHelper() { + try { + return ExternalDisplayHelper.getInstance(); + } catch (IllegalStateException e) { + return null; + } + } +} From 59d43eaf0898e5fb823cead3ed86350a0ebf7062 Mon Sep 17 00:00:00 2001 From: Dmitriy Grachev Date: Thu, 15 May 2025 12:40:19 +0300 Subject: [PATCH 3/3] fix `Can't add "react-native-external-display": invalid package version undefined.` --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index 12ad5324..7ec7b009 100644 --- a/package.json +++ b/package.json @@ -4,6 +4,7 @@ "workspaces": [ "packages/*" ], + "version": "0.6.6", "packageManager": "yarn@1.22.22", "scripts": { "lint": "eslint .",