diff options
| author | 2020-03-06 21:01:13 +0800 | |
|---|---|---|
| committer | 2020-05-11 13:30:14 +0800 | |
| commit | ca70b013021a4486dbed015dd7f362d00878efbe (patch) | |
| tree | 7078a1f14b180fd1d57c6c309ea1abebd8041de1 | |
| parent | 53ed707827f48bdb183add5f08d285dc06e9c705 (diff) | |
Add fixed rotation display adjustments
If an activity is launched with fixed rotation transform,
its window layout and configuration will be rotated. But
if it gets real information from the display, the values
(getRotation, getRealSize, getRealMetric, getCutout) are
inconsistent with the actual appearance.
This change provides the basic information to adjust the
returned values.
Bug: 147213487
Test: atest DisplayAdjustmentsTests#testFixedRotationAdjustments
Change-Id: I864d5759f41209d5f93c4a9011b720675c25e765
| -rw-r--r-- | core/java/android/view/Display.java | 34 | ||||
| -rw-r--r-- | core/java/android/view/DisplayAdjustments.java | 152 | ||||
| -rw-r--r-- | core/tests/coretests/src/android/view/DisplayAdjustmentsTests.java | 37 |
3 files changed, 217 insertions, 6 deletions
diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java index 4469fdbb12ec..8e2efe3f2b38 100644 --- a/core/java/android/view/Display.java +++ b/core/java/android/view/Display.java @@ -104,6 +104,14 @@ public final class Display { private int mCachedAppHeightCompat; /** + * Indicates that the application is started in a different rotation than the real display, so + * the display information may be adjusted. That ensures the methods {@link #getRotation}, + * {@link #getRealSize}, {@link #getRealMetrics}, and {@link #getCutout} are consistent with how + * the application window is laid out. + */ + private boolean mMayAdjustByFixedRotation; + + /** * The default Display id, which is the id of the primary display assuming there is one. */ public static final int DEFAULT_DISPLAY = 0; @@ -804,7 +812,9 @@ public final class Display { public int getRotation() { synchronized (this) { updateDisplayInfoLocked(); - return mDisplayInfo.rotation; + return mMayAdjustByFixedRotation + ? getDisplayAdjustments().getRotation(mDisplayInfo.rotation) + : mDisplayInfo.rotation; } } @@ -828,7 +838,9 @@ public final class Display { public DisplayCutout getCutout() { synchronized (this) { updateDisplayInfoLocked(); - return mDisplayInfo.displayCutout; + return mMayAdjustByFixedRotation + ? getDisplayAdjustments().getDisplayCutout(mDisplayInfo.displayCutout) + : mDisplayInfo.displayCutout; } } @@ -1140,6 +1152,9 @@ public final class Display { updateDisplayInfoLocked(); outSize.x = mDisplayInfo.logicalWidth; outSize.y = mDisplayInfo.logicalHeight; + if (mMayAdjustByFixedRotation) { + getDisplayAdjustments().adjustSize(outSize, mDisplayInfo.rotation); + } } } @@ -1159,6 +1174,9 @@ public final class Display { updateDisplayInfoLocked(); mDisplayInfo.getLogicalMetrics(outMetrics, CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null); + if (mMayAdjustByFixedRotation) { + getDisplayAdjustments().adjustMetrics(outMetrics, mDisplayInfo.rotation); + } } } @@ -1225,6 +1243,11 @@ public final class Display { } } } + + // TODO(b/147213487): Replace the condition with per-resources state. + mMayAdjustByFixedRotation = mIsValid && mResources != null + && mResources.getConfiguration().windowConfiguration.getRotation() + != mDisplayInfo.rotation; } private void updateCachedAppSizeIfNeededLocked() { @@ -1243,9 +1266,12 @@ public final class Display { public String toString() { synchronized (this) { updateDisplayInfoLocked(); - mDisplayInfo.getAppMetrics(mTempMetrics, getDisplayAdjustments()); + final DisplayAdjustments adjustments = getDisplayAdjustments(); + mDisplayInfo.getAppMetrics(mTempMetrics, adjustments); return "Display id " + mDisplayId + ": " + mDisplayInfo - + ", " + mTempMetrics + ", isValid=" + mIsValid; + + (mMayAdjustByFixedRotation + ? (", " + adjustments.getFixedRotationAdjustments() + ", ") : ", ") + + mTempMetrics + ", isValid=" + mIsValid; } } diff --git a/core/java/android/view/DisplayAdjustments.java b/core/java/android/view/DisplayAdjustments.java index 27c2d5c5cdc3..c726bee9f402 100644 --- a/core/java/android/view/DisplayAdjustments.java +++ b/core/java/android/view/DisplayAdjustments.java @@ -21,6 +21,10 @@ import android.annotation.Nullable; import android.compat.annotation.UnsupportedAppUsage; import android.content.res.CompatibilityInfo; import android.content.res.Configuration; +import android.graphics.Point; +import android.os.Parcel; +import android.os.Parcelable; +import android.util.DisplayMetrics; import java.util.Objects; @@ -30,6 +34,7 @@ public class DisplayAdjustments { private volatile CompatibilityInfo mCompatInfo = CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO; private final Configuration mConfiguration = new Configuration(Configuration.EMPTY); + private FixedRotationAdjustments mFixedRotationAdjustments; @UnsupportedAppUsage public DisplayAdjustments() { @@ -44,6 +49,7 @@ public class DisplayAdjustments { public DisplayAdjustments(@NonNull DisplayAdjustments daj) { setCompatibilityInfo(daj.mCompatInfo); mConfiguration.setTo(daj.getConfiguration()); + mFixedRotationAdjustments = daj.mFixedRotationAdjustments; } @UnsupportedAppUsage @@ -84,11 +90,78 @@ public class DisplayAdjustments { return mConfiguration; } + public void setFixedRotationAdjustments(FixedRotationAdjustments fixedRotationAdjustments) { + mFixedRotationAdjustments = fixedRotationAdjustments; + } + + public FixedRotationAdjustments getFixedRotationAdjustments() { + return mFixedRotationAdjustments; + } + + /** Returns {@code false} if the width and height of display should swap. */ + private boolean noFlip(@Surface.Rotation int realRotation) { + final FixedRotationAdjustments rotationAdjustments = mFixedRotationAdjustments; + if (rotationAdjustments == null) { + return true; + } + // Check if the delta is rotated by 90 degrees. + return (realRotation - rotationAdjustments.mRotation + 4) % 2 == 0; + } + + /** Adjusts the given size if possible. */ + public void adjustSize(@NonNull Point size, @Surface.Rotation int realRotation) { + if (noFlip(realRotation)) { + return; + } + final int w = size.x; + size.x = size.y; + size.y = w; + } + + /** Adjusts the given metrics if possible. */ + public void adjustMetrics(@NonNull DisplayMetrics metrics, @Surface.Rotation int realRotation) { + if (noFlip(realRotation)) { + return; + } + int w = metrics.widthPixels; + metrics.widthPixels = metrics.heightPixels; + metrics.heightPixels = w; + + w = metrics.noncompatWidthPixels; + metrics.noncompatWidthPixels = metrics.noncompatHeightPixels; + metrics.noncompatHeightPixels = w; + + float x = metrics.xdpi; + metrics.xdpi = metrics.ydpi; + metrics.ydpi = x; + + x = metrics.noncompatXdpi; + metrics.noncompatXdpi = metrics.noncompatYdpi; + metrics.noncompatYdpi = x; + } + + /** Returns the adjusted cutout if available. Otherwise the original cutout is returned. */ + @Nullable + public DisplayCutout getDisplayCutout(@Nullable DisplayCutout realCutout) { + final FixedRotationAdjustments rotationAdjustments = mFixedRotationAdjustments; + return rotationAdjustments != null && rotationAdjustments.mRotatedDisplayCutout != null + ? rotationAdjustments.mRotatedDisplayCutout + : realCutout; + } + + /** Returns the adjusted rotation if available. Otherwise the original rotation is returned. */ + @Surface.Rotation + public int getRotation(@Surface.Rotation int realRotation) { + final FixedRotationAdjustments rotationAdjustments = mFixedRotationAdjustments; + return rotationAdjustments != null ? rotationAdjustments.mRotation : realRotation; + } + @Override public int hashCode() { int hash = 17; hash = hash * 31 + Objects.hashCode(mCompatInfo); hash = hash * 31 + Objects.hashCode(mConfiguration); + hash = hash * 31 + Objects.hashCode(mFixedRotationAdjustments); return hash; } @@ -98,7 +171,82 @@ public class DisplayAdjustments { return false; } DisplayAdjustments daj = (DisplayAdjustments)o; - return Objects.equals(daj.mCompatInfo, mCompatInfo) && - Objects.equals(daj.mConfiguration, mConfiguration); + return Objects.equals(daj.mCompatInfo, mCompatInfo) + && Objects.equals(daj.mConfiguration, mConfiguration) + && Objects.equals(daj.mFixedRotationAdjustments, mFixedRotationAdjustments); + } + + /** + * An application can be launched in different rotation than the real display. This class + * provides the information to adjust the values returned by {@link #Display}. + * @hide + */ + public static class FixedRotationAdjustments implements Parcelable { + /** The application-based rotation. */ + @Surface.Rotation + final int mRotation; + + /** Non-null if the device has cutout. */ + @Nullable + final DisplayCutout mRotatedDisplayCutout; + + public FixedRotationAdjustments(@Surface.Rotation int rotation, DisplayCutout cutout) { + mRotation = rotation; + mRotatedDisplayCutout = cutout; + } + + @Override + public int hashCode() { + int hash = 17; + hash = hash * 31 + mRotation; + hash = hash * 31 + Objects.hashCode(mRotatedDisplayCutout); + return hash; + } + + @Override + public boolean equals(Object o) { + if (!(o instanceof FixedRotationAdjustments)) { + return false; + } + final FixedRotationAdjustments other = (FixedRotationAdjustments) o; + return mRotation == other.mRotation + && Objects.equals(mRotatedDisplayCutout, other.mRotatedDisplayCutout); + } + + @Override + public String toString() { + return "FixedRotationAdjustments{rotation=" + Surface.rotationToString(mRotation) + + " cutout=" + mRotatedDisplayCutout + "}"; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(mRotation); + dest.writeTypedObject( + new DisplayCutout.ParcelableWrapper(mRotatedDisplayCutout), flags); + } + + private FixedRotationAdjustments(Parcel in) { + mRotation = in.readInt(); + final DisplayCutout.ParcelableWrapper cutoutWrapper = + in.readTypedObject(DisplayCutout.ParcelableWrapper.CREATOR); + mRotatedDisplayCutout = cutoutWrapper != null ? cutoutWrapper.get() : null; + } + + public static final Creator<FixedRotationAdjustments> CREATOR = + new Creator<FixedRotationAdjustments>() { + public FixedRotationAdjustments createFromParcel(Parcel in) { + return new FixedRotationAdjustments(in); + } + + public FixedRotationAdjustments[] newArray(int size) { + return new FixedRotationAdjustments[size]; + } + }; } } diff --git a/core/tests/coretests/src/android/view/DisplayAdjustmentsTests.java b/core/tests/coretests/src/android/view/DisplayAdjustmentsTests.java index afbf8db3cd2d..2fc42e91a8cc 100644 --- a/core/tests/coretests/src/android/view/DisplayAdjustmentsTests.java +++ b/core/tests/coretests/src/android/view/DisplayAdjustmentsTests.java @@ -19,6 +19,9 @@ package android.view; import static org.junit.Assert.assertEquals; import android.content.res.Configuration; +import android.graphics.Point; +import android.util.DisplayMetrics; +import android.view.DisplayAdjustments.FixedRotationAdjustments; import androidx.test.ext.junit.runners.AndroidJUnit4; @@ -67,4 +70,38 @@ public class DisplayAdjustmentsTests { assertEquals(configuration, newAdjustments.getConfiguration()); } + + @Test + public void testFixedRotationAdjustments() { + final DisplayAdjustments mDisplayAdjustments = new DisplayAdjustments(); + final int realRotation = Surface.ROTATION_0; + final int fixedRotation = Surface.ROTATION_90; + + mDisplayAdjustments.setFixedRotationAdjustments( + new FixedRotationAdjustments(fixedRotation, null /* cutout */)); + + final int w = 1000; + final int h = 2000; + final Point size = new Point(w, h); + mDisplayAdjustments.adjustSize(size, realRotation); + + assertEquals(fixedRotation, mDisplayAdjustments.getRotation(realRotation)); + assertEquals(new Point(h, w), size); + + final DisplayMetrics metrics = new DisplayMetrics(); + metrics.xdpi = metrics.noncompatXdpi = w; + metrics.widthPixels = metrics.noncompatWidthPixels = w; + metrics.ydpi = metrics.noncompatYdpi = h; + metrics.heightPixels = metrics.noncompatHeightPixels = h; + + final DisplayMetrics flippedMetrics = new DisplayMetrics(); + flippedMetrics.xdpi = flippedMetrics.noncompatXdpi = h; + flippedMetrics.widthPixels = flippedMetrics.noncompatWidthPixels = h; + flippedMetrics.ydpi = flippedMetrics.noncompatYdpi = w; + flippedMetrics.heightPixels = flippedMetrics.noncompatHeightPixels = w; + + mDisplayAdjustments.adjustMetrics(metrics, realRotation); + + assertEquals(flippedMetrics, metrics); + } } |