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 androidx.test.uiautomator; 18 19 import static org.junit.Assert.assertEquals; 20 import static org.junit.Assert.assertFalse; 21 import static org.junit.Assert.assertNotNull; 22 import static org.junit.Assert.assertThrows; 23 import static org.junit.Assert.assertTrue; 24 import static org.mockito.ArgumentMatchers.anyInt; 25 import static org.mockito.ArgumentMatchers.anyLong; 26 import static org.mockito.ArgumentMatchers.eq; 27 import static org.mockito.Mockito.atLeastOnce; 28 import static org.mockito.Mockito.doReturn; 29 import static org.mockito.Mockito.never; 30 import static org.mockito.Mockito.spy; 31 import static org.mockito.Mockito.times; 32 import static org.mockito.Mockito.verify; 33 34 import android.app.Instrumentation; 35 import android.app.UiAutomation; 36 import android.content.ContentResolver; 37 import android.graphics.Bitmap; 38 import android.graphics.BitmapFactory; 39 import android.graphics.Point; 40 import android.os.Build; 41 import android.provider.Settings; 42 import android.util.DisplayMetrics; 43 44 import androidx.test.core.app.ApplicationProvider; 45 import androidx.test.filters.SdkSuppress; 46 import androidx.test.platform.app.InstrumentationRegistry; 47 48 import org.junit.After; 49 import org.junit.Before; 50 import org.junit.Rule; 51 import org.junit.Test; 52 import org.junit.rules.TemporaryFolder; 53 54 import java.io.File; 55 import java.io.IOException; 56 import java.util.regex.Matcher; 57 import java.util.regex.Pattern; 58 59 public class UiDeviceTest { 60 61 private static final String WATCHER_NAME = "test_watcher"; 62 63 @Rule 64 public TemporaryFolder mTmpDir = new TemporaryFolder(); 65 66 private Instrumentation mInstrumentation; 67 private UiAutomation mUiAutomation; 68 private UiDevice mDevice; 69 private int mDefaultFlags; 70 71 @Before setUp()72 public void setUp() { 73 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { 74 // Configure spies on API 28+ (min version supported by dexmaker-mockito-inline). 75 mInstrumentation = spy(InstrumentationRegistry.getInstrumentation()); 76 mUiAutomation = spy(InstrumentationRegistry.getInstrumentation().getUiAutomation()); 77 doReturn(mUiAutomation).when(mInstrumentation).getUiAutomation(anyInt()); 78 mDevice = new UiDevice(mInstrumentation); 79 } else { 80 mDevice = new UiDevice(InstrumentationRegistry.getInstrumentation()); 81 } 82 mDefaultFlags = Configurator.getInstance().getUiAutomationFlags(); 83 } 84 85 @After tearDown()86 public void tearDown() { 87 Configurator.getInstance().setUiAutomationFlags(mDefaultFlags); 88 } 89 90 @Test testGetDisplayMetrics()91 public void testGetDisplayMetrics() throws IOException { 92 String densityCmdOutput = mDevice.executeShellCommand("wm density"); 93 Pattern densityPattern = Pattern.compile("^Physical\\sdensity:\\s(\\d+)\\D+.*"); 94 Matcher densityMatcher = densityPattern.matcher(densityCmdOutput); 95 assertTrue(densityMatcher.find()); 96 String densityDpi = densityMatcher.group(1); 97 assertNotNull(densityDpi); 98 float density = Float.parseFloat(densityDpi) / DisplayMetrics.DENSITY_DEFAULT; 99 100 try { 101 int width = 800; 102 int height = 400; 103 mDevice.executeShellCommand(String.format("wm size %dx%d", width, height)); 104 105 Point expectedSizeDp = new Point(Math.round(width / density), 106 Math.round(height / density)); 107 108 assertEquals(width, mDevice.getDisplayWidth()); 109 assertEquals(height, mDevice.getDisplayHeight()); 110 assertEquals(expectedSizeDp, mDevice.getDisplaySizeDp()); 111 } finally { 112 mDevice.executeShellCommand("wm size reset"); 113 } 114 } 115 116 @Test testGetProductName()117 public void testGetProductName() { 118 assertEquals(Build.PRODUCT, mDevice.getProductName()); 119 } 120 121 @Test testRegisterAndRunUiWatcher_conditionMet()122 public void testRegisterAndRunUiWatcher_conditionMet() { 123 // The watcher will return true when its watching condition is met. 124 UiWatcher watcher = () -> true; 125 mDevice.registerWatcher(WATCHER_NAME, watcher); 126 127 assertFalse(mDevice.hasWatcherTriggered(WATCHER_NAME)); 128 assertFalse(mDevice.hasAnyWatcherTriggered()); 129 mDevice.runWatchers(); 130 assertTrue(mDevice.hasWatcherTriggered(WATCHER_NAME)); 131 assertTrue(mDevice.hasAnyWatcherTriggered()); 132 } 133 134 @Test testRegisterAndRunUiWatcher_conditionNotMet()135 public void testRegisterAndRunUiWatcher_conditionNotMet() { 136 UiWatcher watcher = () -> false; 137 mDevice.registerWatcher(WATCHER_NAME, watcher); 138 139 assertFalse(mDevice.hasWatcherTriggered(WATCHER_NAME)); 140 assertFalse(mDevice.hasAnyWatcherTriggered()); 141 mDevice.runWatchers(); 142 assertFalse(mDevice.hasWatcherTriggered(WATCHER_NAME)); 143 assertFalse(mDevice.hasAnyWatcherTriggered()); 144 } 145 146 @Test testResetUiWatcher()147 public void testResetUiWatcher() { 148 UiWatcher watcher = () -> true; 149 mDevice.registerWatcher(WATCHER_NAME, watcher); 150 mDevice.runWatchers(); 151 152 assertTrue(mDevice.hasWatcherTriggered(WATCHER_NAME)); 153 assertTrue(mDevice.hasAnyWatcherTriggered()); 154 mDevice.resetWatcherTriggers(); 155 assertFalse(mDevice.hasWatcherTriggered(WATCHER_NAME)); 156 assertFalse(mDevice.hasAnyWatcherTriggered()); 157 } 158 159 @Test testRemoveUiWatcher()160 public void testRemoveUiWatcher() { 161 UiWatcher watcher = () -> true; 162 mDevice.registerWatcher(WATCHER_NAME, watcher); 163 mDevice.removeWatcher(WATCHER_NAME); 164 mDevice.runWatchers(); 165 166 assertFalse(mDevice.hasWatcherTriggered(WATCHER_NAME)); 167 assertFalse(mDevice.hasAnyWatcherTriggered()); 168 } 169 170 @Test testFreezeAndUnfreezeRotation()171 public void testFreezeAndUnfreezeRotation() throws Exception { 172 ContentResolver resolver = ApplicationProvider.getApplicationContext().getContentResolver(); 173 174 mDevice.freezeRotation(); 175 // The value of `ACCELEROMETER_ROTATION` will be 0 if the accelerometer is NOT used for 176 // detecting rotation, and 1 otherwise. 177 assertEquals(0, 178 Settings.System.getInt(resolver, Settings.System.ACCELEROMETER_ROTATION, 0)); 179 180 mDevice.unfreezeRotation(); 181 assertEquals(1, 182 Settings.System.getInt(resolver, Settings.System.ACCELEROMETER_ROTATION, 0)); 183 } 184 185 @Test 186 @SdkSuppress(minSdkVersion = Build.VERSION_CODES.P) testGetUiAutomation_withDefaultFlags()187 public void testGetUiAutomation_withDefaultFlags() { 188 mDevice.getUiAutomation(); 189 // Verify that the UiAutomation instance was obtained with default flags (N+). 190 verify(mInstrumentation, atLeastOnce()).getUiAutomation(eq(mDefaultFlags)); 191 } 192 193 @Test 194 @SdkSuppress(minSdkVersion = Build.VERSION_CODES.P) testGetUiAutomation_withCustomFlags()195 public void testGetUiAutomation_withCustomFlags() { 196 int customFlags = 5; 197 Configurator.getInstance().setUiAutomationFlags(customFlags); 198 mDevice.getUiAutomation(); 199 // Verify that the UiAutomation instance was obtained with custom flags (N+). 200 verify(mInstrumentation, atLeastOnce()).getUiAutomation(eq(customFlags)); 201 } 202 203 @Test testExecuteShellCommand()204 public void testExecuteShellCommand() throws IOException { 205 String output = mDevice.executeShellCommand("pm list packages"); 206 assertTrue(output.contains("package:androidx.test.uiautomator.test")); 207 } 208 209 @Test testTakeScreenshot()210 public void testTakeScreenshot() throws Exception { 211 File outFile = mTmpDir.newFile(); 212 assertTrue(mDevice.takeScreenshot(outFile)); 213 // Verify that a valid screenshot was generated with default scale. 214 Bitmap screenshot = BitmapFactory.decodeFile(outFile.getPath()); 215 assertNotNull(screenshot); 216 assertEquals(mDevice.getDisplayWidth(), screenshot.getWidth()); 217 assertEquals(mDevice.getDisplayHeight(), screenshot.getHeight()); 218 } 219 220 @Test testTakeScreenshot_scaled()221 public void testTakeScreenshot_scaled() throws Exception { 222 File outFile = mTmpDir.newFile(); 223 assertTrue(mDevice.takeScreenshot(outFile, 0.5f, 100)); 224 // Verify that a valid screenshot was generated with 1/2 scale. 225 Bitmap screenshot = BitmapFactory.decodeFile(outFile.getPath()); 226 assertNotNull(screenshot); 227 assertEquals(mDevice.getDisplayWidth() / 2, screenshot.getWidth()); 228 assertEquals(mDevice.getDisplayHeight() / 2, screenshot.getHeight()); 229 } 230 231 @Test testInaccessibleDisplay()232 public void testInaccessibleDisplay() { 233 assertThrows(IllegalArgumentException.class, () -> mDevice.getDisplayRotation(1000)); 234 assertThrows(IllegalArgumentException.class, () -> mDevice.getDisplaySize(1000)); 235 } 236 237 @Test 238 @SdkSuppress(minSdkVersion = Build.VERSION_CODES.P) testWaitForIdle()239 public void testWaitForIdle() throws Exception { 240 mDevice.waitForIdle(); 241 long defaultTimeout = Configurator.getInstance().getWaitForIdleTimeout(); 242 verify(mUiAutomation, times(1)).waitForIdle(anyLong(), eq(defaultTimeout)); 243 244 mDevice.waitForIdle(123L); 245 verify(mUiAutomation, times(1)).waitForIdle(anyLong(), eq(123L)); 246 } 247 248 @Test 249 @SdkSuppress(minSdkVersion = Build.VERSION_CODES.P) testWaitForIdle_watcher()250 public void testWaitForIdle_watcher() throws Exception { 251 UiWatcher watcher = () -> { 252 mDevice.waitForIdle(); 253 return true; 254 }; 255 mDevice.registerWatcher(WATCHER_NAME, watcher); 256 mDevice.runWatchers(); 257 258 // Wait for idle skipped during watcher execution. 259 verify(mUiAutomation, never()).waitForIdle(anyLong(), anyLong()); 260 } 261 } 262