Skip to content

Commit 336fbf7

Browse files
committed
Bug 1989603 - Get display information from View's display id. r=geckoview-reviewers,ohall
Actually, we always get the display information on default display. But when using Samsung DeX, the application can show on non-default display. So we should get the display information from the View's display id. This issue is device dependent issue, so there is no way to add a unit test for this. Differential Revision: https://phabricator.services.mozilla.com/D281610
1 parent 64824ca commit 336fbf7

3 files changed

Lines changed: 149 additions & 74 deletions

File tree

mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoAppShell.java

Lines changed: 131 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -841,7 +841,7 @@ private static synchronized int getDpi() {
841841
if (sDensityDpiOverride != 0) {
842842
return sDensityDpiOverride;
843843
}
844-
return sScreenCompat.getDensityDpi();
844+
return sScreenCompat.getDensityDpi(sDisplayId);
845845
}
846846

847847
public static synchronized void setDisplayDensityOverride(@Nullable final Float density) {
@@ -861,7 +861,7 @@ private static synchronized float getDensity() {
861861
return sDensityOverride;
862862
}
863863

864-
return sScreenCompat.getDensity();
864+
return sScreenCompat.getDensity(sDisplayId);
865865
}
866866

867867
private static int sTotalRam;
@@ -900,9 +900,7 @@ public static synchronized int getScreenDepth() {
900900
sScreenDepth = 16;
901901
final Context applicationContext = getApplicationContext();
902902
final PixelFormat info = new PixelFormat();
903-
final WindowManager wm =
904-
(WindowManager) applicationContext.getSystemService(Context.WINDOW_SERVICE);
905-
PixelFormat.getPixelFormatInfo(wm.getDefaultDisplay().getPixelFormat(), info);
903+
PixelFormat.getPixelFormatInfo(sScreenCompat.getDisplay(sDisplayId).getPixelFormat(), info);
906904
if (info.bitsPerPixel >= 24 && isHighMemoryDevice(applicationContext)) {
907905
sScreenDepth = sUseMaxScreenDepth ? info.bitsPerPixel : 24;
908906
}
@@ -912,14 +910,12 @@ public static synchronized int getScreenDepth() {
912910
}
913911

914912
@WrapForJNI(calledFrom = "gecko")
915-
public static synchronized float getScreenRefreshRate() {
913+
private static synchronized float getScreenRefreshRate() {
916914
if (sScreenRefreshRate != null) {
917915
return sScreenRefreshRate;
918916
}
919917

920-
final WindowManager wm =
921-
(WindowManager) getApplicationContext().getSystemService(Context.WINDOW_SERVICE);
922-
final float refreshRate = wm.getDefaultDisplay().getRefreshRate();
918+
final float refreshRate = sScreenCompat.getDisplay(sDisplayId).getRefreshRate();
923919
// Android 11+ supports multiple refresh rate. So we have to get refresh rate per call.
924920
// https://source.android.com/docs/core/graphics/multiple-refresh-rate
925921
if (Build.VERSION.SDK_INT < 30) {
@@ -931,9 +927,7 @@ public static synchronized float getScreenRefreshRate() {
931927

932928
@WrapForJNI(calledFrom = "gecko")
933929
private static boolean hasHDRScreen() {
934-
final Display display =
935-
((DisplayManager) getApplicationContext().getSystemService(Context.DISPLAY_SERVICE))
936-
.getDisplay(Display.DEFAULT_DISPLAY);
930+
final Display display = sScreenCompat.getDisplay(sDisplayId);
937931
return display != null && display.isHdr();
938932
}
939933

@@ -1307,7 +1301,7 @@ private static short getScreenOrientation() {
13071301
}
13081302

13091303
/* package */ static int getRotation() {
1310-
return sScreenCompat.getRotation();
1304+
return sScreenCompat.getRotation(sDisplayId);
13111305
}
13121306

13131307
@WrapForJNI(calledFrom = "gecko")
@@ -1486,13 +1480,17 @@ public static synchronized void setScreenSizeOverride(final Rect size) {
14861480
static final ScreenCompat sScreenCompat;
14871481

14881482
private interface ScreenCompat {
1489-
Rect getScreenSize();
1483+
Rect getScreenSize(int displayId);
14901484

1491-
int getRotation();
1485+
int getRotation(int displayId);
14921486

1493-
int getDensityDpi();
1487+
int getDensityDpi(int displayId);
14941488

1495-
float getDensity();
1489+
float getDensity(int displayId);
1490+
1491+
Display getDisplay(int displayId);
1492+
1493+
void onDisplayRemoved(int displayId);
14961494
}
14971495

14981496
private static class JellyBeanMR1ScreenCompat implements ScreenCompat {
@@ -1504,94 +1502,143 @@ private static DisplayMetrics getDisplayMetrics() {
15041502
}
15051503

15061504
@Override
1507-
public Rect getScreenSize() {
1508-
final WindowManager wm =
1509-
(WindowManager) getApplicationContext().getSystemService(Context.WINDOW_SERVICE);
1510-
final Display disp = wm.getDefaultDisplay();
1505+
public Rect getScreenSize(final int displayId) {
1506+
final Display disp = getDisplay(displayId);
15111507
final Point size = new Point();
15121508
disp.getRealSize(size);
15131509
return new Rect(0, 0, size.x, size.y);
15141510
}
15151511

15161512
@Override
1517-
public int getRotation() {
1518-
final WindowManager wm =
1519-
(WindowManager) getApplicationContext().getSystemService(Context.WINDOW_SERVICE);
1520-
return wm.getDefaultDisplay().getRotation();
1513+
public int getRotation(final int displayId) {
1514+
return getDisplay(displayId).getRotation();
15211515
}
15221516

15231517
@Override
1524-
public int getDensityDpi() {
1518+
public int getDensityDpi(final int displayId) {
15251519
if (mDensityDpi == 0) {
15261520
mDensityDpi = getDisplayMetrics().densityDpi;
15271521
}
15281522
return mDensityDpi;
15291523
}
15301524

15311525
@Override
1532-
public float getDensity() {
1526+
public float getDensity(final int displayId) {
15331527
if (mDensity == null) {
15341528
mDensity = getDisplayMetrics().density;
15351529
}
15361530
return mDensity;
15371531
}
1532+
1533+
@Override
1534+
public Display getDisplay(final int displayId) {
1535+
final DisplayManager displayManager =
1536+
(DisplayManager) getApplicationContext().getSystemService(Context.DISPLAY_SERVICE);
1537+
final Display display = displayManager.getDisplay(displayId);
1538+
if (display != null) {
1539+
return display;
1540+
}
1541+
if (displayId != Display.DEFAULT_DISPLAY) {
1542+
return getDisplay(Display.DEFAULT_DISPLAY);
1543+
}
1544+
// No display found even if default display. This should not happen.
1545+
throw new RuntimeException("No default display found");
1546+
}
1547+
1548+
@Override
1549+
public void onDisplayRemoved(final int displayId) {}
15381550
}
15391551

15401552
@RequiresApi(Build.VERSION_CODES.S)
15411553
private static class AndroidSScreenCompat implements ScreenCompat {
15421554
@SuppressLint("StaticFieldLeak")
1543-
private static Context sWindowContext;
1544-
1545-
private static Context getWindowContext() {
1546-
if (sWindowContext == null) {
1547-
final DisplayManager displayManager =
1548-
(DisplayManager) getApplicationContext().getSystemService(Context.DISPLAY_SERVICE);
1549-
final Display display = displayManager.getDisplay(Display.DEFAULT_DISPLAY);
1550-
sWindowContext =
1551-
getApplicationContext()
1552-
.createWindowContext(display, WindowManager.LayoutParams.TYPE_APPLICATION, null);
1553-
sWindowContext.registerComponentCallbacks(
1554-
new ComponentCallbacks() {
1555-
@Override
1556-
public void onConfigurationChanged(final Configuration newConfig) {
1557-
if (GeckoScreenOrientation.getInstance().update()) {
1558-
// refreshScreenInfo is already called.
1559-
return;
1560-
}
1561-
ScreenManagerHelper.refreshScreenInfo();
1562-
}
1563-
1564-
@Override
1565-
public void onLowMemory() {}
1566-
});
1555+
private final SimpleArrayMap<Integer, Context> mWindowContextMap = new SimpleArrayMap<>();
1556+
1557+
private final ComponentCallbacks mComponentCallbacks =
1558+
new ComponentCallbacks() {
1559+
@Override
1560+
public void onConfigurationChanged(final Configuration newConfig) {
1561+
if (GeckoScreenOrientation.getInstance().update()) {
1562+
// refreshScreenInfo is already called.
1563+
return;
1564+
}
1565+
ScreenManagerHelper.refreshScreenInfo();
1566+
}
1567+
1568+
@Override
1569+
public void onLowMemory() {}
1570+
};
1571+
1572+
private synchronized Context getWindowContext(final int displayId) {
1573+
Context windowContext = mWindowContextMap.get(displayId);
1574+
if (windowContext != null) {
1575+
return windowContext;
15671576
}
1568-
return sWindowContext;
1577+
1578+
final DisplayManager displayManager =
1579+
(DisplayManager) getApplicationContext().getSystemService(Context.DISPLAY_SERVICE);
1580+
final Display display = displayManager.getDisplay(displayId);
1581+
if (display == null) {
1582+
if (displayId != Display.DEFAULT_DISPLAY) {
1583+
return getWindowContext(Display.DEFAULT_DISPLAY);
1584+
}
1585+
// No display found even if default display. This should not happen.
1586+
throw new RuntimeException("No default display found");
1587+
}
1588+
windowContext =
1589+
getApplicationContext()
1590+
.createWindowContext(display, WindowManager.LayoutParams.TYPE_APPLICATION, null);
1591+
windowContext.registerComponentCallbacks(mComponentCallbacks);
1592+
mWindowContextMap.put(displayId, windowContext);
1593+
1594+
return windowContext;
15691595
}
15701596

1571-
private static DisplayMetrics getDisplayMetrics() {
1572-
return getWindowContext().getResources().getDisplayMetrics();
1597+
private DisplayMetrics getDisplayMetrics(final int displayId) {
1598+
return getWindowContext(displayId).getResources().getDisplayMetrics();
15731599
}
15741600

15751601
@Override
1576-
public Rect getScreenSize() {
1577-
final WindowManager windowManager = getWindowContext().getSystemService(WindowManager.class);
1602+
public Rect getScreenSize(final int displayId) {
1603+
final WindowManager windowManager =
1604+
getWindowContext(displayId).getSystemService(WindowManager.class);
15781605
return windowManager.getCurrentWindowMetrics().getBounds();
15791606
}
15801607

15811608
@Override
1582-
public int getRotation() {
1583-
final WindowManager windowManager = getWindowContext().getSystemService(WindowManager.class);
1584-
return windowManager.getDefaultDisplay().getRotation();
1609+
public int getRotation(final int displayId) {
1610+
return getDisplay(displayId).getRotation();
1611+
}
1612+
1613+
@Override
1614+
public int getDensityDpi(final int displayId) {
1615+
return getDisplayMetrics(displayId).densityDpi;
1616+
}
1617+
1618+
@Override
1619+
public float getDensity(final int displayId) {
1620+
return getDisplayMetrics(displayId).density;
15851621
}
15861622

15871623
@Override
1588-
public int getDensityDpi() {
1589-
return getDisplayMetrics().densityDpi;
1624+
public Display getDisplay(final int displayId) {
1625+
final Display display = getWindowContext(displayId).getDisplay();
1626+
if (display != null) {
1627+
return display;
1628+
}
1629+
if (displayId != Display.DEFAULT_DISPLAY) {
1630+
return getWindowContext(Display.DEFAULT_DISPLAY).getDisplay();
1631+
}
1632+
// No display found even if default display. This should not happen.
1633+
throw new RuntimeException("No default display found");
15901634
}
15911635

15921636
@Override
1593-
public float getDensity() {
1594-
return getDisplayMetrics().density;
1637+
public synchronized void onDisplayRemoved(final int displayId) {
1638+
final Context context = mWindowContextMap.remove(displayId);
1639+
if (context != null) {
1640+
context.unregisterComponentCallbacks(mComponentCallbacks);
1641+
}
15951642
}
15961643
}
15971644

@@ -1603,8 +1650,11 @@ public float getDensity() {
16031650
}
16041651
}
16051652

1653+
/** The display id that is associated with the GeckoView object. */
1654+
private static volatile int sDisplayId = Display.DEFAULT_DISPLAY;
1655+
16061656
/* package */ static Rect getScreenSizeIgnoreOverride() {
1607-
return sScreenCompat.getScreenSize();
1657+
return sScreenCompat.getScreenSize(sDisplayId);
16081658
}
16091659

16101660
@WrapForJNI(calledFrom = "gecko")
@@ -1616,6 +1666,23 @@ private static synchronized Rect getScreenSize() {
16161666
return getScreenSizeIgnoreOverride();
16171667
}
16181668

1669+
/* package */ static void onDisplayRemoved(final int displayId) {
1670+
sScreenCompat.onDisplayRemoved(displayId);
1671+
}
1672+
1673+
/* package */ static int getDisplayId() {
1674+
return sDisplayId;
1675+
}
1676+
1677+
/**
1678+
* Set the display id that is associated with the GeckoView object.
1679+
*
1680+
* @param displayId The display id.
1681+
*/
1682+
public static void setDisplayId(final int displayId) {
1683+
sDisplayId = displayId;
1684+
}
1685+
16191686
@WrapForJNI(calledFrom = "any")
16201687
public static int getAudioOutputFramesPerBuffer() {
16211688
if (BuildConfig.DEBUG_BUILD && isIsolatedProcess()) {

mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoScreenChangeListener.java

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
import android.content.Context;
99
import android.hardware.display.DisplayManager;
1010
import android.util.Log;
11-
import android.view.Display;
1211
import org.mozilla.gecko.util.ThreadUtils;
1312

1413
public class GeckoScreenChangeListener implements DisplayManager.DisplayListener {
@@ -23,7 +22,13 @@ public GeckoScreenChangeListener() {}
2322
public void onDisplayAdded(final int displayId) {}
2423

2524
@Override
26-
public void onDisplayRemoved(final int displayId) {}
25+
public void onDisplayRemoved(final int displayId) {
26+
if (DEBUG) {
27+
Log.d(LOGTAG, "onDisplayRemoved");
28+
}
29+
30+
GeckoAppShell.onDisplayRemoved(displayId);
31+
}
2732

2833
@Override
2934
public void onDisplayChanged(final int displayId) {
@@ -33,9 +38,9 @@ public void onDisplayChanged(final int displayId) {
3338

3439
// Even if onDisplayChanged is called, Configuration may not updated yet.
3540
// So we use Display's data instead.
36-
if (displayId != Display.DEFAULT_DISPLAY) {
41+
if (displayId != GeckoAppShell.getDisplayId()) {
3742
if (DEBUG) {
38-
Log.d(LOGTAG, "Primary display is only supported");
43+
Log.d(LOGTAG, "The display that GeckoView is attached is only supported");
3944
}
4045
return;
4146
}

mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoView.java

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@
6363
import java.util.Objects;
6464
import org.mozilla.gecko.AndroidGamepadManager;
6565
import org.mozilla.gecko.EventDispatcher;
66+
import org.mozilla.gecko.GeckoAppShell;
6667
import org.mozilla.gecko.InputMethods;
6768
import org.mozilla.gecko.SurfaceViewWrapper;
6869
import org.mozilla.gecko.util.ThreadUtils;
@@ -719,12 +720,6 @@ public void onAttachedToWindow() {
719720
if (mIsSessionPoisoned) {
720721
throw new IllegalStateException("Trying to display a view with invalid session.");
721722
}
722-
if (mSession != null) {
723-
final GeckoRuntime runtime = mSession.getRuntime();
724-
if (runtime != null) {
725-
runtime.orientationChanged();
726-
}
727-
}
728723

729724
if (mSession != null) {
730725
mDisplay.acquire(mSession.acquireDisplay());
@@ -735,6 +730,14 @@ public void onAttachedToWindow() {
735730
// This needs to be called after the `super.onAttachedToWindow()`.
736731
addWindowInsetsListener(KEYBOARD_WINDOW_INSETS_LISTENER, mDisplay);
737732
attachWindowInsetsListener(getActivityFromContext(getContext()));
733+
GeckoAppShell.setDisplayId(getDisplay().getDisplayId());
734+
735+
if (mSession != null) {
736+
final GeckoRuntime runtime = mSession.getRuntime();
737+
if (runtime != null) {
738+
runtime.orientationChanged();
739+
}
740+
}
738741
}
739742

740743
@Override

0 commit comments

Comments
 (0)