Merge "Adjust activity display metrics based on stack configuration."
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index d781863..0289e48 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -2372,35 +2372,32 @@
         return activity;
     }
 
-    private Context createBaseContextForActivity(ActivityClientRecord r,
-            final Activity activity) {
-        ContextImpl appContext =
-                ContextImpl.createActivityContext(this, r.packageInfo, r.overrideConfig);
-        appContext.setOuterContext(activity);
-        Context baseContext = appContext;
-
-        final DisplayManagerGlobal dm = DisplayManagerGlobal.getInstance();
+    private Context createBaseContextForActivity(ActivityClientRecord r, final Activity activity) {
+        int displayId = Display.DEFAULT_DISPLAY;
         try {
             IActivityContainer container =
                     ActivityManagerNative.getDefault().getEnclosingActivityContainer(r.token);
-            final int displayId =
-                    container == null ? Display.DEFAULT_DISPLAY : container.getDisplayId();
-            if (displayId > Display.DEFAULT_DISPLAY) {
-                Display display = dm.getRealDisplay(displayId, r.token);
-                baseContext = appContext.createDisplayContext(display);
+            if (container != null) {
+                displayId = container.getDisplayId();
             }
         } catch (RemoteException e) {
         }
 
+        ContextImpl appContext = ContextImpl.createActivityContext(
+                this, r.packageInfo, displayId, r.overrideConfig);
+        appContext.setOuterContext(activity);
+        Context baseContext = appContext;
+
+        final DisplayManagerGlobal dm = DisplayManagerGlobal.getInstance();
         // For debugging purposes, if the activity's package name contains the value of
         // the "debug.use-second-display" system property as a substring, then show
         // its content on a secondary display if there is one.
         String pkgName = SystemProperties.get("debug.second-display.pkg");
         if (pkgName != null && !pkgName.isEmpty()
                 && r.packageInfo.mPackageName.contains(pkgName)) {
-            for (int displayId : dm.getDisplayIds()) {
-                if (displayId != Display.DEFAULT_DISPLAY) {
-                    Display display = dm.getRealDisplay(displayId, r.token);
+            for (int id : dm.getDisplayIds()) {
+                if (id != Display.DEFAULT_DISPLAY) {
+                    Display display = dm.getRealDisplay(id, r.overrideConfig);
                     baseContext = appContext.createDisplayContext(display);
                     break;
                 }
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 6c78cab..0098d86 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -2252,7 +2252,7 @@
         ContextImpl context = new ContextImpl(null, mainThread,
                 packageInfo, null, null, false, null, null);
         context.mResources.updateConfiguration(context.mResourcesManager.getConfiguration(),
-                context.mResourcesManager.getDisplayMetricsLocked(Display.DEFAULT_DISPLAY));
+                context.mResourcesManager.getDisplayMetricsLocked());
         return context;
     }
 
@@ -2263,9 +2263,11 @@
     }
 
     static ContextImpl createActivityContext(ActivityThread mainThread,
-            LoadedApk packageInfo, Configuration overrideConfiguration) {
+            LoadedApk packageInfo, int displayId, Configuration overrideConfiguration) {
         if (packageInfo == null) throw new IllegalArgumentException("packageInfo");
-        return new ContextImpl(null, mainThread, packageInfo, null, null, false, null,
+        final Display display = ResourcesManager.getInstance().getAdjustedDisplay(
+                displayId, overrideConfiguration);
+        return new ContextImpl(null, mainThread, packageInfo, null, null, false, display,
                 overrideConfiguration);
     }
 
@@ -2296,7 +2298,7 @@
             compatInfo = packageInfo.getCompatibilityInfo();
         }
         mDisplayAdjustments.setCompatibilityInfo(compatInfo);
-        mDisplayAdjustments.setActivityToken(activityToken);
+        mDisplayAdjustments.setConfiguration(overrideConfiguration);
 
         Resources resources = packageInfo.getResources(mainThread);
         if (resources != null) {
diff --git a/core/java/android/app/ResourcesManager.java b/core/java/android/app/ResourcesManager.java
index fac40b2..17885a2 100644
--- a/core/java/android/app/ResourcesManager.java
+++ b/core/java/android/app/ResourcesManager.java
@@ -27,6 +27,7 @@
 import android.hardware.display.DisplayManagerGlobal;
 import android.util.ArrayMap;
 import android.util.DisplayMetrics;
+import android.util.Pair;
 import android.util.Slog;
 import android.view.Display;
 import android.view.DisplayAdjustments;
@@ -40,11 +41,10 @@
     private static final boolean DEBUG = false;
 
     private static ResourcesManager sResourcesManager;
-    final ArrayMap<ResourcesKey, WeakReference<Resources> > mActiveResources
-            = new ArrayMap<ResourcesKey, WeakReference<Resources> >();
-
-    final ArrayMap<DisplayAdjustments, DisplayMetrics> mDefaultDisplayMetrics
-            = new ArrayMap<DisplayAdjustments, DisplayMetrics>();
+    private final ArrayMap<ResourcesKey, WeakReference<Resources> > mActiveResources =
+            new ArrayMap<>();
+    private final ArrayMap<Pair<Integer, Configuration>, WeakReference<Display>> mDisplays =
+            new ArrayMap<>();
 
     CompatibilityInfo mResCompatibilityInfo;
 
@@ -63,46 +63,18 @@
         return mResConfiguration;
     }
 
-    public void flushDisplayMetricsLocked() {
-        mDefaultDisplayMetrics.clear();
+    DisplayMetrics getDisplayMetricsLocked() {
+        return getDisplayMetricsLocked(Display.DEFAULT_DISPLAY);
     }
 
-    public DisplayMetrics getDisplayMetricsLocked(int displayId) {
-        return getDisplayMetricsLocked(displayId, DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS);
-    }
-
-    public DisplayMetrics getDisplayMetricsLocked(int displayId, DisplayAdjustments daj) {
-        boolean isDefaultDisplay = (displayId == Display.DEFAULT_DISPLAY);
-        DisplayMetrics dm = isDefaultDisplay ? mDefaultDisplayMetrics.get(daj) : null;
-        if (dm != null) {
-            return dm;
-        }
-        dm = new DisplayMetrics();
-
-        DisplayManagerGlobal displayManager = DisplayManagerGlobal.getInstance();
-        if (displayManager == null) {
-            // may be null early in system startup
-            dm.setToDefaults();
-            return dm;
-        }
-
-        if (isDefaultDisplay) {
-            mDefaultDisplayMetrics.put(daj, dm);
-        }
-
-        Display d = displayManager.getCompatibleDisplay(displayId, daj);
-        if (d != null) {
-            d.getMetrics(dm);
+    DisplayMetrics getDisplayMetricsLocked(int displayId) {
+        DisplayMetrics dm = new DisplayMetrics();
+        final Display display = getAdjustedDisplay(displayId, Configuration.EMPTY);
+        if (display != null) {
+            display.getMetrics(dm);
         } else {
-            // Display no longer exists
-            // FIXME: This would not be a problem if we kept the Display object around
-            // instead of using the raw display id everywhere.  The Display object caches
-            // its information even after the display has been removed.
             dm.setToDefaults();
         }
-        //Slog.i("foo", "New metrics: w=" + metrics.widthPixels + " h="
-        //        + metrics.heightPixels + " den=" + metrics.density
-        //        + " xdpi=" + metrics.xdpi + " ydpi=" + metrics.ydpi);
         return dm;
     }
 
@@ -138,6 +110,37 @@
     }
 
     /**
+     * Returns an adjusted {@link Display} object based on the inputs or null if display isn't
+     * available.
+     *
+     * @param displayId display Id.
+     * @param overrideConfiguration override configurations.
+     */
+    public Display getAdjustedDisplay(final int displayId, Configuration overrideConfiguration) {
+        final Pair<Integer, Configuration> key =
+                Pair.create(displayId, new Configuration(overrideConfiguration));
+        synchronized (this) {
+            WeakReference<Display> wd = mDisplays.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.getRealDisplay(displayId, key.second);
+            if (display != null) {
+                mDisplays.put(key, new WeakReference<>(display));
+            }
+            return display;
+        }
+    }
+
+    /**
      * Creates the top level Resources for applications with the given compatibility info.
      *
      * @param resDir the resource directory.
@@ -148,7 +151,7 @@
      * @param overrideConfiguration override configurations.
      * @param compatInfo the compatibility info. Must not be null.
      */
-    public Resources getTopLevelResources(String resDir, String[] splitResDirs,
+    Resources getTopLevelResources(String resDir, String[] splitResDirs,
             String[] overlayDirs, String[] libDirs, int displayId,
             Configuration overrideConfiguration, CompatibilityInfo compatInfo) {
         final float scale = compatInfo.applicationScale;
@@ -247,7 +250,7 @@
         }
     }
 
-    public final boolean applyConfigurationToResourcesLocked(Configuration config,
+    final boolean applyConfigurationToResourcesLocked(Configuration config,
             CompatibilityInfo compat) {
         if (mResConfiguration == null) {
             mResConfiguration = new Configuration();
@@ -258,8 +261,9 @@
             return false;
         }
         int changes = mResConfiguration.updateFrom(config);
-        flushDisplayMetricsLocked();
-        DisplayMetrics defaultDisplayMetrics = getDisplayMetricsLocked(Display.DEFAULT_DISPLAY);
+        // Things might have changed in display manager, so clear the cached displays.
+        mDisplays.clear();
+        DisplayMetrics defaultDisplayMetrics = getDisplayMetricsLocked();
 
         if (compat != null && (mResCompatibilityInfo == null ||
                 !mResCompatibilityInfo.equals(compat))) {
@@ -281,7 +285,7 @@
 
         Configuration tmpConfig = null;
 
-        for (int i=mActiveResources.size()-1; i>=0; i--) {
+        for (int i = mActiveResources.size() - 1; i >= 0; i--) {
             ResourcesKey key = mActiveResources.keyAt(i);
             Resources r = mActiveResources.valueAt(i).get();
             if (r != null) {
diff --git a/core/java/android/hardware/display/DisplayManagerGlobal.java b/core/java/android/hardware/display/DisplayManagerGlobal.java
index 0051ef5..d9f9c1e 100644
--- a/core/java/android/hardware/display/DisplayManagerGlobal.java
+++ b/core/java/android/hardware/display/DisplayManagerGlobal.java
@@ -17,10 +17,10 @@
 package android.hardware.display;
 
 import android.content.Context;
+import android.content.res.Configuration;
 import android.hardware.display.DisplayManager.DisplayListener;
 import android.media.projection.MediaProjection;
 import android.media.projection.IMediaProjection;
-import android.os.Binder;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Looper;
@@ -196,11 +196,11 @@
      * Gets information about a logical display without applying any compatibility metrics.
      *
      * @param displayId The logical display id.
-     * @param IBinder the activity token for this display.
+     * @param configuration the configuration.
      * @return The display object, or null if there is no display with the given id.
      */
-    public Display getRealDisplay(int displayId, IBinder token) {
-        return getCompatibleDisplay(displayId, new DisplayAdjustments(token));
+    public Display getRealDisplay(int displayId, Configuration configuration) {
+        return getCompatibleDisplay(displayId, new DisplayAdjustments(configuration));
     }
 
     public void registerDisplayListener(DisplayListener listener, Handler handler) {
diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java
index cfb0297..71863b7 100644
--- a/core/java/android/view/Display.java
+++ b/core/java/android/view/Display.java
@@ -716,7 +716,7 @@
             updateDisplayInfoLocked();
             mDisplayInfo.getLogicalMetrics(outMetrics,
                     CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO,
-                    mDisplayAdjustments.getActivityToken());
+                    mDisplayAdjustments.getConfiguration());
         }
     }
 
diff --git a/core/java/android/view/DisplayAdjustments.java b/core/java/android/view/DisplayAdjustments.java
index 35fb504..272740f 100644
--- a/core/java/android/view/DisplayAdjustments.java
+++ b/core/java/android/view/DisplayAdjustments.java
@@ -17,7 +17,7 @@
 package android.view;
 
 import android.content.res.CompatibilityInfo;
-import android.os.IBinder;
+import android.content.res.Configuration;
 
 import java.util.Objects;
 
@@ -28,22 +28,18 @@
     public static final DisplayAdjustments DEFAULT_DISPLAY_ADJUSTMENTS = new DisplayAdjustments();
 
     private volatile CompatibilityInfo mCompatInfo = CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO;
-    private volatile IBinder mActivityToken;
+    private Configuration mConfiguration = Configuration.EMPTY;
 
     public DisplayAdjustments() {
     }
 
-    public DisplayAdjustments(IBinder token) {
-        mActivityToken = token;
+    public DisplayAdjustments(Configuration configuration) {
+        mConfiguration = configuration;
     }
 
     public DisplayAdjustments(DisplayAdjustments daj) {
-        this (daj.getCompatibilityInfo(), daj.getActivityToken());
-    }
-
-    public DisplayAdjustments(CompatibilityInfo compatInfo, IBinder token) {
-        setCompatibilityInfo(compatInfo);
-        mActivityToken = token;
+        setCompatibilityInfo(daj.mCompatInfo);
+        mConfiguration = daj.mConfiguration;
     }
 
     public void setCompatibilityInfo(CompatibilityInfo compatInfo) {
@@ -63,16 +59,16 @@
         return mCompatInfo;
     }
 
-    public void setActivityToken(IBinder token) {
+    public void setConfiguration(Configuration configuration) {
         if (this == DEFAULT_DISPLAY_ADJUSTMENTS) {
             throw new IllegalArgumentException(
-                    "setActivityToken: Cannot modify DEFAULT_DISPLAY_ADJUSTMENTS");
+                    "setConfiguration: Cannot modify DEFAULT_DISPLAY_ADJUSTMENTS");
         }
-        mActivityToken = token;
+        mConfiguration = configuration;
     }
 
-    public IBinder getActivityToken() {
-        return mActivityToken;
+    public Configuration getConfiguration() {
+        return mConfiguration;
     }
 
     @Override
@@ -80,7 +76,7 @@
         int hash = 17;
         hash = hash * 31 + mCompatInfo.hashCode();
         if (DEVELOPMENT_RESOURCES_DEPEND_ON_ACTIVITY_TOKEN) {
-            hash = hash * 31 + (mActivityToken == null ? 0 : mActivityToken.hashCode());
+            hash = hash * 31 + (mConfiguration == null ? 0 : mConfiguration.hashCode());
         }
         return hash;
     }
@@ -92,6 +88,6 @@
         }
         DisplayAdjustments daj = (DisplayAdjustments)o;
         return Objects.equals(daj.mCompatInfo, mCompatInfo) &&
-                Objects.equals(daj.mActivityToken, mActivityToken);
+                Objects.equals(daj.mConfiguration, mConfiguration);
     }
 }
diff --git a/core/java/android/view/DisplayInfo.java b/core/java/android/view/DisplayInfo.java
index 9feb681..ecf45b4 100644
--- a/core/java/android/view/DisplayInfo.java
+++ b/core/java/android/view/DisplayInfo.java
@@ -17,7 +17,7 @@
 package android.view;
 
 import android.content.res.CompatibilityInfo;
-import android.os.IBinder;
+import android.content.res.Configuration;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.util.DisplayMetrics;
@@ -401,16 +401,17 @@
 
     public void getAppMetrics(DisplayMetrics outMetrics, DisplayAdjustments displayAdjustments) {
         getMetricsWithSize(outMetrics, displayAdjustments.getCompatibilityInfo(),
-                displayAdjustments.getActivityToken(), appWidth, appHeight);
+                displayAdjustments.getConfiguration(), appWidth, appHeight);
     }
 
-    public void getAppMetrics(DisplayMetrics outMetrics, CompatibilityInfo ci, IBinder token) {
-        getMetricsWithSize(outMetrics, ci, token, appWidth, appHeight);
+    public void getAppMetrics(DisplayMetrics outMetrics, CompatibilityInfo ci,
+            Configuration configuration) {
+        getMetricsWithSize(outMetrics, ci, configuration, appWidth, appHeight);
     }
 
     public void getLogicalMetrics(DisplayMetrics outMetrics, CompatibilityInfo compatInfo,
-            IBinder token) {
-        getMetricsWithSize(outMetrics, compatInfo, token, logicalWidth, logicalHeight);
+            Configuration configuration) {
+        getMetricsWithSize(outMetrics, compatInfo, configuration, logicalWidth, logicalHeight);
     }
 
     public int getNaturalWidth() {
@@ -431,17 +432,24 @@
     }
 
     private void getMetricsWithSize(DisplayMetrics outMetrics, CompatibilityInfo compatInfo,
-            IBinder token, int width, int height) {
+            Configuration configuration, int width, int height) {
         outMetrics.densityDpi = outMetrics.noncompatDensityDpi = logicalDensityDpi;
-        outMetrics.noncompatWidthPixels  = outMetrics.widthPixels = width;
-        outMetrics.noncompatHeightPixels = outMetrics.heightPixels = height;
-
         outMetrics.density = outMetrics.noncompatDensity =
                 logicalDensityDpi * DisplayMetrics.DENSITY_DEFAULT_SCALE;
         outMetrics.scaledDensity = outMetrics.noncompatScaledDensity = outMetrics.density;
         outMetrics.xdpi = outMetrics.noncompatXdpi = physicalXDpi;
         outMetrics.ydpi = outMetrics.noncompatYdpi = physicalYDpi;
 
+        width = (configuration != null
+                && configuration.screenWidthDp != Configuration.SCREEN_WIDTH_DP_UNDEFINED)
+                ? (int)((configuration.screenWidthDp * outMetrics.density) + 0.5f) : width;
+        height = (configuration != null
+                && configuration.screenHeightDp != Configuration.SCREEN_HEIGHT_DP_UNDEFINED)
+                ? (int)((configuration.screenHeightDp * outMetrics.density) + 0.5f) : height;
+
+        outMetrics.noncompatWidthPixels  = outMetrics.widthPixels = width;
+        outMetrics.noncompatHeightPixels = outMetrics.heightPixels = height;
+
         if (!compatInfo.equals(CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO)) {
             compatInfo.applyToDisplayMetrics(outMetrics);
         }
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index fb2a8d8..24fae8a 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -478,7 +478,6 @@
 
                 CompatibilityInfo compatibilityInfo = mDisplayAdjustments.getCompatibilityInfo();
                 mTranslator = compatibilityInfo.getTranslator();
-                mDisplayAdjustments.setActivityToken(attrs.token);
 
                 // If the application owns the surface, don't enable hardware acceleration
                 if (mSurfaceHolder == null) {
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index e88dace..99cc03e 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -1551,6 +1551,9 @@
                 pw.print(prefix); pw.print("touchable region="); pw.println(region);
             }
             pw.print(prefix); pw.print("mConfiguration="); pw.println(mConfiguration);
+            if (mOverrideConfig != Configuration.EMPTY) {
+                pw.print(prefix); pw.print("mOverrideConfig="); pw.println(mOverrideConfig);
+            }
         }
         pw.print(prefix); pw.print("mHasSurface="); pw.print(mHasSurface);
                 pw.print(" mShownFrame="); mShownFrame.printShortString(pw);