diff options
| author | 2023-07-13 16:38:38 +0000 | |
|---|---|---|
| committer | 2023-09-08 21:18:33 +0000 | |
| commit | f2bcb596c256ac9ea35cea205b3619defb73ffd0 (patch) | |
| tree | 51ca4ca321db91f1c4ad1ae3ce5ccd9a6bbc4c1c | |
| parent | d3965882d85bc4f57c9e01c5ebda70498218cfc5 (diff) | |
Add CompatScaleProvider interface
Currently TV, and game service have their specific code in core
framework which is shared with all the platforms.
Adding CompatScaleProvider interface so that the per service logic
can move out of core framework.
Bug: 291638620
Test: atest WmTests:CompatScaleProviderTest
Change-Id: I14cc656a50386b07e31811173e735dbe41324d7c
6 files changed, 482 insertions, 35 deletions
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 39589fa93149..f28b4b4eb207 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -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; @@ -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) { diff --git a/core/java/android/content/res/CompatibilityInfo.java b/core/java/android/content/res/CompatibilityInfo.java index 08ba5b6c268c..f929c1f03c87 100644 --- a/core/java/android/content/res/CompatibilityInfo.java +++ b/core/java/android/content/res/CompatibilityInfo.java @@ -100,7 +100,7 @@ public class CompatibilityInfo implements Parcelable { * The effective screen density we have selected for this application. */ public final int applicationDensity; - + /** * Application's scale. */ @@ -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, @@ -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; @@ -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 @@ -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; } } @@ -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 @@ -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)) { @@ -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): @@ -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); } } @@ -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 invertedRatio, Configuration inoutConfig) { - inoutConfig.densityDpi = (int) ((inoutConfig.densityDpi * invertedRatio) + .5f); - inoutConfig.windowConfiguration.scale(invertedRatio); + 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 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 */ @@ -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. * @@ -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; @@ -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"); @@ -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; } @@ -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) @@ -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; + } } } diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java index fd42077bed7d..f47007b28e5b 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java @@ -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; @@ -5628,6 +5627,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 diff --git a/services/core/java/com/android/server/wm/CompatModePackages.java b/services/core/java/com/android/server/wm/CompatModePackages.java index c6978fd59134..e906b185bae7 100644 --- a/services/core/java/com/android/server/wm/CompatModePackages.java +++ b/services/core/java/com/android/server/wm/CompatModePackages.java @@ -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; @@ -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; @@ -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"); @@ -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); @@ -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; diff --git a/services/core/java/com/android/server/wm/CompatScaleProvider.java b/services/core/java/com/android/server/wm/CompatScaleProvider.java new file mode 100644 index 000000000000..5474ecec381a --- /dev/null +++ b/services/core/java/com/android/server/wm/CompatScaleProvider.java @@ -0,0 +1,86 @@ +/* + * 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); +} diff --git a/services/tests/wmtests/src/com/android/server/wm/CompatScaleProviderTest.java b/services/tests/wmtests/src/com/android/server/wm/CompatScaleProviderTest.java new file mode 100644 index 000000000000..96e3cb1030ce --- /dev/null +++ b/services/tests/wmtests/src/com/android/server/wm/CompatScaleProviderTest.java @@ -0,0 +1,166 @@ +/* + * 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 static com.android.dx.mockito.inline.extended.ExtendedMockito.mock; +import static org.junit.Assert.assertThrows; +import static org.mockito.Mockito.inOrder; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +import android.platform.test.annotations.Presubmit; + +import androidx.test.filters.SmallTest; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.InOrder; + +/** + * Tests for the {@link CompatScaleProvider} interface. + * See {@link CompatModePackages} class for implementation. + * + * Build/Install/Run: + * atest WmTests:CompatScaleProviderTest + */ +@SmallTest +@Presubmit +public class CompatScaleProviderTest extends SystemServiceTestsBase { + private static final String TEST_PACKAGE = "compat.mode.packages"; + static final int TEST_USER_ID = 1; + + private ActivityTaskManagerService mAtm; + + /** + * setup method before every test. + */ + @Before + public void setUp() { + mAtm = mSystemServicesTestRule.getActivityTaskManagerService(); + } + + /** + * Registering a {@link CompatScaleProvider} with an invalid id should throw an exception. + */ + @Test + public void registerCompatScaleProviderWithInvalidId() { + CompatScaleProvider compatScaleProvider = mock(CompatScaleProvider.class); + assertThrows( + IllegalArgumentException.class, + () -> mAtm.registerCompatScaleProvider(-1, compatScaleProvider) + ); + } + + /** + * Registering a {@code null} {@link CompatScaleProvider} should throw an exception. + */ + @Test + public void registerCompatScaleProviderFailIfCallbackIsNull() { + assertThrows( + IllegalArgumentException.class, + () -> mAtm.registerCompatScaleProvider( + CompatScaleProvider.COMPAT_SCALE_MODE_PRODUCT, null) + ); + } + + /** + * Registering a {@link CompatScaleProvider} with a already registered id should throw an + * exception. + */ + @Test + public void registerCompatScaleProviderFailIfIdIsAlreadyRegistered() { + CompatScaleProvider compatScaleProvider = mock(CompatScaleProvider.class); + mAtm.registerCompatScaleProvider(CompatScaleProvider.COMPAT_SCALE_MODE_PRODUCT, + compatScaleProvider); + assertThrows( + IllegalArgumentException.class, + () -> mAtm.registerCompatScaleProvider( + CompatScaleProvider.COMPAT_SCALE_MODE_PRODUCT, compatScaleProvider) + ); + mAtm.unregisterCompatScaleProvider(CompatScaleProvider.COMPAT_SCALE_MODE_PRODUCT); + } + + /** + * Successfully registering a {@link CompatScaleProvider} with should result in callbacks + * getting called. + */ + @Test + public void registerCompatScaleProviderSuccessfully() { + CompatScaleProvider compatScaleProvider = mock(CompatScaleProvider.class); + mAtm.registerCompatScaleProvider(CompatScaleProvider.COMPAT_SCALE_MODE_PRODUCT, + compatScaleProvider); + mAtm.mCompatModePackages.getCompatScale(TEST_PACKAGE, TEST_USER_ID); + verify(compatScaleProvider, times(1)).getCompatScale(TEST_PACKAGE, TEST_USER_ID); + mAtm.unregisterCompatScaleProvider(CompatScaleProvider.COMPAT_SCALE_MODE_PRODUCT); + } + + /** + * Unregistering a {@link CompatScaleProvider} with a unregistered id should throw an exception. + */ + @Test + public void unregisterCompatScaleProviderFailIfIdNotRegistered() { + assertThrows( + IllegalArgumentException.class, + () -> mAtm.unregisterCompatScaleProvider( + CompatScaleProvider.COMPAT_SCALE_MODE_PRODUCT) + ); + } + + /** + * Unregistering a {@link CompatScaleProvider} with an invalid id should throw an exception. + */ + @Test + public void unregisterCompatScaleProviderFailIfIdNotInRange() { + assertThrows( + IllegalArgumentException.class, + () -> mAtm.unregisterCompatScaleProvider(-1) + ); + } + + /** + * Successfully unregistering a {@link CompatScaleProvider} should stop the callbacks from + * getting called. + */ + @Test + public void unregisterCompatScaleProviderSuccessfully() { + CompatScaleProvider compatScaleProvider = mock(CompatScaleProvider.class); + mAtm.registerCompatScaleProvider(CompatScaleProvider.COMPAT_SCALE_MODE_PRODUCT, + compatScaleProvider); + mAtm.unregisterCompatScaleProvider(CompatScaleProvider.COMPAT_SCALE_MODE_PRODUCT); + mAtm.mCompatModePackages.getCompatScale(TEST_PACKAGE, TEST_USER_ID); + verify(compatScaleProvider, never()).getCompatScale(TEST_PACKAGE, TEST_USER_ID); + } + + /** + * Order of calling {@link CompatScaleProvider} is same as the id that was used for + * registering it. + */ + @Test + public void registerCompatScaleProviderRespectsOrderId() { + CompatScaleProvider gameModeCompatScaleProvider = mock(CompatScaleProvider.class); + CompatScaleProvider productCompatScaleProvider = mock(CompatScaleProvider.class); + mAtm.registerCompatScaleProvider(CompatScaleProvider.COMPAT_SCALE_MODE_GAME, + gameModeCompatScaleProvider); + mAtm.registerCompatScaleProvider(CompatScaleProvider.COMPAT_SCALE_MODE_PRODUCT, + productCompatScaleProvider); + mAtm.mCompatModePackages.getCompatScale(TEST_PACKAGE, TEST_USER_ID); + InOrder inOrder = inOrder(gameModeCompatScaleProvider, productCompatScaleProvider); + inOrder.verify(gameModeCompatScaleProvider).getCompatScale(TEST_PACKAGE, TEST_USER_ID); + inOrder.verify(productCompatScaleProvider).getCompatScale(TEST_PACKAGE, TEST_USER_ID); + } +} |