Loading core/java/android/app/ActivityThread.java +7 −3 Original line number Diff line number Diff line Loading @@ -36,7 +36,6 @@ import static android.view.Display.INVALID_DISPLAY; import static android.window.ConfigurationHelper.freeTextLayoutCachesIfNeeded; import static android.window.ConfigurationHelper.isDifferentDisplay; import static android.window.ConfigurationHelper.shouldUpdateResources; import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE; import static com.android.internal.os.SafeZipPathValidatorCallback.VALIDATE_ZIP_PATH_FOR_PATH_TRAVERSAL; Loading Loading @@ -1286,8 +1285,13 @@ public final class ActivityThread extends ClientTransactionHandler } private void updateCompatOverrideScale(CompatibilityInfo info) { CompatibilityInfo.setOverrideInvertedScale( info.hasOverrideScaling() ? info.applicationInvertedScale : 1f); if (info.hasOverrideScaling()) { CompatibilityInfo.setOverrideInvertedScale(info.applicationInvertedScale, info.applicationDensityInvertedScale); } else { CompatibilityInfo.setOverrideInvertedScale(/* invertScale */ 1f, /* densityInvertScale */1f); } } public final void runIsolatedEntryPoint(String entryPoint, String[] entryPointArgs) { Loading core/java/android/content/res/CompatibilityInfo.java +151 −29 Original line number Diff line number Diff line Loading @@ -112,9 +112,27 @@ public class CompatibilityInfo implements Parcelable { */ public final float applicationInvertedScale; /** * Application's density scale. * * <p>In most cases this is equal to {@link #applicationScale}, but in some cases e.g. * Automotive the requirement is to just scale the density and keep the resolution the same. * This is used for artificially making apps look zoomed in to compensate for the user distance * from the screen. */ public final float applicationDensityScale; /** * Application's density inverted scale. */ public final float applicationDensityInvertedScale; /** The process level override inverted scale. See {@link #HAS_OVERRIDE_SCALING}. */ private static float sOverrideInvertedScale = 1f; /** The process level override inverted density scale. See {@link #HAS_OVERRIDE_SCALING}. */ private static float sOverrideDensityInvertScale = 1f; @UnsupportedAppUsage @Deprecated public CompatibilityInfo(ApplicationInfo appInfo, int screenLayout, int sw, Loading @@ -123,17 +141,24 @@ public class CompatibilityInfo implements Parcelable { } public CompatibilityInfo(ApplicationInfo appInfo, int screenLayout, int sw, boolean forceCompat, float overrideScale) { boolean forceCompat, float scaleFactor) { this(appInfo, screenLayout, sw, forceCompat, scaleFactor, scaleFactor); } public CompatibilityInfo(ApplicationInfo appInfo, int screenLayout, int sw, boolean forceCompat, float scaleFactor, float densityScaleFactor) { int compatFlags = 0; if (appInfo.targetSdkVersion < VERSION_CODES.O) { compatFlags |= NEEDS_COMPAT_RES; } if (overrideScale != 1.0f) { applicationScale = overrideScale; applicationInvertedScale = 1.0f / overrideScale; if (scaleFactor != 1f || densityScaleFactor != 1f) { applicationScale = scaleFactor; applicationInvertedScale = 1f / scaleFactor; applicationDensityScale = densityScaleFactor; applicationDensityInvertedScale = 1f / densityScaleFactor; applicationDensity = (int) ((DisplayMetrics.DENSITY_DEVICE_STABLE * applicationInvertedScale) + .5f); * applicationDensityInvertedScale) + .5f); mCompatibilityFlags = NEVER_NEEDS_COMPAT | HAS_OVERRIDE_SCALING; // Override scale has the highest priority. So ignore other compatibility attributes. return; Loading Loading @@ -181,7 +206,8 @@ public class CompatibilityInfo implements Parcelable { applicationDensity = DisplayMetrics.DENSITY_DEVICE; applicationScale = 1.0f; applicationInvertedScale = 1.0f; applicationDensityScale = 1.0f; applicationDensityInvertedScale = 1.0f; } else { /** * Has the application said that its UI is expandable? Based on the Loading Loading @@ -271,11 +297,16 @@ public class CompatibilityInfo implements Parcelable { applicationDensity = DisplayMetrics.DENSITY_DEVICE; applicationScale = 1.0f; applicationInvertedScale = 1.0f; applicationDensityScale = 1.0f; applicationDensityInvertedScale = 1.0f; } else { applicationDensity = DisplayMetrics.DENSITY_DEFAULT; applicationScale = DisplayMetrics.DENSITY_DEVICE / (float) DisplayMetrics.DENSITY_DEFAULT; applicationInvertedScale = 1.0f / applicationScale; applicationDensityScale = DisplayMetrics.DENSITY_DEVICE / (float) DisplayMetrics.DENSITY_DEFAULT; applicationDensityInvertedScale = 1f / applicationDensityScale; compatFlags |= SCALING_REQUIRED; } } Loading @@ -289,6 +320,8 @@ public class CompatibilityInfo implements Parcelable { applicationDensity = dens; applicationScale = scale; applicationInvertedScale = invertedScale; applicationDensityScale = (float) DisplayMetrics.DENSITY_DEVICE_STABLE / dens; applicationDensityInvertedScale = 1f / applicationDensityScale; } @UnsupportedAppUsage Loading Loading @@ -528,7 +561,8 @@ public class CompatibilityInfo implements Parcelable { /** Applies the compatibility adjustment to the display metrics. */ public void applyDisplayMetricsIfNeeded(DisplayMetrics inoutDm, boolean applyToSize) { if (hasOverrideScale()) { scaleDisplayMetrics(sOverrideInvertedScale, inoutDm, applyToSize); scaleDisplayMetrics(sOverrideInvertedScale, sOverrideDensityInvertScale, inoutDm, applyToSize); return; } if (!equals(DEFAULT_COMPATIBILITY_INFO)) { Loading @@ -548,15 +582,17 @@ public class CompatibilityInfo implements Parcelable { } if (isScalingRequired()) { scaleDisplayMetrics(applicationInvertedScale, inoutDm, true /* applyToSize */); scaleDisplayMetrics(applicationInvertedScale, applicationDensityInvertedScale, inoutDm, true /* applyToSize */); } } /** Scales the density of the given display metrics. */ private static void scaleDisplayMetrics(float invertedRatio, DisplayMetrics inoutDm, boolean applyToSize) { inoutDm.density = inoutDm.noncompatDensity * invertedRatio; inoutDm.densityDpi = (int) ((inoutDm.noncompatDensityDpi * invertedRatio) + .5f); private static void scaleDisplayMetrics(float invertScale, float densityInvertScale, DisplayMetrics inoutDm, boolean applyToSize) { inoutDm.density = inoutDm.noncompatDensity * densityInvertScale; inoutDm.densityDpi = (int) ((inoutDm.noncompatDensityDpi * densityInvertScale) + .5f); // Note: since this is changing the scaledDensity, you might think we also need to change // inoutDm.fontScaleConverter to accurately calculate non-linear font scaling. But we're not // going to do that, for a couple of reasons (see b/265695259 for details): Loading @@ -570,12 +606,12 @@ public class CompatibilityInfo implements Parcelable { // b. Sometime later by WindowManager in onResume or other windowing events. In this case // the DisplayMetrics object is never used by the app/resources, so it's ok if // fontScaleConverter is null because it's not being used to scale fonts anyway. inoutDm.scaledDensity = inoutDm.noncompatScaledDensity * invertedRatio; inoutDm.xdpi = inoutDm.noncompatXdpi * invertedRatio; inoutDm.ydpi = inoutDm.noncompatYdpi * invertedRatio; inoutDm.scaledDensity = inoutDm.noncompatScaledDensity * densityInvertScale; inoutDm.xdpi = inoutDm.noncompatXdpi * densityInvertScale; inoutDm.ydpi = inoutDm.noncompatYdpi * densityInvertScale; if (applyToSize) { inoutDm.widthPixels = (int) (inoutDm.widthPixels * invertedRatio + 0.5f); inoutDm.heightPixels = (int) (inoutDm.heightPixels * invertedRatio + 0.5f); inoutDm.widthPixels = (int) (inoutDm.widthPixels * invertScale + 0.5f); inoutDm.heightPixels = (int) (inoutDm.heightPixels * invertScale + 0.5f); } } Loading @@ -594,38 +630,55 @@ public class CompatibilityInfo implements Parcelable { } inoutConfig.densityDpi = displayDensity; if (isScalingRequired()) { scaleConfiguration(applicationInvertedScale, inoutConfig); scaleConfiguration(applicationInvertedScale, applicationDensityInvertedScale, inoutConfig); } } /** Scales the density and bounds of the given configuration. */ public static void scaleConfiguration(float invertScale, Configuration inoutConfig) { scaleConfiguration(invertScale, invertScale, inoutConfig); } /** Scales the density and bounds of the given configuration. */ public static void scaleConfiguration(float invertedRatio, Configuration inoutConfig) { inoutConfig.densityDpi = (int) ((inoutConfig.densityDpi * invertedRatio) + .5f); inoutConfig.windowConfiguration.scale(invertedRatio); public static void scaleConfiguration(float invertScale, float densityInvertScale, Configuration inoutConfig) { inoutConfig.densityDpi = (int) ((inoutConfig.densityDpi * densityInvertScale) + .5f); inoutConfig.windowConfiguration.scale(invertScale); } /** @see #sOverrideInvertedScale */ public static void applyOverrideScaleIfNeeded(Configuration config) { if (!hasOverrideScale()) return; scaleConfiguration(sOverrideInvertedScale, config); scaleConfiguration(sOverrideInvertedScale, sOverrideDensityInvertScale, config); } /** @see #sOverrideInvertedScale */ public static void applyOverrideScaleIfNeeded(MergedConfiguration mergedConfig) { if (!hasOverrideScale()) return; scaleConfiguration(sOverrideInvertedScale, mergedConfig.getGlobalConfiguration()); scaleConfiguration(sOverrideInvertedScale, mergedConfig.getOverrideConfiguration()); scaleConfiguration(sOverrideInvertedScale, mergedConfig.getMergedConfiguration()); scaleConfiguration(sOverrideInvertedScale, sOverrideDensityInvertScale, mergedConfig.getGlobalConfiguration()); scaleConfiguration(sOverrideInvertedScale, sOverrideDensityInvertScale, mergedConfig.getOverrideConfiguration()); scaleConfiguration(sOverrideInvertedScale, sOverrideDensityInvertScale, mergedConfig.getMergedConfiguration()); } /** Returns {@code true} if this process is in a environment with override scale. */ private static boolean hasOverrideScale() { return sOverrideInvertedScale != 1f; return sOverrideInvertedScale != 1f || sOverrideDensityInvertScale != 1f; } /** @see #sOverrideInvertedScale */ public static void setOverrideInvertedScale(float invertedRatio) { sOverrideInvertedScale = invertedRatio; public static void setOverrideInvertedScale(float invertScale) { setOverrideInvertedScale(invertScale, invertScale); } /** @see #sOverrideInvertedScale */ public static void setOverrideInvertedScale(float invertScale, float densityInvertScale) { sOverrideInvertedScale = invertScale; sOverrideDensityInvertScale = densityInvertScale; } /** @see #sOverrideInvertedScale */ Loading @@ -633,6 +686,11 @@ public class CompatibilityInfo implements Parcelable { return sOverrideInvertedScale; } /** @see #sOverrideDensityInvertScale */ public static float getOverrideDensityInvertedScale() { return sOverrideDensityInvertScale; } /** * Compute the frame Rect for applications runs under compatibility mode. * Loading Loading @@ -693,6 +751,8 @@ public class CompatibilityInfo implements Parcelable { if (applicationDensity != oc.applicationDensity) return false; if (applicationScale != oc.applicationScale) return false; if (applicationInvertedScale != oc.applicationInvertedScale) return false; if (applicationDensityScale != oc.applicationDensityScale) return false; if (applicationDensityInvertedScale != oc.applicationDensityInvertedScale) return false; return true; } catch (ClassCastException e) { return false; Loading @@ -713,6 +773,8 @@ public class CompatibilityInfo implements Parcelable { if (hasOverrideScaling()) { sb.append(" overrideInvScale="); sb.append(applicationInvertedScale); sb.append(" overrideDensityInvScale="); sb.append(applicationDensityInvertedScale); } if (!supportsScreen()) { sb.append(" resizing"); Loading @@ -734,6 +796,8 @@ public class CompatibilityInfo implements Parcelable { result = 31 * result + applicationDensity; result = 31 * result + Float.floatToIntBits(applicationScale); result = 31 * result + Float.floatToIntBits(applicationInvertedScale); result = 31 * result + Float.floatToIntBits(applicationDensityScale); result = 31 * result + Float.floatToIntBits(applicationDensityInvertedScale); return result; } Loading @@ -748,6 +812,8 @@ public class CompatibilityInfo implements Parcelable { dest.writeInt(applicationDensity); dest.writeFloat(applicationScale); dest.writeFloat(applicationInvertedScale); dest.writeFloat(applicationDensityScale); dest.writeFloat(applicationDensityInvertedScale); } @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) Loading @@ -769,5 +835,61 @@ public class CompatibilityInfo implements Parcelable { applicationDensity = source.readInt(); applicationScale = source.readFloat(); applicationInvertedScale = source.readFloat(); applicationDensityScale = source.readFloat(); applicationDensityInvertedScale = source.readFloat(); } /** * A data class for holding scale factor for width, height, and density. */ public static final class CompatScale { public final float mScaleFactor; public final float mDensityScaleFactor; public CompatScale(float scaleFactor) { this(scaleFactor, scaleFactor); } public CompatScale(float scaleFactor, float densityScaleFactor) { mScaleFactor = scaleFactor; mDensityScaleFactor = densityScaleFactor; } @Override public boolean equals(@Nullable Object o) { if (this == o) { return true; } if (!(o instanceof CompatScale)) { return false; } try { CompatScale oc = (CompatScale) o; if (mScaleFactor != oc.mScaleFactor) return false; if (mDensityScaleFactor != oc.mDensityScaleFactor) return false; return true; } catch (ClassCastException e) { return false; } } @Override public String toString() { StringBuilder sb = new StringBuilder(128); sb.append("mScaleFactor= "); sb.append(mScaleFactor); sb.append(" mDensityScaleFactor= "); sb.append(mDensityScaleFactor); return sb.toString(); } @Override public int hashCode() { int result = 17; result = 31 * result + Float.floatToIntBits(mScaleFactor); result = 31 * result + Float.floatToIntBits(mDensityScaleFactor); return result; } } } services/core/java/com/android/server/wm/ActivityTaskManagerService.java +9 −1 Original line number Diff line number Diff line Loading @@ -68,7 +68,6 @@ import static android.view.WindowManager.TRANSIT_CHANGE; import static android.view.WindowManager.TRANSIT_PIP; import static android.view.WindowManager.TRANSIT_TO_FRONT; import static android.view.WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_TO_LAUNCHER_CLEAR_SNAPSHOT; import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_CONFIGURATION; import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_DREAM; import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_FOCUS; Loading Loading @@ -5631,6 +5630,15 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { } } void registerCompatScaleProvider(@CompatScaleProvider.CompatScaleModeOrderId int id, @NonNull CompatScaleProvider provider) { mCompatModePackages.registerCompatScaleProvider(id, provider); } void unregisterCompatScaleProvider(@CompatScaleProvider.CompatScaleModeOrderId int id) { mCompatModePackages.unregisterCompatScaleProvider(id); } /** * Returns {@code true} if the process represented by the pid passed as argument is * instrumented and the instrumentation source was granted with the permission also Loading services/core/java/com/android/server/wm/CompatModePackages.java +63 −2 Original line number Diff line number Diff line Loading @@ -20,7 +20,10 @@ import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_CONFIGURATION import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM; import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.wm.ActivityTaskSupervisor.PRESERVE_WINDOWS; import static com.android.server.wm.CompatScaleProvider.COMPAT_SCALE_MODE_SYSTEM_FIRST; import static com.android.server.wm.CompatScaleProvider.COMPAT_SCALE_MODE_SYSTEM_LAST; import android.annotation.NonNull; import android.app.ActivityManager; import android.app.AppGlobals; import android.app.GameManagerInternal; Loading @@ -32,6 +35,7 @@ import android.compat.annotation.Overridable; import android.content.pm.ApplicationInfo; import android.content.pm.IPackageManager; import android.content.res.CompatibilityInfo; import android.content.res.CompatibilityInfo.CompatScale; import android.content.res.Configuration; import android.os.Build; import android.os.Handler; Loading Loading @@ -332,6 +336,8 @@ public final class CompatModePackages { private final HashMap<String, Integer> mPackages = new HashMap<>(); private final CompatHandler mHandler; private final SparseArray<CompatScaleProvider> mProviders = new SparseArray<>(); public CompatModePackages(ActivityTaskManagerService service, File systemDir, Handler handler) { mService = service; mFile = new AtomicFile(new File(systemDir, "packages-compat.xml"), "compat-mode"); Loading Loading @@ -441,13 +447,38 @@ public final class CompatModePackages { public CompatibilityInfo compatibilityInfoForPackageLocked(ApplicationInfo ai) { final boolean forceCompat = getPackageCompatModeEnabledLocked(ai); final float compatScale = getCompatScale(ai.packageName, ai.uid); final CompatScale compatScale = getCompatScaleFromProvider(ai.packageName, ai.uid); final float appScale = compatScale != null ? compatScale.mScaleFactor : getCompatScale(ai.packageName, ai.uid, /* checkProvider= */ false); final float densityScale = compatScale != null ? compatScale.mDensityScaleFactor : 1f; final Configuration config = mService.getGlobalConfiguration(); return new CompatibilityInfo(ai, config.screenLayout, config.smallestScreenWidthDp, forceCompat, compatScale); forceCompat, appScale, densityScale); } float getCompatScale(String packageName, int uid) { return getCompatScale(packageName, uid, /* checkProvider= */ true); } private CompatScale getCompatScaleFromProvider(String packageName, int uid) { for (int i = 0; i < mProviders.size(); i++) { final CompatScaleProvider provider = mProviders.valueAt(i); final CompatScale compatScale = provider.getCompatScale(packageName, uid); if (compatScale != null) { return compatScale; } } return null; } private float getCompatScale(String packageName, int uid, boolean checkProviders) { if (checkProviders) { final CompatScale compatScale = getCompatScaleFromProvider(packageName, uid); if (compatScale != null) { return compatScale.mScaleFactor; } } final UserHandle userHandle = UserHandle.getUserHandleForUid(uid); if (mGameManager == null) { mGameManager = LocalServices.getService(GameManagerInternal.class); Loading Loading @@ -487,6 +518,36 @@ public final class CompatModePackages { return 1f; } void registerCompatScaleProvider(@CompatScaleProvider.CompatScaleModeOrderId int id, @NonNull CompatScaleProvider provider) { synchronized (mService.mGlobalLock) { if (mProviders.contains(id)) { throw new IllegalArgumentException("Duplicate id provided: " + id); } if (provider == null) { throw new IllegalArgumentException("The passed CompatScaleProvider " + "can not be null"); } if (!CompatScaleProvider.isValidOrderId(id)) { throw new IllegalArgumentException( "Provided id " + id + " is not in range of valid ids for system " + "services [" + COMPAT_SCALE_MODE_SYSTEM_FIRST + "," + COMPAT_SCALE_MODE_SYSTEM_LAST + "]"); } mProviders.put(id, provider); } } void unregisterCompatScaleProvider(@CompatScaleProvider.CompatScaleModeOrderId int id) { synchronized (mService.mGlobalLock) { if (!mProviders.contains(id)) { throw new IllegalArgumentException( "CompatScaleProvider with id (" + id + ") is not registered"); } mProviders.remove(id); } } private static float getScalingFactor(String packageName, UserHandle userHandle) { if (CompatChanges.isChangeEnabled(DOWNSCALE_90, packageName, userHandle)) { return 0.9f; Loading services/core/java/com/android/server/wm/CompatScaleProvider.java 0 → 100644 +86 −0 Original line number Diff line number Diff line /* * Copyright (C) 2023 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.server.wm; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.res.CompatibilityInfo.CompatScale; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; /** * An interface for services that need to provide compatibility scale different than * the default android compatibility. */ public interface CompatScaleProvider { /** * The unique id of each provider registered by a system service which determines the order * it will execute in. */ @IntDef(prefix = { "COMPAT_SCALE_MODE_" }, value = { // Order Ids for system services COMPAT_SCALE_MODE_SYSTEM_FIRST, COMPAT_SCALE_MODE_GAME, COMPAT_SCALE_MODE_PRODUCT, COMPAT_SCALE_MODE_SYSTEM_LAST, // Update this when adding new ids }) @Retention(RetentionPolicy.SOURCE) @interface CompatScaleModeOrderId {} /** * The first id, used by the framework to determine the valid range of ids. * @hide */ int COMPAT_SCALE_MODE_SYSTEM_FIRST = 0; /** * TODO(b/295207384) * The identifier for {@link android.app.GameManagerInternal} provider * @hide */ int COMPAT_SCALE_MODE_GAME = 1; /** * The identifier for a provider which is specific to the type of android product like * Automotive, Wear, TV etc. * @hide */ int COMPAT_SCALE_MODE_PRODUCT = 2; /** * The final id, used by the framework to determine the valid range of ids. Update this when * adding new ids. * @hide */ int COMPAT_SCALE_MODE_SYSTEM_LAST = COMPAT_SCALE_MODE_PRODUCT; /** * Returns {@code true} if the id is in the range of valid system services * @hide */ static boolean isValidOrderId(int id) { return (id >= COMPAT_SCALE_MODE_SYSTEM_FIRST && id <= COMPAT_SCALE_MODE_SYSTEM_LAST); } /** * @return an instance of {@link CompatScale} to apply for the given package */ @Nullable CompatScale getCompatScale(@NonNull String packageName, int uid); } Loading
core/java/android/app/ActivityThread.java +7 −3 Original line number Diff line number Diff line Loading @@ -36,7 +36,6 @@ import static android.view.Display.INVALID_DISPLAY; import static android.window.ConfigurationHelper.freeTextLayoutCachesIfNeeded; import static android.window.ConfigurationHelper.isDifferentDisplay; import static android.window.ConfigurationHelper.shouldUpdateResources; import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE; import static com.android.internal.os.SafeZipPathValidatorCallback.VALIDATE_ZIP_PATH_FOR_PATH_TRAVERSAL; Loading Loading @@ -1286,8 +1285,13 @@ public final class ActivityThread extends ClientTransactionHandler } private void updateCompatOverrideScale(CompatibilityInfo info) { CompatibilityInfo.setOverrideInvertedScale( info.hasOverrideScaling() ? info.applicationInvertedScale : 1f); if (info.hasOverrideScaling()) { CompatibilityInfo.setOverrideInvertedScale(info.applicationInvertedScale, info.applicationDensityInvertedScale); } else { CompatibilityInfo.setOverrideInvertedScale(/* invertScale */ 1f, /* densityInvertScale */1f); } } public final void runIsolatedEntryPoint(String entryPoint, String[] entryPointArgs) { Loading
core/java/android/content/res/CompatibilityInfo.java +151 −29 Original line number Diff line number Diff line Loading @@ -112,9 +112,27 @@ public class CompatibilityInfo implements Parcelable { */ public final float applicationInvertedScale; /** * Application's density scale. * * <p>In most cases this is equal to {@link #applicationScale}, but in some cases e.g. * Automotive the requirement is to just scale the density and keep the resolution the same. * This is used for artificially making apps look zoomed in to compensate for the user distance * from the screen. */ public final float applicationDensityScale; /** * Application's density inverted scale. */ public final float applicationDensityInvertedScale; /** The process level override inverted scale. See {@link #HAS_OVERRIDE_SCALING}. */ private static float sOverrideInvertedScale = 1f; /** The process level override inverted density scale. See {@link #HAS_OVERRIDE_SCALING}. */ private static float sOverrideDensityInvertScale = 1f; @UnsupportedAppUsage @Deprecated public CompatibilityInfo(ApplicationInfo appInfo, int screenLayout, int sw, Loading @@ -123,17 +141,24 @@ public class CompatibilityInfo implements Parcelable { } public CompatibilityInfo(ApplicationInfo appInfo, int screenLayout, int sw, boolean forceCompat, float overrideScale) { boolean forceCompat, float scaleFactor) { this(appInfo, screenLayout, sw, forceCompat, scaleFactor, scaleFactor); } public CompatibilityInfo(ApplicationInfo appInfo, int screenLayout, int sw, boolean forceCompat, float scaleFactor, float densityScaleFactor) { int compatFlags = 0; if (appInfo.targetSdkVersion < VERSION_CODES.O) { compatFlags |= NEEDS_COMPAT_RES; } if (overrideScale != 1.0f) { applicationScale = overrideScale; applicationInvertedScale = 1.0f / overrideScale; if (scaleFactor != 1f || densityScaleFactor != 1f) { applicationScale = scaleFactor; applicationInvertedScale = 1f / scaleFactor; applicationDensityScale = densityScaleFactor; applicationDensityInvertedScale = 1f / densityScaleFactor; applicationDensity = (int) ((DisplayMetrics.DENSITY_DEVICE_STABLE * applicationInvertedScale) + .5f); * applicationDensityInvertedScale) + .5f); mCompatibilityFlags = NEVER_NEEDS_COMPAT | HAS_OVERRIDE_SCALING; // Override scale has the highest priority. So ignore other compatibility attributes. return; Loading Loading @@ -181,7 +206,8 @@ public class CompatibilityInfo implements Parcelable { applicationDensity = DisplayMetrics.DENSITY_DEVICE; applicationScale = 1.0f; applicationInvertedScale = 1.0f; applicationDensityScale = 1.0f; applicationDensityInvertedScale = 1.0f; } else { /** * Has the application said that its UI is expandable? Based on the Loading Loading @@ -271,11 +297,16 @@ public class CompatibilityInfo implements Parcelable { applicationDensity = DisplayMetrics.DENSITY_DEVICE; applicationScale = 1.0f; applicationInvertedScale = 1.0f; applicationDensityScale = 1.0f; applicationDensityInvertedScale = 1.0f; } else { applicationDensity = DisplayMetrics.DENSITY_DEFAULT; applicationScale = DisplayMetrics.DENSITY_DEVICE / (float) DisplayMetrics.DENSITY_DEFAULT; applicationInvertedScale = 1.0f / applicationScale; applicationDensityScale = DisplayMetrics.DENSITY_DEVICE / (float) DisplayMetrics.DENSITY_DEFAULT; applicationDensityInvertedScale = 1f / applicationDensityScale; compatFlags |= SCALING_REQUIRED; } } Loading @@ -289,6 +320,8 @@ public class CompatibilityInfo implements Parcelable { applicationDensity = dens; applicationScale = scale; applicationInvertedScale = invertedScale; applicationDensityScale = (float) DisplayMetrics.DENSITY_DEVICE_STABLE / dens; applicationDensityInvertedScale = 1f / applicationDensityScale; } @UnsupportedAppUsage Loading Loading @@ -528,7 +561,8 @@ public class CompatibilityInfo implements Parcelable { /** Applies the compatibility adjustment to the display metrics. */ public void applyDisplayMetricsIfNeeded(DisplayMetrics inoutDm, boolean applyToSize) { if (hasOverrideScale()) { scaleDisplayMetrics(sOverrideInvertedScale, inoutDm, applyToSize); scaleDisplayMetrics(sOverrideInvertedScale, sOverrideDensityInvertScale, inoutDm, applyToSize); return; } if (!equals(DEFAULT_COMPATIBILITY_INFO)) { Loading @@ -548,15 +582,17 @@ public class CompatibilityInfo implements Parcelable { } if (isScalingRequired()) { scaleDisplayMetrics(applicationInvertedScale, inoutDm, true /* applyToSize */); scaleDisplayMetrics(applicationInvertedScale, applicationDensityInvertedScale, inoutDm, true /* applyToSize */); } } /** Scales the density of the given display metrics. */ private static void scaleDisplayMetrics(float invertedRatio, DisplayMetrics inoutDm, boolean applyToSize) { inoutDm.density = inoutDm.noncompatDensity * invertedRatio; inoutDm.densityDpi = (int) ((inoutDm.noncompatDensityDpi * invertedRatio) + .5f); private static void scaleDisplayMetrics(float invertScale, float densityInvertScale, DisplayMetrics inoutDm, boolean applyToSize) { inoutDm.density = inoutDm.noncompatDensity * densityInvertScale; inoutDm.densityDpi = (int) ((inoutDm.noncompatDensityDpi * densityInvertScale) + .5f); // Note: since this is changing the scaledDensity, you might think we also need to change // inoutDm.fontScaleConverter to accurately calculate non-linear font scaling. But we're not // going to do that, for a couple of reasons (see b/265695259 for details): Loading @@ -570,12 +606,12 @@ public class CompatibilityInfo implements Parcelable { // b. Sometime later by WindowManager in onResume or other windowing events. In this case // the DisplayMetrics object is never used by the app/resources, so it's ok if // fontScaleConverter is null because it's not being used to scale fonts anyway. inoutDm.scaledDensity = inoutDm.noncompatScaledDensity * invertedRatio; inoutDm.xdpi = inoutDm.noncompatXdpi * invertedRatio; inoutDm.ydpi = inoutDm.noncompatYdpi * invertedRatio; inoutDm.scaledDensity = inoutDm.noncompatScaledDensity * densityInvertScale; inoutDm.xdpi = inoutDm.noncompatXdpi * densityInvertScale; inoutDm.ydpi = inoutDm.noncompatYdpi * densityInvertScale; if (applyToSize) { inoutDm.widthPixels = (int) (inoutDm.widthPixels * invertedRatio + 0.5f); inoutDm.heightPixels = (int) (inoutDm.heightPixels * invertedRatio + 0.5f); inoutDm.widthPixels = (int) (inoutDm.widthPixels * invertScale + 0.5f); inoutDm.heightPixels = (int) (inoutDm.heightPixels * invertScale + 0.5f); } } Loading @@ -594,38 +630,55 @@ public class CompatibilityInfo implements Parcelable { } inoutConfig.densityDpi = displayDensity; if (isScalingRequired()) { scaleConfiguration(applicationInvertedScale, inoutConfig); scaleConfiguration(applicationInvertedScale, applicationDensityInvertedScale, inoutConfig); } } /** Scales the density and bounds of the given configuration. */ public static void scaleConfiguration(float invertScale, Configuration inoutConfig) { scaleConfiguration(invertScale, invertScale, inoutConfig); } /** Scales the density and bounds of the given configuration. */ public static void scaleConfiguration(float invertedRatio, Configuration inoutConfig) { inoutConfig.densityDpi = (int) ((inoutConfig.densityDpi * invertedRatio) + .5f); inoutConfig.windowConfiguration.scale(invertedRatio); public static void scaleConfiguration(float invertScale, float densityInvertScale, Configuration inoutConfig) { inoutConfig.densityDpi = (int) ((inoutConfig.densityDpi * densityInvertScale) + .5f); inoutConfig.windowConfiguration.scale(invertScale); } /** @see #sOverrideInvertedScale */ public static void applyOverrideScaleIfNeeded(Configuration config) { if (!hasOverrideScale()) return; scaleConfiguration(sOverrideInvertedScale, config); scaleConfiguration(sOverrideInvertedScale, sOverrideDensityInvertScale, config); } /** @see #sOverrideInvertedScale */ public static void applyOverrideScaleIfNeeded(MergedConfiguration mergedConfig) { if (!hasOverrideScale()) return; scaleConfiguration(sOverrideInvertedScale, mergedConfig.getGlobalConfiguration()); scaleConfiguration(sOverrideInvertedScale, mergedConfig.getOverrideConfiguration()); scaleConfiguration(sOverrideInvertedScale, mergedConfig.getMergedConfiguration()); scaleConfiguration(sOverrideInvertedScale, sOverrideDensityInvertScale, mergedConfig.getGlobalConfiguration()); scaleConfiguration(sOverrideInvertedScale, sOverrideDensityInvertScale, mergedConfig.getOverrideConfiguration()); scaleConfiguration(sOverrideInvertedScale, sOverrideDensityInvertScale, mergedConfig.getMergedConfiguration()); } /** Returns {@code true} if this process is in a environment with override scale. */ private static boolean hasOverrideScale() { return sOverrideInvertedScale != 1f; return sOverrideInvertedScale != 1f || sOverrideDensityInvertScale != 1f; } /** @see #sOverrideInvertedScale */ public static void setOverrideInvertedScale(float invertedRatio) { sOverrideInvertedScale = invertedRatio; public static void setOverrideInvertedScale(float invertScale) { setOverrideInvertedScale(invertScale, invertScale); } /** @see #sOverrideInvertedScale */ public static void setOverrideInvertedScale(float invertScale, float densityInvertScale) { sOverrideInvertedScale = invertScale; sOverrideDensityInvertScale = densityInvertScale; } /** @see #sOverrideInvertedScale */ Loading @@ -633,6 +686,11 @@ public class CompatibilityInfo implements Parcelable { return sOverrideInvertedScale; } /** @see #sOverrideDensityInvertScale */ public static float getOverrideDensityInvertedScale() { return sOverrideDensityInvertScale; } /** * Compute the frame Rect for applications runs under compatibility mode. * Loading Loading @@ -693,6 +751,8 @@ public class CompatibilityInfo implements Parcelable { if (applicationDensity != oc.applicationDensity) return false; if (applicationScale != oc.applicationScale) return false; if (applicationInvertedScale != oc.applicationInvertedScale) return false; if (applicationDensityScale != oc.applicationDensityScale) return false; if (applicationDensityInvertedScale != oc.applicationDensityInvertedScale) return false; return true; } catch (ClassCastException e) { return false; Loading @@ -713,6 +773,8 @@ public class CompatibilityInfo implements Parcelable { if (hasOverrideScaling()) { sb.append(" overrideInvScale="); sb.append(applicationInvertedScale); sb.append(" overrideDensityInvScale="); sb.append(applicationDensityInvertedScale); } if (!supportsScreen()) { sb.append(" resizing"); Loading @@ -734,6 +796,8 @@ public class CompatibilityInfo implements Parcelable { result = 31 * result + applicationDensity; result = 31 * result + Float.floatToIntBits(applicationScale); result = 31 * result + Float.floatToIntBits(applicationInvertedScale); result = 31 * result + Float.floatToIntBits(applicationDensityScale); result = 31 * result + Float.floatToIntBits(applicationDensityInvertedScale); return result; } Loading @@ -748,6 +812,8 @@ public class CompatibilityInfo implements Parcelable { dest.writeInt(applicationDensity); dest.writeFloat(applicationScale); dest.writeFloat(applicationInvertedScale); dest.writeFloat(applicationDensityScale); dest.writeFloat(applicationDensityInvertedScale); } @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) Loading @@ -769,5 +835,61 @@ public class CompatibilityInfo implements Parcelable { applicationDensity = source.readInt(); applicationScale = source.readFloat(); applicationInvertedScale = source.readFloat(); applicationDensityScale = source.readFloat(); applicationDensityInvertedScale = source.readFloat(); } /** * A data class for holding scale factor for width, height, and density. */ public static final class CompatScale { public final float mScaleFactor; public final float mDensityScaleFactor; public CompatScale(float scaleFactor) { this(scaleFactor, scaleFactor); } public CompatScale(float scaleFactor, float densityScaleFactor) { mScaleFactor = scaleFactor; mDensityScaleFactor = densityScaleFactor; } @Override public boolean equals(@Nullable Object o) { if (this == o) { return true; } if (!(o instanceof CompatScale)) { return false; } try { CompatScale oc = (CompatScale) o; if (mScaleFactor != oc.mScaleFactor) return false; if (mDensityScaleFactor != oc.mDensityScaleFactor) return false; return true; } catch (ClassCastException e) { return false; } } @Override public String toString() { StringBuilder sb = new StringBuilder(128); sb.append("mScaleFactor= "); sb.append(mScaleFactor); sb.append(" mDensityScaleFactor= "); sb.append(mDensityScaleFactor); return sb.toString(); } @Override public int hashCode() { int result = 17; result = 31 * result + Float.floatToIntBits(mScaleFactor); result = 31 * result + Float.floatToIntBits(mDensityScaleFactor); return result; } } }
services/core/java/com/android/server/wm/ActivityTaskManagerService.java +9 −1 Original line number Diff line number Diff line Loading @@ -68,7 +68,6 @@ import static android.view.WindowManager.TRANSIT_CHANGE; import static android.view.WindowManager.TRANSIT_PIP; import static android.view.WindowManager.TRANSIT_TO_FRONT; import static android.view.WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_TO_LAUNCHER_CLEAR_SNAPSHOT; import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_CONFIGURATION; import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_DREAM; import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_FOCUS; Loading Loading @@ -5631,6 +5630,15 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { } } void registerCompatScaleProvider(@CompatScaleProvider.CompatScaleModeOrderId int id, @NonNull CompatScaleProvider provider) { mCompatModePackages.registerCompatScaleProvider(id, provider); } void unregisterCompatScaleProvider(@CompatScaleProvider.CompatScaleModeOrderId int id) { mCompatModePackages.unregisterCompatScaleProvider(id); } /** * Returns {@code true} if the process represented by the pid passed as argument is * instrumented and the instrumentation source was granted with the permission also Loading
services/core/java/com/android/server/wm/CompatModePackages.java +63 −2 Original line number Diff line number Diff line Loading @@ -20,7 +20,10 @@ import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_CONFIGURATION import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM; import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.wm.ActivityTaskSupervisor.PRESERVE_WINDOWS; import static com.android.server.wm.CompatScaleProvider.COMPAT_SCALE_MODE_SYSTEM_FIRST; import static com.android.server.wm.CompatScaleProvider.COMPAT_SCALE_MODE_SYSTEM_LAST; import android.annotation.NonNull; import android.app.ActivityManager; import android.app.AppGlobals; import android.app.GameManagerInternal; Loading @@ -32,6 +35,7 @@ import android.compat.annotation.Overridable; import android.content.pm.ApplicationInfo; import android.content.pm.IPackageManager; import android.content.res.CompatibilityInfo; import android.content.res.CompatibilityInfo.CompatScale; import android.content.res.Configuration; import android.os.Build; import android.os.Handler; Loading Loading @@ -332,6 +336,8 @@ public final class CompatModePackages { private final HashMap<String, Integer> mPackages = new HashMap<>(); private final CompatHandler mHandler; private final SparseArray<CompatScaleProvider> mProviders = new SparseArray<>(); public CompatModePackages(ActivityTaskManagerService service, File systemDir, Handler handler) { mService = service; mFile = new AtomicFile(new File(systemDir, "packages-compat.xml"), "compat-mode"); Loading Loading @@ -441,13 +447,38 @@ public final class CompatModePackages { public CompatibilityInfo compatibilityInfoForPackageLocked(ApplicationInfo ai) { final boolean forceCompat = getPackageCompatModeEnabledLocked(ai); final float compatScale = getCompatScale(ai.packageName, ai.uid); final CompatScale compatScale = getCompatScaleFromProvider(ai.packageName, ai.uid); final float appScale = compatScale != null ? compatScale.mScaleFactor : getCompatScale(ai.packageName, ai.uid, /* checkProvider= */ false); final float densityScale = compatScale != null ? compatScale.mDensityScaleFactor : 1f; final Configuration config = mService.getGlobalConfiguration(); return new CompatibilityInfo(ai, config.screenLayout, config.smallestScreenWidthDp, forceCompat, compatScale); forceCompat, appScale, densityScale); } float getCompatScale(String packageName, int uid) { return getCompatScale(packageName, uid, /* checkProvider= */ true); } private CompatScale getCompatScaleFromProvider(String packageName, int uid) { for (int i = 0; i < mProviders.size(); i++) { final CompatScaleProvider provider = mProviders.valueAt(i); final CompatScale compatScale = provider.getCompatScale(packageName, uid); if (compatScale != null) { return compatScale; } } return null; } private float getCompatScale(String packageName, int uid, boolean checkProviders) { if (checkProviders) { final CompatScale compatScale = getCompatScaleFromProvider(packageName, uid); if (compatScale != null) { return compatScale.mScaleFactor; } } final UserHandle userHandle = UserHandle.getUserHandleForUid(uid); if (mGameManager == null) { mGameManager = LocalServices.getService(GameManagerInternal.class); Loading Loading @@ -487,6 +518,36 @@ public final class CompatModePackages { return 1f; } void registerCompatScaleProvider(@CompatScaleProvider.CompatScaleModeOrderId int id, @NonNull CompatScaleProvider provider) { synchronized (mService.mGlobalLock) { if (mProviders.contains(id)) { throw new IllegalArgumentException("Duplicate id provided: " + id); } if (provider == null) { throw new IllegalArgumentException("The passed CompatScaleProvider " + "can not be null"); } if (!CompatScaleProvider.isValidOrderId(id)) { throw new IllegalArgumentException( "Provided id " + id + " is not in range of valid ids for system " + "services [" + COMPAT_SCALE_MODE_SYSTEM_FIRST + "," + COMPAT_SCALE_MODE_SYSTEM_LAST + "]"); } mProviders.put(id, provider); } } void unregisterCompatScaleProvider(@CompatScaleProvider.CompatScaleModeOrderId int id) { synchronized (mService.mGlobalLock) { if (!mProviders.contains(id)) { throw new IllegalArgumentException( "CompatScaleProvider with id (" + id + ") is not registered"); } mProviders.remove(id); } } private static float getScalingFactor(String packageName, UserHandle userHandle) { if (CompatChanges.isChangeEnabled(DOWNSCALE_90, packageName, userHandle)) { return 0.9f; Loading
services/core/java/com/android/server/wm/CompatScaleProvider.java 0 → 100644 +86 −0 Original line number Diff line number Diff line /* * Copyright (C) 2023 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.server.wm; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.res.CompatibilityInfo.CompatScale; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; /** * An interface for services that need to provide compatibility scale different than * the default android compatibility. */ public interface CompatScaleProvider { /** * The unique id of each provider registered by a system service which determines the order * it will execute in. */ @IntDef(prefix = { "COMPAT_SCALE_MODE_" }, value = { // Order Ids for system services COMPAT_SCALE_MODE_SYSTEM_FIRST, COMPAT_SCALE_MODE_GAME, COMPAT_SCALE_MODE_PRODUCT, COMPAT_SCALE_MODE_SYSTEM_LAST, // Update this when adding new ids }) @Retention(RetentionPolicy.SOURCE) @interface CompatScaleModeOrderId {} /** * The first id, used by the framework to determine the valid range of ids. * @hide */ int COMPAT_SCALE_MODE_SYSTEM_FIRST = 0; /** * TODO(b/295207384) * The identifier for {@link android.app.GameManagerInternal} provider * @hide */ int COMPAT_SCALE_MODE_GAME = 1; /** * The identifier for a provider which is specific to the type of android product like * Automotive, Wear, TV etc. * @hide */ int COMPAT_SCALE_MODE_PRODUCT = 2; /** * The final id, used by the framework to determine the valid range of ids. Update this when * adding new ids. * @hide */ int COMPAT_SCALE_MODE_SYSTEM_LAST = COMPAT_SCALE_MODE_PRODUCT; /** * Returns {@code true} if the id is in the range of valid system services * @hide */ static boolean isValidOrderId(int id) { return (id >= COMPAT_SCALE_MODE_SYSTEM_FIRST && id <= COMPAT_SCALE_MODE_SYSTEM_LAST); } /** * @return an instance of {@link CompatScale} to apply for the given package */ @Nullable CompatScale getCompatScale(@NonNull String packageName, int uid); }