diff options
3 files changed, 132 insertions, 8 deletions
diff --git a/core/java/android/content/res/CompatibilityInfo.java b/core/java/android/content/res/CompatibilityInfo.java index f6edb2edc5ff..abf694f9742e 100644 --- a/core/java/android/content/res/CompatibilityInfo.java +++ b/core/java/android/content/res/CompatibilityInfo.java @@ -89,6 +89,11 @@ public class CompatibilityInfo implements Parcelable { private static final int NEEDS_COMPAT_RES = 16; /** + * Set if the application needs to be forcibly downscaled + */ + private static final int HAS_OVERRIDE_SCALING = 32; + + /** * The effective screen density we have selected for this application. */ public final int applicationDensity; @@ -107,6 +112,11 @@ public class CompatibilityInfo implements Parcelable { @UnsupportedAppUsage public CompatibilityInfo(ApplicationInfo appInfo, int screenLayout, int sw, boolean forceCompat) { + this(appInfo, screenLayout, sw, forceCompat, 1f); + } + + public CompatibilityInfo(ApplicationInfo appInfo, int screenLayout, int sw, + boolean forceCompat, float overrideScale) { int compatFlags = 0; if (appInfo.targetSdkVersion < VERSION_CODES.O) { @@ -241,7 +251,12 @@ public class CompatibilityInfo implements Parcelable { compatFlags |= NEVER_NEEDS_COMPAT; } - if ((appInfo.flags & ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES) != 0) { + if (overrideScale != 1.0f) { + applicationDensity = DisplayMetrics.DENSITY_DEFAULT; + applicationScale = overrideScale; + applicationInvertedScale = 1.0f / overrideScale; + compatFlags |= HAS_OVERRIDE_SCALING; + } else if ((appInfo.flags & ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES) != 0) { applicationDensity = DisplayMetrics.DENSITY_DEVICE; applicationScale = 1.0f; applicationInvertedScale = 1.0f; @@ -277,7 +292,7 @@ public class CompatibilityInfo implements Parcelable { */ @UnsupportedAppUsage public boolean isScalingRequired() { - return (mCompatibilityFlags&SCALING_REQUIRED) != 0; + return (mCompatibilityFlags & (SCALING_REQUIRED | HAS_OVERRIDE_SCALING)) != 0; } @UnsupportedAppUsage @@ -303,7 +318,7 @@ public class CompatibilityInfo implements Parcelable { */ @UnsupportedAppUsage public Translator getTranslator() { - return isScalingRequired() ? new Translator() : null; + return (mCompatibilityFlags & SCALING_REQUIRED) != 0 ? new Translator() : null; } /** @@ -504,6 +519,16 @@ public class CompatibilityInfo implements Parcelable { if (isScalingRequired()) { float invertedRatio = applicationInvertedScale; inoutConfig.densityDpi = (int)((inoutConfig.densityDpi * invertedRatio) + .5f); + inoutConfig.screenWidthDp = (int) ((inoutConfig.screenWidthDp * invertedRatio) + .5f); + inoutConfig.screenHeightDp = (int) ((inoutConfig.screenHeightDp * invertedRatio) + .5f); + inoutConfig.smallestScreenWidthDp = + (int) ((inoutConfig.smallestScreenWidthDp * invertedRatio) + .5f); + inoutConfig.windowConfiguration.getMaxBounds().scale(invertedRatio); + inoutConfig.windowConfiguration.getBounds().scale(invertedRatio); + final Rect appBounds = inoutConfig.windowConfiguration.getAppBounds(); + if (appBounds != null) { + appBounds.scale(invertedRatio); + } } } diff --git a/services/core/java/com/android/server/wm/CompatModePackages.java b/services/core/java/com/android/server/wm/CompatModePackages.java index dbad8b364270..a725dd34fbf6 100644 --- a/services/core/java/com/android/server/wm/CompatModePackages.java +++ b/services/core/java/com/android/server/wm/CompatModePackages.java @@ -24,6 +24,9 @@ import static com.android.server.wm.ActivityTaskSupervisor.PRESERVE_WINDOWS; import android.app.ActivityManager; import android.app.AppGlobals; +import android.app.compat.CompatChanges; +import android.compat.annotation.ChangeId; +import android.compat.annotation.Disabled; import android.content.pm.ApplicationInfo; import android.content.pm.IPackageManager; import android.content.res.CompatibilityInfo; @@ -32,6 +35,7 @@ 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.Slog; import android.util.SparseArray; @@ -63,6 +67,58 @@ public final class CompatModePackages { // Compatibility state: compatibility mode is enabled. private static final int COMPAT_FLAG_ENABLED = 1<<1; + /** + * CompatModePackages#DOWNSCALED is the gatekeeper of all per-app buffer downscaling + * changes. Disabling this change will prevent the following scaling factors from working: + * CompatModePackages#DOWNSCALE_87_5 + * CompatModePackages#DOWNSCALE_75 + * CompatModePackages#DOWNSCALE_62_5 + * CompatModePackages#DOWNSCALE_50 + * + * If CompatModePackages#DOWNSCALED is enabled for an app package, then the app will be forcibly + * resized to the highest enabled scaling factor e.g. 87.5% if both 87.5% and 75% were + * enabled. + */ + @ChangeId + @Disabled + private static final long DOWNSCALED = 168419799L; + + /** + * With CompatModePackages#DOWNSCALED enabled, subsequently enabling change-id + * CompatModePackages#DOWNSCALE_87_5 for a package will force the app to assume it's + * running on a display with 87.5% the vertical and horizontal resolution of the real display. + */ + @ChangeId + @Disabled + private static final long DOWNSCALE_87_5 = 176926753L; + + /** + * With CompatModePackages#DOWNSCALED enabled, subsequently enabling change-id + * CompatModePackages#DOWNSCALE_75 for a package will force the app to assume it's + * running on a display with 75% the vertical and horizontal resolution of the real display. + */ + @ChangeId + @Disabled + private static final long DOWNSCALE_75 = 176926829L; + + /** + * With CompatModePackages#DOWNSCALED enabled, subsequently enabling change-id + * CompatModePackages#DOWNSCALE_62_5 for a package will force the app to assume it's + * running on a display with 62.5% the vertical and horizontal resolution of the real display. + */ + @ChangeId + @Disabled + private static final long DOWNSCALE_62_5 = 176926771L; + + /** + * With CompatModePackages#DOWNSCALED enabled, subsequently enabling change-id + * CompatModePackages#DOWNSCALE_50 for a package will force the app to assume it's + * running on a display with 50% vertical and horizontal resolution of the real display. + */ + @ChangeId + @Disabled + private static final long DOWNSCALE_50 = 176926741L; + private final HashMap<String, Integer> mPackages = new HashMap<String, Integer>(); private static final int MSG_WRITE = 300; @@ -191,11 +247,39 @@ public final class CompatModePackages { mHandler.sendMessageDelayed(msg, 10000); } + float getCompatScale(String packageName, int uid) { + if (!CompatChanges.isChangeEnabled( + DOWNSCALED, packageName, UserHandle.getUserHandleForUid(uid))) { + return 1f; + } + 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; + } + 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); + (getPackageFlags(ai.packageName) & COMPAT_FLAG_ENABLED) != 0, requestedScale); //Slog.i(TAG, "*********** COMPAT FOR PKG " + ai.packageName + ": " + ci); return ci; } diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index f2be5ffb2ab2..025037688c8c 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -441,6 +441,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP float mGlobalScale=1; float mLastGlobalScale=1; float mInvGlobalScale=1; + float mOverrideScale = 1; float mHScale=1, mVScale=1; float mLastHScale=1, mLastVScale=1; final Matrix mTmpMatrix = new Matrix(); @@ -1014,6 +1015,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP mLastRequestedWidth = 0; mLastRequestedHeight = 0; mLayer = 0; + mOverrideScale = mWmService.mAtmService.mCompatModePackages.getCompatScale( + mAttrs.packageName, s.mUid); // Make sure we initial all fields before adding to parentWindow, to prevent exception // during onDisplayChanged. @@ -1046,8 +1049,15 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP mSession.windowAddedLocked(mAttrs.packageName); } + /** + * @return {@code true} if the application runs in size compatibility mode or has an app level + * scaling override set. + * @see CompatModePackages#getCompatScale + * @see android.content.res.CompatibilityInfo#supportsScreen + * @see ActivityRecord#inSizeCompatMode() + */ boolean inSizeCompatMode() { - return inSizeCompatMode(mAttrs, mActivityRecord); + return mOverrideScale != 1f || inSizeCompatMode(mAttrs, mActivityRecord); } /** @@ -1682,7 +1692,13 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP void prelayout() { if (inSizeCompatMode()) { - mGlobalScale = mToken.getSizeCompatScale(); + if (mOverrideScale != 1f) { + mGlobalScale = mToken.hasSizeCompatBounds() + ? mToken.getSizeCompatScale() * mOverrideScale + : mOverrideScale; + } else { + mGlobalScale = mToken.getSizeCompatScale(); + } mInvGlobalScale = 1 / mGlobalScale; } else { mGlobalScale = mInvGlobalScale = 1; @@ -2640,8 +2656,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP // scaling but the existing logic doesn't expect that. The result is that the already- // scaled region ends up getting sent to surfaceflinger which then applies the scale // (again). Until this is resolved, apply an inverse-scale here. - if (mActivityRecord != null && mActivityRecord.hasSizeCompatBounds() - && mGlobalScale != 1.f) { + if (mInvGlobalScale != 1.f) { region.scale(mInvGlobalScale); } |