From 70c9d936d9599e328ea43d47049a70737b122191 Mon Sep 17 00:00:00 2001 From: Sergey Nikolaienkov Date: Mon, 15 Feb 2021 09:42:20 +0000 Subject: [PATCH] Cap resolution for pre-S apps on TV at 1080p On Android TV applications that target pre-S SDK are not expecting to receive a Window larger than 1080p. To avoid this from happening this CL overrides compatibility scaling for applications that target a pre-S SDK on ATV devices that have larger than 1080p screen, so that the applications would still need to draw to a 1080p Surface. Bug: 157629738 Test: atest CtsWindowManagerDeviceTestCases:TvMaxWindowSizeTests Change-Id: I2b240bb5fcae6b165fd17c982cc29c49de348dbf --- .../content/res/CompatibilityInfo.java | 1 + .../android/server/wm/CompatModePackages.java | 97 +++++++++++-------- .../android/test/dpi/DpiTestActivity.java | 24 ++--- 3 files changed, 68 insertions(+), 54 deletions(-) diff --git a/core/java/android/content/res/CompatibilityInfo.java b/core/java/android/content/res/CompatibilityInfo.java index bbde8b103ef3..d7225ccd9ca6 100644 --- a/core/java/android/content/res/CompatibilityInfo.java +++ b/core/java/android/content/res/CompatibilityInfo.java @@ -110,6 +110,7 @@ public class CompatibilityInfo implements Parcelable { public final float applicationInvertedScale; @UnsupportedAppUsage + @Deprecated public CompatibilityInfo(ApplicationInfo appInfo, int screenLayout, int sw, boolean forceCompat) { this(appInfo, screenLayout, sw, forceCompat, 1f); diff --git a/services/core/java/com/android/server/wm/CompatModePackages.java b/services/core/java/com/android/server/wm/CompatModePackages.java index a725dd34fbf6..28a509bc9276 100644 --- a/services/core/java/com/android/server/wm/CompatModePackages.java +++ b/services/core/java/com/android/server/wm/CompatModePackages.java @@ -27,16 +27,20 @@ import android.app.AppGlobals; import android.app.compat.CompatChanges; import android.compat.annotation.ChangeId; import android.compat.annotation.Disabled; +import android.compat.annotation.EnabledSince; +import android.compat.annotation.Overridable; import android.content.pm.ApplicationInfo; import android.content.pm.IPackageManager; import android.content.res.CompatibilityInfo; import android.content.res.Configuration; +import android.os.Build; import android.os.Handler; import android.os.Looper; import android.os.Message; import android.os.RemoteException; import android.os.UserHandle; import android.util.AtomicFile; +import android.util.DisplayMetrics; import android.util.Slog; import android.util.SparseArray; import android.util.TypedXmlPullParser; @@ -119,6 +123,17 @@ public final class CompatModePackages { @Disabled private static final long DOWNSCALE_50 = 176926741L; + /** + * On Android TV applications that target pre-S are not expecting to receive a Window larger + * than 1080p, so if needed we are downscaling their Windows to 1080p. + * However, applications that target S and greater release version are expected to be able to + * handle any Window size, so we should not downscale their Windows. + */ + @ChangeId + @Overridable + @EnabledSince(targetSdkVersion = Build.VERSION_CODES.S) + private static final long DO_NOT_DOWNSCALE_TO_1080P_ON_TV = 157629738L; // This is a Bug ID. + private final HashMap mPackages = new HashMap(); private static final int MSG_WRITE = 300; @@ -138,7 +153,7 @@ public final class CompatModePackages { break; } } - }; + } public CompatModePackages(ActivityTaskManagerService service, File systemDir, Handler handler) { mService = service; @@ -247,55 +262,53 @@ public final class CompatModePackages { mHandler.sendMessageDelayed(msg, 10000); } + public CompatibilityInfo compatibilityInfoForPackageLocked(ApplicationInfo ai) { + final boolean forceCompat = getPackageCompatModeEnabledLocked(ai); + final float compatScale = getCompatScale(ai.packageName, ai.uid); + final Configuration config = mService.getGlobalConfiguration(); + return new CompatibilityInfo(ai, config.screenLayout, config.smallestScreenWidthDp, + forceCompat, compatScale); + } + float getCompatScale(String packageName, int uid) { - if (!CompatChanges.isChangeEnabled( - DOWNSCALED, packageName, UserHandle.getUserHandleForUid(uid))) { - return 1f; + final UserHandle userHandle = UserHandle.getUserHandleForUid(uid); + if (CompatChanges.isChangeEnabled(DOWNSCALED, packageName, userHandle)) { + if (CompatChanges.isChangeEnabled(DOWNSCALE_87_5, packageName, userHandle)) { + return 8f / 7f; // 1.14285714286 + } + if (CompatChanges.isChangeEnabled(DOWNSCALE_75, packageName, userHandle)) { + return 4f / 3f; // 1.333333333 + } + if (CompatChanges.isChangeEnabled(DOWNSCALE_62_5, packageName, userHandle)) { + return /* 1 / 0.625 */ 1.6f; + } + if (CompatChanges.isChangeEnabled(DOWNSCALE_50, packageName, userHandle)) { + return /* 1 / 0.5 */ 2f; + } } - if (CompatChanges.isChangeEnabled( - DOWNSCALE_87_5, packageName, UserHandle.getUserHandleForUid(uid))) { - // 8/7 == (1 / 0.875) ~= 1.14285714286 - return 8f / 7f; - } - if (CompatChanges.isChangeEnabled( - DOWNSCALE_75, packageName, UserHandle.getUserHandleForUid(uid))) { - // 4/3 == (1 / 0.75) ~= 1.333333333 - return 4f / 3f; - } - if (CompatChanges.isChangeEnabled( - DOWNSCALE_62_5, packageName, UserHandle.getUserHandleForUid(uid))) { - // (1 / 0.625) == 1.6 - return 1.6f; - } - if (CompatChanges.isChangeEnabled( - DOWNSCALE_50, packageName, UserHandle.getUserHandleForUid(uid))) { - return 2f; + + if (mService.mHasLeanbackFeature) { + final Configuration config = mService.getGlobalConfiguration(); + final float density = config.densityDpi / (float) DisplayMetrics.DENSITY_DEFAULT; + final int smallestScreenWidthPx = (int) (config.smallestScreenWidthDp * density + .5f); + if (smallestScreenWidthPx > 1080 && !CompatChanges.isChangeEnabled( + DO_NOT_DOWNSCALE_TO_1080P_ON_TV, packageName, userHandle)) { + return smallestScreenWidthPx / 1080f; + } } + return 1f; } - public CompatibilityInfo compatibilityInfoForPackageLocked(ApplicationInfo ai) { - final Configuration globalConfig = mService.getGlobalConfiguration(); - final float requestedScale = getCompatScale(ai.packageName, ai.uid); - CompatibilityInfo ci = new CompatibilityInfo(ai, globalConfig.screenLayout, - globalConfig.smallestScreenWidthDp, - (getPackageFlags(ai.packageName) & COMPAT_FLAG_ENABLED) != 0, requestedScale); - //Slog.i(TAG, "*********** COMPAT FOR PKG " + ai.packageName + ": " + ci); - return ci; - } - public int computeCompatModeLocked(ApplicationInfo ai) { - final boolean enabled = (getPackageFlags(ai.packageName)&COMPAT_FLAG_ENABLED) != 0; - final Configuration globalConfig = mService.getGlobalConfiguration(); - final CompatibilityInfo info = new CompatibilityInfo(ai, globalConfig.screenLayout, - globalConfig.smallestScreenWidthDp, enabled); + final CompatibilityInfo info = compatibilityInfoForPackageLocked(ai); if (info.alwaysSupportsScreen()) { return ActivityManager.COMPAT_MODE_NEVER; } if (info.neverSupportsScreen()) { return ActivityManager.COMPAT_MODE_ALWAYS; } - return enabled ? ActivityManager.COMPAT_MODE_ENABLED + return getPackageCompatModeEnabledLocked(ai) ? ActivityManager.COMPAT_MODE_ENABLED : ActivityManager.COMPAT_MODE_DISABLED; } @@ -307,6 +320,10 @@ public final class CompatModePackages { setPackageFlagLocked(packageName, COMPAT_FLAG_DONT_ASK, ask); } + private boolean getPackageCompatModeEnabledLocked(ApplicationInfo ai) { + return (getPackageFlags(ai.packageName) & COMPAT_FLAG_ENABLED) != 0; + } + private void setPackageFlagLocked(String packageName, int flag, boolean set) { final int curFlags = getPackageFlags(packageName); final int newFlags = set ? (curFlags & ~flag) : (curFlags | flag); @@ -443,9 +460,6 @@ public final class CompatModePackages { out.startTag(null, "compat-packages"); final IPackageManager pm = AppGlobals.getPackageManager(); - final Configuration globalConfig = mService.getGlobalConfiguration(); - final int screenLayout = globalConfig.screenLayout; - final int smallestScreenWidthDp = globalConfig.smallestScreenWidthDp; final Iterator> it = pkgs.entrySet().iterator(); while (it.hasNext()) { Map.Entry entry = it.next(); @@ -462,8 +476,7 @@ public final class CompatModePackages { if (ai == null) { continue; } - CompatibilityInfo info = new CompatibilityInfo(ai, screenLayout, - smallestScreenWidthDp, false); + final CompatibilityInfo info = compatibilityInfoForPackageLocked(ai); if (info.alwaysSupportsScreen()) { continue; } diff --git a/tests/DpiTest/src/com/google/android/test/dpi/DpiTestActivity.java b/tests/DpiTest/src/com/google/android/test/dpi/DpiTestActivity.java index 01c1c70f3f2a..cf501aed1dd5 100644 --- a/tests/DpiTest/src/com/google/android/test/dpi/DpiTestActivity.java +++ b/tests/DpiTest/src/com/google/android/test/dpi/DpiTestActivity.java @@ -19,23 +19,23 @@ package com.google.android.test.dpi; import android.app.Activity; import android.app.ActivityThread; import android.app.Application; -import android.os.Bundle; -import android.graphics.BitmapFactory; -import android.graphics.Bitmap; -import android.graphics.Canvas; -import android.graphics.drawable.BitmapDrawable; -import android.graphics.drawable.Drawable; -import android.widget.LinearLayout; -import android.widget.TextView; -import android.widget.ScrollView; -import android.view.LayoutInflater; -import android.view.View; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.res.CompatibilityInfo; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.Canvas; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; +import android.os.Bundle; import android.util.DisplayMetrics; import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.LinearLayout; +import android.widget.ScrollView; +import android.widget.TextView; public class DpiTestActivity extends Activity { public DpiTestActivity() { @@ -64,7 +64,7 @@ public class DpiTestActivity extends Activity { | ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES; app.getResources().setCompatibilityInfo(new CompatibilityInfo(ai, getResources().getConfiguration().screenLayout, - getResources().getConfiguration().smallestScreenWidthDp, false)); + getResources().getConfiguration().smallestScreenWidthDp, false, 1f)); } } catch (PackageManager.NameNotFoundException e) { throw new RuntimeException("ouch", e);