diff options
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) } |