From 609bf65668181d93502a57575f6f20281f2494b8 Mon Sep 17 00:00:00 2001 From: Bryce Lee Date: Thu, 9 Feb 2017 16:50:13 -0800 Subject: [PATCH] Update DisplayAdjustments in Display from Resources. Previously, a copy of DisplayAdjustments was provided during Display construction. If the Display instance is held, the adjustments would not update. However, the DisplayInfo would, leading to a mismatch. This changelist adds a reference to the Resources, which can be queried to provide the latest adjustments. Fixes: 33430498 Test: manual from bug repro steps. Test: make -j32 cts; cts-tradefed; run cts --module CtsAppTestCases --test android.app.cts.DisplayTest#testRotation Change-Id: Ida2ed3990add885d06b011494af24b055343f3fa --- core/java/android/app/ActivityThread.java | 2 +- core/java/android/app/ContextImpl.java | 13 +---- core/java/android/app/ResourcesManager.java | 58 ++++++++++++++++--- .../hardware/display/DisplayManager.java | 3 +- .../display/DisplayManagerGlobal.java | 19 ++++++ core/java/android/view/Display.java | 47 ++++++++++++--- core/java/android/view/ViewRootImpl.java | 6 +- 7 files changed, 115 insertions(+), 33 deletions(-) diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index be70dcd204caf..00611f7ae4ad8 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -2916,7 +2916,7 @@ public final class ActivityThread { for (int id : dm.getDisplayIds()) { if (id != Display.DEFAULT_DISPLAY) { Display display = - dm.getCompatibleDisplay(id, appContext.getDisplayAdjustments(id)); + dm.getCompatibleDisplay(id, appContext.getResources()); appContext = (ContextImpl) appContext.createDisplayContext(display); break; } diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java index 045bd0ae8a387..3e9b9877ee492 100644 --- a/core/java/android/app/ContextImpl.java +++ b/core/java/android/app/ContextImpl.java @@ -2067,24 +2067,17 @@ class ContextImpl extends Context { @Override public Display getDisplay() { - final DisplayAdjustments displayAdjustments = mResources.getDisplayAdjustments(); if (mDisplay == null) { return mResourcesManager.getAdjustedDisplay(Display.DEFAULT_DISPLAY, - displayAdjustments); + mResources); } - if (!mDisplay.getDisplayAdjustments().equals(displayAdjustments)) { - mDisplay = mResourcesManager.getAdjustedDisplay(mDisplay.getDisplayId(), - displayAdjustments); - } return mDisplay; } @Override public void updateDisplay(int displayId) { - final DisplayAdjustments displayAdjustments = mResources.getDisplayAdjustments(); - mDisplay = mResourcesManager.getAdjustedDisplay(displayId, - displayAdjustments); + mDisplay = mResourcesManager.getAdjustedDisplay(displayId, mResources); } @Override @@ -2202,7 +2195,7 @@ class ContextImpl extends Context { compatInfo, classLoader); context.mDisplay = resourcesManager.getAdjustedDisplay(displayId, - context.mResources.getDisplayAdjustments()); + context.getResources()); return context; } diff --git a/core/java/android/app/ResourcesManager.java b/core/java/android/app/ResourcesManager.java index 55f7df36ad704..52ec045d5b605 100644 --- a/core/java/android/app/ResourcesManager.java +++ b/core/java/android/app/ResourcesManager.java @@ -104,10 +104,17 @@ public class ResourcesManager { new WeakHashMap<>(); /** - * A cache of DisplayId to DisplayAdjustments. + * A cache of DisplayId, DisplayAdjustments to Display. */ - private final ArrayMap, WeakReference> mDisplays = - new ArrayMap<>(); + private final ArrayMap, WeakReference> + mAdjustedDisplays = new ArrayMap<>(); + + /** + * A cache of DisplayId, Resources to Display. These display adjustments associated with these + * {@link Display}s will change as the resources change. + */ + private final ArrayMap, WeakReference> mResourceDisplays = + new ArrayMap<>(); public static ResourcesManager getInstance() { synchronized (ResourcesManager.class) { @@ -201,19 +208,21 @@ public class ResourcesManager { /** * Returns an adjusted {@link Display} object based on the inputs or null if display isn't - * available. + * available. This method is only used within {@link ResourcesManager} to calculate display + * metrics based on a set {@link DisplayAdjustments}. All other usages should instead call + * {@link ResourcesManager#getAdjustedDisplay(int, Resources)}. * * @param displayId display Id. * @param displayAdjustments display adjustments. */ - public Display getAdjustedDisplay(final int displayId, + private Display getAdjustedDisplay(final int displayId, @Nullable DisplayAdjustments displayAdjustments) { final DisplayAdjustments displayAdjustmentsCopy = (displayAdjustments != null) ? new DisplayAdjustments(displayAdjustments) : new DisplayAdjustments(); final Pair key = Pair.create(displayId, displayAdjustmentsCopy); synchronized (this) { - WeakReference wd = mDisplays.get(key); + WeakReference wd = mAdjustedDisplays.get(key); if (wd != null) { final Display display = wd.get(); if (display != null) { @@ -227,7 +236,37 @@ public class ResourcesManager { } final Display display = dm.getCompatibleDisplay(displayId, key.second); if (display != null) { - mDisplays.put(key, new WeakReference<>(display)); + mAdjustedDisplays.put(key, new WeakReference<>(display)); + } + return display; + } + } + + /** + * Returns an adjusted {@link Display} object based on the inputs or null if display isn't + * available. + * + * @param displayId display Id. + * @param resources The {@link Resources} backing the display adjustments. + */ + public Display getAdjustedDisplay(final int displayId, Resources resources) { + final Pair key = Pair.create(displayId, resources); + synchronized (this) { + WeakReference wd = mResourceDisplays.get(key); + if (wd != null) { + final Display display = wd.get(); + if (display != null) { + return display; + } + } + final DisplayManagerGlobal dm = DisplayManagerGlobal.getInstance(); + if (dm == null) { + // may be null early in system startup + return null; + } + final Display display = dm.getCompatibleDisplay(displayId, resources); + if (display != null) { + mResourceDisplays.put(key, new WeakReference<>(display)); } return display; } @@ -316,6 +355,7 @@ public class ResourcesManager { final DisplayMetrics dm = getDisplayMetrics(key.mDisplayId, daj); final Configuration config = generateConfig(key, dm); final ResourcesImpl impl = new ResourcesImpl(assets, dm, config, daj); + if (DEBUG) { Slog.d(TAG, "- creating impl=" + impl + " with key: " + key); } @@ -811,7 +851,9 @@ public class ResourcesManager { } int changes = mResConfiguration.updateFrom(config); // Things might have changed in display manager, so clear the cached displays. - mDisplays.clear(); + mAdjustedDisplays.clear(); + mResourceDisplays.clear(); + DisplayMetrics defaultDisplayMetrics = getDisplayMetrics(); if (compat != null && (mResCompatibilityInfo == null || diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java index 33a9f5eb67f06..a529c2ffba3d0 100644 --- a/core/java/android/hardware/display/DisplayManager.java +++ b/core/java/android/hardware/display/DisplayManager.java @@ -339,8 +339,7 @@ public final class DisplayManager { private Display getOrCreateDisplayLocked(int displayId, boolean assumeValid) { Display display = mDisplays.get(displayId); if (display == null) { - display = mGlobal.getCompatibleDisplay(displayId, - mContext.getDisplayAdjustments(displayId)); + display = mGlobal.getCompatibleDisplay(displayId, mContext.getResources()); if (display != null) { mDisplays.put(displayId, display); } diff --git a/core/java/android/hardware/display/DisplayManagerGlobal.java b/core/java/android/hardware/display/DisplayManagerGlobal.java index 826eb74aef65f..341754c76edb4 100644 --- a/core/java/android/hardware/display/DisplayManagerGlobal.java +++ b/core/java/android/hardware/display/DisplayManagerGlobal.java @@ -18,6 +18,7 @@ package android.hardware.display; import android.content.Context; import android.content.res.Configuration; +import android.content.res.Resources; import android.hardware.display.DisplayManager.DisplayListener; import android.media.projection.MediaProjection; import android.media.projection.IMediaProjection; @@ -180,6 +181,24 @@ public final class DisplayManagerGlobal { return new Display(this, displayId, displayInfo, daj); } + /** + * Gets information about a logical display. + * + * The display metrics may be adjusted to provide compatibility + * for legacy applications or limited screen areas. + * + * @param displayId The logical display id. + * @param resources Resources providing compatibility info. + * @return The display object, or null if there is no display with the given id. + */ + public Display getCompatibleDisplay(int displayId, Resources resources) { + DisplayInfo displayInfo = getDisplayInfo(displayId); + if (displayInfo == null) { + return null; + } + return new Display(this, displayId, displayInfo, resources); + } + /** * Gets information about a logical display without applying any compatibility metrics. * diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java index 83b6a52e33e8c..7ec7ba7dd162b 100644 --- a/core/java/android/view/Display.java +++ b/core/java/android/view/Display.java @@ -21,6 +21,7 @@ import static android.Manifest.permission.CONFIGURE_DISPLAY_COLOR_MODE; import android.annotation.IntDef; import android.annotation.RequiresPermission; import android.content.res.CompatibilityInfo; +import android.content.res.Resources; import android.graphics.PixelFormat; import android.graphics.Point; import android.graphics.Rect; @@ -71,7 +72,8 @@ public final class Display { private final String mAddress; private final int mOwnerUid; private final String mOwnerPackageName; - private final DisplayAdjustments mDisplayAdjustments; + private final Resources mResources; + private DisplayAdjustments mDisplayAdjustments; private DisplayInfo mDisplayInfo; // never null private boolean mIsValid; @@ -355,19 +357,39 @@ public final class Display { /** * Internal method to create a display. + * The display created with this method will have a static {@link DisplayAdjustments} applied. * Applications should use {@link android.view.WindowManager#getDefaultDisplay()} * or {@link android.hardware.display.DisplayManager#getDisplay} * to get a display object. * * @hide */ - public Display(DisplayManagerGlobal global, - int displayId, DisplayInfo displayInfo /*not null*/, + public Display(DisplayManagerGlobal global, int displayId, /*@NotNull*/ DisplayInfo displayInfo, DisplayAdjustments daj) { + this(global, displayId, displayInfo, daj, null /*res*/); + } + + /** + * Internal method to create a display. + * The display created with this method will be adjusted based on the adjustments in the + * supplied {@link Resources}. + * + * @hide + */ + public Display(DisplayManagerGlobal global, int displayId, /*@NotNull*/ DisplayInfo displayInfo, + Resources res) { + this(global, displayId, displayInfo, null /*daj*/, res); + } + + private Display(DisplayManagerGlobal global, int displayId, + /*@NotNull*/ DisplayInfo displayInfo, DisplayAdjustments daj, Resources res) { mGlobal = global; mDisplayId = displayId; mDisplayInfo = displayInfo; - mDisplayAdjustments = new DisplayAdjustments(daj); + mResources = res; + mDisplayAdjustments = mResources != null + ? new DisplayAdjustments(mResources.getConfiguration()) + : daj != null ? new DisplayAdjustments(daj) : null; mIsValid = true; // Cache properties that cannot change as long as the display is valid. @@ -512,6 +534,13 @@ public final class Display { * @hide */ public DisplayAdjustments getDisplayAdjustments() { + if (mResources != null) { + final DisplayAdjustments currentAdjustements = mResources.getDisplayAdjustments(); + if (!mDisplayAdjustments.equals(currentAdjustements)) { + mDisplayAdjustments = new DisplayAdjustments(currentAdjustements); + } + } + return mDisplayAdjustments; } @@ -562,7 +591,7 @@ public final class Display { public void getSize(Point outSize) { synchronized (this) { updateDisplayInfoLocked(); - mDisplayInfo.getAppMetrics(mTempMetrics, mDisplayAdjustments); + mDisplayInfo.getAppMetrics(mTempMetrics, getDisplayAdjustments()); outSize.x = mTempMetrics.widthPixels; outSize.y = mTempMetrics.heightPixels; } @@ -577,7 +606,7 @@ public final class Display { public void getRectSize(Rect outSize) { synchronized (this) { updateDisplayInfoLocked(); - mDisplayInfo.getAppMetrics(mTempMetrics, mDisplayAdjustments); + mDisplayInfo.getAppMetrics(mTempMetrics, getDisplayAdjustments()); outSize.set(0, 0, mTempMetrics.widthPixels, mTempMetrics.heightPixels); } } @@ -908,7 +937,7 @@ public final class Display { public void getMetrics(DisplayMetrics outMetrics) { synchronized (this) { updateDisplayInfoLocked(); - mDisplayInfo.getAppMetrics(outMetrics, mDisplayAdjustments); + mDisplayInfo.getAppMetrics(outMetrics, getDisplayAdjustments()); } } @@ -1017,7 +1046,7 @@ public final class Display { long now = SystemClock.uptimeMillis(); if (now > mLastCachedAppSizeUpdate + CACHED_APP_SIZE_DURATION_MILLIS) { updateDisplayInfoLocked(); - mDisplayInfo.getAppMetrics(mTempMetrics, mDisplayAdjustments); + mDisplayInfo.getAppMetrics(mTempMetrics, getDisplayAdjustments()); mCachedAppWidthCompat = mTempMetrics.widthPixels; mCachedAppHeightCompat = mTempMetrics.heightPixels; mLastCachedAppSizeUpdate = now; @@ -1029,7 +1058,7 @@ public final class Display { public String toString() { synchronized (this) { updateDisplayInfoLocked(); - mDisplayInfo.getAppMetrics(mTempMetrics, mDisplayAdjustments); + mDisplayInfo.getAppMetrics(mTempMetrics, getDisplayAdjustments()); return "Display id " + mDisplayId + ": " + mDisplayInfo + ", " + mTempMetrics + ", isValid=" + mIsValid; } diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index c81e9385897f7..595e7a1e2da6f 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -1047,8 +1047,8 @@ public final class ViewRootImpl implements ViewParent, // Get new instance of display based on current display adjustments. It may be updated later // if moving between the displays also involved a configuration change. - final DisplayAdjustments displayAdjustments = mView.getResources().getDisplayAdjustments(); - mDisplay = ResourcesManager.getInstance().getAdjustedDisplay(displayId, displayAdjustments); + mDisplay = ResourcesManager.getInstance().getAdjustedDisplay(displayId, + mView.getResources()); mAttachInfo.mDisplayState = mDisplay.getState(); // Internal state updated, now notify the view hierarchy. mView.dispatchMovedToDisplay(mDisplay); @@ -3384,7 +3384,7 @@ public final class ViewRootImpl implements ViewParent, if (force || mLastConfiguration.diff(config) != 0) { // Update the display with new DisplayAdjustments. mDisplay = ResourcesManager.getInstance().getAdjustedDisplay( - mDisplay.getDisplayId(), localResources.getDisplayAdjustments()); + mDisplay.getDisplayId(), localResources); final int lastLayoutDirection = mLastConfiguration.getLayoutDirection(); final int currentLayoutDirection = config.getLayoutDirection();