1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.server.wm.animations; 18 19 import static android.server.wm.ShellCommandHelper.executeShellCommand; 20 import static android.server.wm.ShellCommandHelper.executeShellCommandAndGetStdout; 21 import static android.server.wm.app.Components.TEST_ACTIVITY; 22 import static android.server.wm.displaysize.Components.SMALLEST_WIDTH_ACTIVITY; 23 24 import static org.junit.Assert.assertEquals; 25 import static org.junit.Assert.assertTrue; 26 27 import android.graphics.Point; 28 import android.hardware.display.DisplayManager; 29 import android.hardware.display.VirtualDisplay; 30 import android.os.Build; 31 import android.os.Handler; 32 import android.os.Looper; 33 import android.platform.test.annotations.Presubmit; 34 import android.server.wm.ActivityManagerTestBase; 35 import android.server.wm.CommandSession; 36 import android.view.Display; 37 38 import org.junit.After; 39 import org.junit.Test; 40 41 /** 42 * Ensure that compatibility dialog is shown when launching an application with 43 * an unsupported smallest width. 44 * 45 * <p>Build/Install/Run: 46 * atest CtsWindowManagerDeviceAnimations:DisplaySizeTest 47 */ 48 @Presubmit 49 @android.server.wm.annotation.Group3 50 public class DisplaySizeTest extends ActivityManagerTestBase { 51 52 /** @see com.android.server.wm.UnsupportedDisplaySizeDialog */ 53 private static final String UNSUPPORTED_DISPLAY_SIZE_DIALOG_NAME = 54 "UnsupportedDisplaySizeDialog"; 55 56 @After tearDown()57 public void tearDown() { 58 // Ensure app process is stopped. 59 stopTestPackage(SMALLEST_WIDTH_ACTIVITY.getPackageName()); 60 stopTestPackage(TEST_ACTIVITY.getPackageName()); 61 } 62 63 @Test testCompatibilityDialog()64 public void testCompatibilityDialog() { 65 // Launch some other app (not to perform density change on launcher). 66 launchActivity(TEST_ACTIVITY); 67 mWmState.assertActivityDisplayed(TEST_ACTIVITY); 68 69 createManagedScreenDensitySession().setUnsupportedDensity(); 70 71 // Launch target app. 72 launchActivity(SMALLEST_WIDTH_ACTIVITY); 73 mWmState.assertActivityDisplayed(SMALLEST_WIDTH_ACTIVITY); 74 mWmState.assertWindowDisplayed(UNSUPPORTED_DISPLAY_SIZE_DIALOG_NAME); 75 } 76 77 @Test testCompatibilityDialogWhenFocused()78 public void testCompatibilityDialogWhenFocused() { 79 launchActivity(SMALLEST_WIDTH_ACTIVITY); 80 mWmState.assertActivityDisplayed(SMALLEST_WIDTH_ACTIVITY); 81 82 createManagedScreenDensitySession().setUnsupportedDensity(); 83 84 mWmState.assertWindowDisplayed(UNSUPPORTED_DISPLAY_SIZE_DIALOG_NAME); 85 } 86 87 @Test testCompatibilityDialogAfterReturn()88 public void testCompatibilityDialogAfterReturn() { 89 // Launch target app. 90 launchActivity(SMALLEST_WIDTH_ACTIVITY); 91 mWmState.assertActivityDisplayed(SMALLEST_WIDTH_ACTIVITY); 92 // Launch another activity. 93 final CommandSession.ActivitySession activity = createManagedActivityClientSession() 94 .startActivity(getLaunchActivityBuilder().setUseInstrumentation() 95 .setDisplayId(getMainDisplayId()) 96 .setTargetActivity(TEST_ACTIVITY)); 97 mWmState.assertActivityDisplayed(TEST_ACTIVITY); 98 separateTestJournal(); 99 100 createManagedScreenDensitySession().setUnsupportedDensity(); 101 102 assertActivityLifecycle(TEST_ACTIVITY, true /* relaunched */); 103 activity.finish(); 104 105 mWmState.assertActivityDisplayed(SMALLEST_WIDTH_ACTIVITY); 106 mWmState.assertWindowDisplayed(UNSUPPORTED_DISPLAY_SIZE_DIALOG_NAME); 107 } 108 109 @Test testSizeRangesAfterSettingDisplaySize()110 public void testSizeRangesAfterSettingDisplaySize() throws InterruptedException { 111 VirtualDisplay virtualDisplay = null; 112 try { 113 final int initialLength = 500; 114 final int newLength = 1000; 115 final DisplayManager displayManager = mDm; 116 virtualDisplay = displayManager.createVirtualDisplay("CtsDisplay", initialLength, 117 initialLength, 160 /* densityDpi */, null /* surface */, 0 /* flags */); 118 final Display targetDisplay = virtualDisplay.getDisplay(); 119 final int targetDisplayId = targetDisplay.getDisplayId(); 120 121 mWmState.waitFor("Display " + targetDisplayId + " added", 122 wm -> wm.getDisplay(targetDisplayId) != null); 123 124 final boolean[] displayChanged = { false }; 125 displayManager.registerDisplayListener(new DisplayManager.DisplayListener() { 126 @Override 127 public void onDisplayAdded(int displayId) {} 128 129 @Override 130 public void onDisplayRemoved(int displayId) {} 131 132 @Override 133 public void onDisplayChanged(int displayId) { 134 if (displayId == targetDisplayId) { 135 synchronized (displayManager) { 136 displayChanged[0] = true; 137 displayManager.notify(); 138 } 139 displayManager.unregisterDisplayListener(this); 140 } 141 } 142 }, new Handler(Looper.getMainLooper())); 143 144 executeShellCommand(String.format("wm size %sx%s -d %s", 145 newLength, newLength, targetDisplayId)); 146 147 synchronized (displayManager) { 148 if (!displayChanged[0]) { 149 displayManager.wait(3000 /* milliseconds */); 150 } 151 assertTrue("DisplayManager must receive onDisplayChanged event", displayChanged[0]); 152 } 153 154 final Point expectedSize = new Point(newLength, newLength); 155 final Point smallestSize = new Point(); 156 final Point largestSize = new Point(); 157 targetDisplay.getCurrentSizeRange(smallestSize, largestSize); 158 assertEquals("Smallest size must be changed.", expectedSize, smallestSize); 159 assertEquals("Largest size must be changed.", expectedSize, largestSize); 160 } finally { 161 if (virtualDisplay != null) { 162 virtualDisplay.release(); 163 } 164 } 165 } 166 createManagedScreenDensitySession()167 protected ScreenDensitySession createManagedScreenDensitySession() { 168 return mObjectTracker.manage(new ScreenDensitySession(getMainDisplayId())); 169 } 170 171 private static class ScreenDensitySession implements AutoCloseable { 172 private static final String DENSITY_PROP_DEVICE = "ro.sf.lcd_density"; 173 private static final String DENSITY_PROP_EMULATOR = "qemu.sf.lcd_density"; 174 private final int mTargetDisplay; 175 ScreenDensitySession(int targetDisplay)176 public ScreenDensitySession(int targetDisplay) { 177 super(); 178 mTargetDisplay = targetDisplay; 179 } 180 setUnsupportedDensity()181 void setUnsupportedDensity() { 182 // Set device to 0.85 zoom. It doesn't matter that we're zooming out 183 // since the feature verifies that we're in a non-default density. 184 final int stableDensity = getStableDensity(); 185 final int targetDensity = (int) (stableDensity * 0.85); 186 setDensity(targetDensity); 187 } 188 189 @Override close()190 public void close() throws Exception { 191 resetDensity(); 192 } 193 getStableDensity()194 private int getStableDensity() { 195 final String densityProp; 196 if (Build.IS_EMULATOR) { 197 densityProp = DENSITY_PROP_EMULATOR; 198 } else { 199 densityProp = DENSITY_PROP_DEVICE; 200 } 201 202 return Integer.parseInt( 203 executeShellCommandAndGetStdout("getprop " + densityProp).trim()); 204 } 205 setDensity(int targetDensity)206 private void setDensity(int targetDensity) { 207 executeShellCommand("wm density " + targetDensity + " -d " + mTargetDisplay); 208 209 // Verify that the density is changed. 210 final String output 211 = executeShellCommandAndGetStdout("wm density -d " + mTargetDisplay); 212 final boolean success = output.contains("Override density: " + targetDensity); 213 214 assertTrue("Failed to set density to " + targetDensity, success); 215 } 216 resetDensity()217 private void resetDensity() { 218 executeShellCommand("wm density reset -d " + mTargetDisplay); 219 } 220 } 221 } 222