| /* |
| * Copyright (C) 2021 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 android.server.wm; |
| |
| import static android.server.wm.app.Components.UI_SCALING_TEST_ACTIVITY; |
| |
| import static org.junit.Assert.assertEquals; |
| import static org.junit.Assert.assertFalse; |
| import static org.junit.Assert.assertNotNull; |
| import static org.junit.Assert.assertTrue; |
| |
| import android.content.ComponentName; |
| |
| import org.junit.After; |
| import org.junit.Before; |
| import org.junit.Test; |
| import org.junit.runner.RunWith; |
| import org.junit.runners.Parameterized; |
| |
| import java.util.Arrays; |
| |
| /** |
| * The test is focused on compatibility scaling, and tests the feature form two sides. |
| * 1. It checks that the applications "sees" the metrics in PXs, but the DP metrics remain the same. |
| * 2. It checks the WindowManagerServer state, and makes sure that the scaling is correctly |
| * reflected in the WindowState. |
| * |
| * This is achieved by launching a {@link android.server.wm.app.UiScalingTestActivity} and having it |
| * reporting the metrics it receives. |
| * The Activity also draws 3 UI elements: a text, a red square with a 100dp side and a blue square |
| * with a 100px side. |
| * The text and the red square should have the same when rendered on the screen (by HWC) both when |
| * the compat downscaling is enabled and disabled. |
| * TODO(b/180098454): Add tests to make sure that the UI elements, which have their sizes declared |
| * in DPs (the text and the red square) have the same sizes on the screen (after composition). |
| * |
| * <p>Build/Install/Run: |
| * atest CtsWindowManagerDeviceTestCases:CompatScaleTests |
| */ |
| @RunWith(Parameterized.class) |
| public class CompatScaleTests extends ActivityManagerTestBase { |
| |
| @Parameterized.Parameters(name = "{0}") |
| public static Iterable<Object[]> data() { |
| return Arrays.asList(new Object[][] { |
| { "DOWNSCALE_50", 0.5f }, |
| { "DOWNSCALE_60", 0.6f }, |
| { "DOWNSCALE_70", 0.7f }, |
| { "DOWNSCALE_80", 0.8f }, |
| { "DOWNSCALE_90", 0.9f }, |
| }); |
| } |
| |
| private static final ComponentName ACTIVITY_UNDER_TEST = UI_SCALING_TEST_ACTIVITY; |
| private static final String PACKAGE_UNDER_TEST = ACTIVITY_UNDER_TEST.getPackageName(); |
| private static final float EPSILON_GLOBAL_SCALE = 0.01f; |
| |
| private final String mCompatChangeName; |
| private final float mCompatScale; |
| private final float mInvCompatScale; |
| private CommandSession.SizeInfo mAppSizesNormal; |
| private CommandSession.SizeInfo mAppSizesDownscaled; |
| private WindowManagerState.WindowState mWindowStateNormal; |
| private WindowManagerState.WindowState mWindowStateDownscaled; |
| |
| public CompatScaleTests(String compatChangeName, float compatScale) { |
| mCompatChangeName = compatChangeName; |
| mCompatScale = compatScale; |
| mInvCompatScale = 1 / mCompatScale; |
| } |
| |
| // TODO(b/180343437): replace @Before with @BeforeParam |
| @Before |
| public void launchInNormalAndDownscaleMode_collectSizesAndWindowState() { |
| // Launch activity with downscaling *disabled* and get the sizes it reports and its Window |
| // state. |
| launchActivity(); |
| mAppSizesNormal = getActivityReportedSizes(); |
| mWindowStateNormal = getPackageWindowState(); |
| |
| // Now launch the same activity with downscaling *enabled* and get the sizes it reports and |
| // its Window state. |
| enableDownscaling(mCompatChangeName); |
| launchActivity(); |
| mAppSizesDownscaled = getActivityReportedSizes(); |
| mWindowStateDownscaled = getPackageWindowState(); |
| } |
| |
| /** |
| * Tests that the Density DPI that the application receives from the |
| * {@link android.content.res.Configuration} is correctly scaled in the downscaled mode. |
| * @see android.content.res.Configuration#densityDpi |
| */ |
| @Test |
| public void test_config_densityDpi_scalesCorrectly_inCompatDownscalingMode() { |
| assertScaled("Density DPI should scale by " + mCompatScale, |
| mAppSizesNormal.densityDpi, mCompatScale, mAppSizesDownscaled.densityDpi); |
| } |
| |
| /** |
| * Tests that the screen sizes in DPs that the application receives from the |
| * {@link android.content.res.Configuration} are NOT scaled in the downscaled mode. |
| * @see android.content.res.Configuration#screenWidthDp |
| * @see android.content.res.Configuration#screenHeightDp |
| * @see android.content.res.Configuration#smallestScreenWidthDp |
| */ |
| @Test |
| public void test_config_screenSize_inDPs_doesNotChange_inCompatDownscalingMode() { |
| assertEquals("Width shouldn't change", |
| mAppSizesNormal.widthDp, mAppSizesDownscaled.widthDp); |
| assertEquals("Height shouldn't change", |
| mAppSizesNormal.heightDp, mAppSizesDownscaled.heightDp); |
| assertEquals("Smallest Width shouldn't change", |
| mAppSizesNormal.smallestWidthDp, mAppSizesDownscaled.smallestWidthDp); |
| } |
| |
| /** |
| * Tests that the Window sizes in PXs that the application receives from the |
| * {@link android.content.res.Configuration} are scaled correctly in the downscaled mode. |
| * @see android.content.res.Configuration#windowConfiguration |
| * @see android.app.WindowConfiguration#getBounds() |
| * @see android.app.WindowConfiguration#getAppBounds() |
| */ |
| @Test |
| public void test_config_windowSizes_inPXs_scaleCorrectly_inCompatDownscalingMode() { |
| assertScaled("Width should scale by " + mCompatScale, |
| mAppSizesNormal.windowWidth, mCompatScale, mAppSizesDownscaled.windowWidth); |
| assertScaled("Height should scale by " + mCompatScale, |
| mAppSizesNormal.windowHeight, mCompatScale, mAppSizesDownscaled.windowHeight); |
| assertScaled("App width should scale by " + mCompatScale, |
| mAppSizesNormal.windowAppWidth, mCompatScale, mAppSizesDownscaled.windowAppWidth); |
| assertScaled("App height should scale by " + mCompatScale, |
| mAppSizesNormal.windowAppHeight, mCompatScale, mAppSizesDownscaled.windowAppHeight); |
| } |
| |
| /** |
| * Tests that the {@link android.util.DisplayMetrics} in PXs that the application can obtain via |
| * {@link android.content.res.Resources#getDisplayMetrics()} are scaled correctly in the |
| * downscaled mode. |
| * @see android.util.DisplayMetrics#widthPixels |
| * @see android.util.DisplayMetrics#heightPixels |
| */ |
| @Test |
| public void test_displayMetrics_inPXs_scaleCorrectly_inCompatDownscalingMode() { |
| assertScaled("Width should scale by " + mCompatScale, |
| mAppSizesNormal.metricsWidth, mCompatScale, mAppSizesDownscaled.metricsWidth); |
| assertScaled("Height should scale by " + mCompatScale, |
| mAppSizesNormal.metricsHeight, mCompatScale, mAppSizesDownscaled.metricsHeight); |
| } |
| |
| /** |
| * Tests that the dimensions of a {@link android.view.Display} in PXs that the application can |
| * obtain via {@link android.view.View#getDisplay()} are scaled correctly in the downscaled |
| * mode. |
| * @see android.view.Display#getSize(android.graphics.Point) |
| */ |
| @Test |
| public void test_displaySize_inPXs_scaleCorrectly_inCompatDownscalingMode() { |
| assertScaled("Width should scale by " + mCompatScale, |
| mAppSizesNormal.displayWidth, mCompatScale, mAppSizesDownscaled.displayWidth); |
| assertScaled("Height should scale by " + mCompatScale, |
| mAppSizesNormal.displayHeight, mCompatScale, mAppSizesDownscaled.displayHeight); |
| } |
| |
| /** |
| * Test that compatibility downscaling is reflected correctly on the WM side. |
| * @see android.server.wm.WindowManagerState.WindowState |
| */ |
| @Test |
| public void test_windowState_inCompatDownscalingMode() { |
| // Check the "normal" window's state for disabled compat mode and appropriate global scale. |
| assertFalse("The Window should not be in the size compat mode", |
| mWindowStateNormal.hasCompatScale()); |
| assertEquals("The window should not be scaled", |
| 1f, mWindowStateNormal.getGlobalScale(), EPSILON_GLOBAL_SCALE); |
| |
| // Check the "downscaled" window's state for enabled compat mode and appropriate global |
| // scale. |
| assertTrue("The Window should be in the size compat mode", |
| mWindowStateDownscaled.hasCompatScale()); |
| assertEquals("The window should have global scale of " + mInvCompatScale, |
| mInvCompatScale, mWindowStateDownscaled.getGlobalScale(), EPSILON_GLOBAL_SCALE); |
| |
| // Make sure the frame sizes changed correctly. |
| assertEquals("Window frame on should not change", |
| mWindowStateNormal.getFrame(), mWindowStateDownscaled.getFrame()); |
| assertScaled("Requested width should scale by " + mCompatScale, |
| mWindowStateNormal.getRequestedWidth(), mCompatScale, |
| mWindowStateDownscaled.getRequestedWidth()); |
| assertScaled("Requested height should scale by " + mCompatScale, |
| mWindowStateNormal.getRequestedHeight(), mCompatScale, |
| mWindowStateDownscaled.getRequestedHeight()); |
| } |
| |
| @After |
| public void tearDown() { |
| disableDownscaling(mCompatChangeName); |
| } |
| |
| private void launchActivity() { |
| launchActivityInNewTask(ACTIVITY_UNDER_TEST); |
| mWmState.computeState(new WaitForValidActivityState(ACTIVITY_UNDER_TEST)); |
| } |
| |
| private CommandSession.SizeInfo getActivityReportedSizes() { |
| final CommandSession.SizeInfo details = |
| getLastReportedSizesForActivity(ACTIVITY_UNDER_TEST); |
| assertNotNull(details); |
| return details; |
| } |
| |
| private WindowManagerState.WindowState getPackageWindowState() { |
| return getPackageWindowState(PACKAGE_UNDER_TEST); |
| } |
| |
| private static void enableDownscaling(String compatChangeName) { |
| executeShellCommand("am compat enable " + compatChangeName + " " + PACKAGE_UNDER_TEST); |
| executeShellCommand("am compat enable DOWNSCALED " + PACKAGE_UNDER_TEST); |
| } |
| |
| private static void disableDownscaling(String compatChangeName) { |
| executeShellCommand("am compat disable DOWNSCALED " + PACKAGE_UNDER_TEST); |
| executeShellCommand("am compat disable " + compatChangeName + " " + PACKAGE_UNDER_TEST); |
| } |
| |
| private static void assertScaled(String message, int baseValue, float expectedScale, |
| int actualValue) { |
| // In order to account for possible rounding errors, let's calculate the actual scale and |
| // compare it's against the expected scale (allowing a small delta). |
| final float actualScale = ((float) actualValue) / baseValue; |
| assertEquals(message, expectedScale, actualScale, EPSILON_GLOBAL_SCALE); |
| } |
| } |