summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/hardware/display/DisplayTopology.java64
-rw-r--r--core/tests/coretests/src/android/hardware/display/DisplayTopologyTest.kt29
-rw-r--r--services/core/java/com/android/server/display/DisplayTopologyCoordinator.java9
-rw-r--r--services/tests/displayservicetests/src/com/android/server/display/DisplayTopologyCoordinatorTest.kt8
4 files changed, 91 insertions, 19 deletions
diff --git a/core/java/android/hardware/display/DisplayTopology.java b/core/java/android/hardware/display/DisplayTopology.java
index ba5dfc094afb..da9d4f472bb6 100644
--- a/core/java/android/hardware/display/DisplayTopology.java
+++ b/core/java/android/hardware/display/DisplayTopology.java
@@ -27,10 +27,12 @@ import android.graphics.PointF;
import android.graphics.RectF;
import android.os.Parcel;
import android.os.Parcelable;
+import android.util.DisplayMetrics;
import android.util.IndentingPrintWriter;
import android.util.MathUtils;
import android.util.Pair;
import android.util.Slog;
+import android.util.SparseArray;
import android.view.Display;
import androidx.annotation.NonNull;
@@ -75,6 +77,24 @@ public final class DisplayTopology implements Parcelable {
};
/**
+ * @param px The value in logical pixels
+ * @param dpi The logical density of the display
+ * @return The value in density-independent pixels
+ */
+ public static float pxToDp(float px, int dpi) {
+ return px * DisplayMetrics.DENSITY_DEFAULT / dpi;
+ }
+
+ /**
+ * @param dp The value in density-independent pixels
+ * @param dpi The logical density of the display
+ * @return The value in logical pixels
+ */
+ public static float dpToPx(float dp, int dpi) {
+ return dp * dpi / DisplayMetrics.DENSITY_DEFAULT;
+ }
+
+ /**
* The topology tree
*/
@Nullable
@@ -474,6 +494,22 @@ public final class DisplayTopology implements Parcelable {
return new DisplayTopology(rootCopy, mPrimaryDisplayId);
}
+ /**
+ * Assign absolute bounds to each display. The top-left corner of the root is at position
+ * (0, 0).
+ * @return Map from logical display ID to the display's absolute bounds
+ */
+ public SparseArray<RectF> getAbsoluteBounds() {
+ Map<TreeNode, RectF> bounds = new HashMap<>();
+ getInfo(bounds, /* depths= */ null, /* parents= */ null, mRoot, /* x= */ 0, /* y= */ 0,
+ /* depth= */ 0);
+ SparseArray<RectF> boundsById = new SparseArray<>();
+ for (Map.Entry<TreeNode, RectF> entry : bounds.entrySet()) {
+ boundsById.append(entry.getKey().mDisplayId, entry.getValue());
+ }
+ return boundsById;
+ }
+
@Override
public int describeContents() {
return 0;
@@ -575,7 +611,7 @@ public final class DisplayTopology implements Parcelable {
}
@Nullable
- private static TreeNode findDisplay(int displayId, TreeNode startingNode) {
+ private static TreeNode findDisplay(int displayId, @Nullable TreeNode startingNode) {
if (startingNode == null) {
return null;
}
@@ -592,8 +628,8 @@ public final class DisplayTopology implements Parcelable {
}
/**
- * Get information about the topology that will be used for the normalization algorithm.
- * Assigns origins to each display to compute the bounds.
+ * Get information about the topology.
+ * Assigns positions to each display to compute the bounds. The root is at position (0, 0).
* @param bounds The map where the bounds of each display will be put
* @param depths The map where the depths of each display in the tree will be put
* @param parents The map where the parent of each display will be put
@@ -602,12 +638,22 @@ public final class DisplayTopology implements Parcelable {
* @param y The starting y position
* @param depth The starting depth
*/
- private static void getInfo(Map<TreeNode, RectF> bounds, Map<TreeNode, Integer> depths,
- Map<TreeNode, TreeNode> parents, TreeNode display, float x, float y, int depth) {
- bounds.put(display, new RectF(x, y, x + display.mWidth, y + display.mHeight));
- depths.put(display, depth);
+ private static void getInfo(@Nullable Map<TreeNode, RectF> bounds,
+ @Nullable Map<TreeNode, Integer> depths, @Nullable Map<TreeNode, TreeNode> parents,
+ @Nullable TreeNode display, float x, float y, int depth) {
+ if (display == null) {
+ return;
+ }
+ if (bounds != null) {
+ bounds.put(display, new RectF(x, y, x + display.mWidth, y + display.mHeight));
+ }
+ if (depths != null) {
+ depths.put(display, depth);
+ }
for (TreeNode child : display.mChildren) {
- parents.put(child, display);
+ if (parents != null) {
+ parents.put(child, display);
+ }
if (child.mPosition == POSITION_LEFT) {
getInfo(bounds, depths, parents, child, x - child.mWidth, y + child.mOffset,
depth + 1);
@@ -662,7 +708,7 @@ public final class DisplayTopology implements Parcelable {
* Ensure that the offsets of all displays within the given tree are within bounds.
* @param display The starting node
*/
- private void clampOffsets(TreeNode display) {
+ private void clampOffsets(@Nullable TreeNode display) {
if (display == null) {
return;
}
diff --git a/core/tests/coretests/src/android/hardware/display/DisplayTopologyTest.kt b/core/tests/coretests/src/android/hardware/display/DisplayTopologyTest.kt
index 255d09b854bd..b7d2562c8dd0 100644
--- a/core/tests/coretests/src/android/hardware/display/DisplayTopologyTest.kt
+++ b/core/tests/coretests/src/android/hardware/display/DisplayTopologyTest.kt
@@ -22,6 +22,7 @@ import android.hardware.display.DisplayTopology.TreeNode.POSITION_BOTTOM
import android.hardware.display.DisplayTopology.TreeNode.POSITION_LEFT
import android.hardware.display.DisplayTopology.TreeNode.POSITION_TOP
import android.hardware.display.DisplayTopology.TreeNode.POSITION_RIGHT
+import android.util.SparseArray
import android.view.Display
import com.google.common.truth.Truth.assertThat
import org.junit.Test
@@ -687,6 +688,34 @@ class DisplayTopologyTest {
offset = 0f, noOfChildren = 0)
}
+ @Test
+ fun coordinates() {
+ val display1 = DisplayTopology.TreeNode(/* displayId= */ 1, /* width= */ 200f,
+ /* height= */ 600f, /* position= */ 0, /* offset= */ 0f)
+
+ val display2 = DisplayTopology.TreeNode(/* displayId= */ 2, /* width= */ 600f,
+ /* height= */ 200f, POSITION_RIGHT, /* offset= */ 0f)
+ display1.addChild(display2)
+
+ val display3 = DisplayTopology.TreeNode(/* displayId= */ 3, /* width= */ 600f,
+ /* height= */ 200f, POSITION_RIGHT, /* offset= */ 400f)
+ display1.addChild(display3)
+
+ val display4 = DisplayTopology.TreeNode(/* displayId= */ 4, /* width= */ 200f,
+ /* height= */ 600f, POSITION_RIGHT, /* offset= */ 0f)
+ display2.addChild(display4)
+
+ topology = DisplayTopology(display1, /* primaryDisplayId= */ 1)
+ val coords = topology.absoluteBounds
+
+ val expectedCoords = SparseArray<RectF>()
+ expectedCoords.append(1, RectF(0f, 0f, 200f, 600f))
+ expectedCoords.append(2, RectF(200f, 0f, 800f, 200f))
+ expectedCoords.append(3, RectF(200f, 400f, 800f, 600f))
+ expectedCoords.append(4, RectF(800f, 0f, 1000f, 600f))
+ assertThat(coords.contentEquals(expectedCoords)).isTrue()
+ }
+
/**
* Runs the rearrange algorithm and returns the resulting tree as a list of nodes, with the
* root at index 0. The number of nodes is inferred from the number of positions passed.
diff --git a/services/core/java/com/android/server/display/DisplayTopologyCoordinator.java b/services/core/java/com/android/server/display/DisplayTopologyCoordinator.java
index 461a9f3f2a0d..88650394020b 100644
--- a/services/core/java/com/android/server/display/DisplayTopologyCoordinator.java
+++ b/services/core/java/com/android/server/display/DisplayTopologyCoordinator.java
@@ -16,8 +16,9 @@
package com.android.server.display;
+import static android.hardware.display.DisplayTopology.pxToDp;
+
import android.hardware.display.DisplayTopology;
-import android.util.DisplayMetrics;
import android.view.Display;
import android.view.DisplayInfo;
@@ -140,8 +141,7 @@ class DisplayTopologyCoordinator {
* @return The width of the display in dp
*/
private float getWidth(DisplayInfo info) {
- return info.logicalWidth * (float) DisplayMetrics.DENSITY_DEFAULT
- / info.logicalDensityDpi;
+ return pxToDp(info.logicalWidth, info.logicalDensityDpi);
}
/**
@@ -149,8 +149,7 @@ class DisplayTopologyCoordinator {
* @return The height of the display in dp
*/
private float getHeight(DisplayInfo info) {
- return info.logicalHeight * (float) DisplayMetrics.DENSITY_DEFAULT
- / info.logicalDensityDpi;
+ return pxToDp(info.logicalHeight, info.logicalDensityDpi);
}
private boolean isDisplayAllowedInTopology(DisplayInfo info) {
diff --git a/services/tests/displayservicetests/src/com/android/server/display/DisplayTopologyCoordinatorTest.kt b/services/tests/displayservicetests/src/com/android/server/display/DisplayTopologyCoordinatorTest.kt
index c65024f8f9d5..b09947aaf2ad 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/DisplayTopologyCoordinatorTest.kt
+++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayTopologyCoordinatorTest.kt
@@ -17,7 +17,7 @@
package com.android.server.display
import android.hardware.display.DisplayTopology
-import android.util.DisplayMetrics
+import android.hardware.display.DisplayTopology.pxToDp
import android.view.Display
import android.view.DisplayInfo
import com.google.common.truth.Truth.assertThat
@@ -62,10 +62,8 @@ class DisplayTopologyCoordinatorTest {
fun addDisplay() {
coordinator.onDisplayAdded(displayInfo)
- val widthDp = displayInfo.logicalWidth * (DisplayMetrics.DENSITY_DEFAULT.toFloat()
- / displayInfo.logicalDensityDpi)
- val heightDp = displayInfo.logicalHeight * (DisplayMetrics.DENSITY_DEFAULT.toFloat()
- / displayInfo.logicalDensityDpi)
+ val widthDp = pxToDp(displayInfo.logicalWidth.toFloat(), displayInfo.logicalDensityDpi)
+ val heightDp = pxToDp(displayInfo.logicalHeight.toFloat(), displayInfo.logicalDensityDpi)
verify(mockTopology).addDisplay(displayInfo.displayId, widthDp, heightDp)
verify(mockTopologyChangedCallback).invoke(mockTopologyCopy)
}