1 /* 2 * Copyright (C) 2020 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 com.android.cts.helpers.aosp; 18 19 import android.app.Instrumentation; 20 import android.app.UiAutomation; 21 import android.os.RemoteException; 22 23 import android.os.SystemClock; 24 import android.platform.helpers.exceptions.TestHelperException; 25 import android.support.test.uiautomator.By; 26 import android.support.test.uiautomator.UiDevice; 27 import android.support.test.uiautomator.UiObject; 28 import android.support.test.uiautomator.UiObject2; 29 import android.support.test.uiautomator.UiObjectNotFoundException; 30 import android.support.test.uiautomator.UiSelector; 31 import android.support.test.uiautomator.Until; 32 import android.util.Log; 33 34 import com.android.cts.helpers.ICtsPrintHelper; 35 36 import java.io.ByteArrayOutputStream; 37 import java.io.IOException; 38 39 public class DefaultCtsPrintHelper implements ICtsPrintHelper { 40 private static final String LOG_TAG = DefaultCtsPrintHelper.class.getSimpleName(); 41 42 protected static final long OPERATION_TIMEOUT_MILLIS = 60000; 43 private static final long GET_UIAUTOMATION_TIMEOUT_MS = 60000; 44 45 protected Instrumentation mInstrumentation; 46 protected UiDevice mDevice; 47 protected UiAutomation mAutomation; 48 DefaultCtsPrintHelper(Instrumentation instrumentation)49 public DefaultCtsPrintHelper(Instrumentation instrumentation) { 50 mInstrumentation = instrumentation; 51 mDevice = UiDevice.getInstance(mInstrumentation); 52 53 long start = SystemClock.uptimeMillis(); 54 while (SystemClock.uptimeMillis() - start < GET_UIAUTOMATION_TIMEOUT_MS) { 55 UiAutomation ui = mInstrumentation.getUiAutomation(); 56 if (ui != null) { 57 mAutomation = ui; 58 break; 59 } 60 } 61 if (mAutomation == null) { 62 throw new AssertionError("Failed to get UiAutomation"); 63 } 64 } 65 dumpWindowHierarchy()66 protected void dumpWindowHierarchy() throws TestHelperException { 67 try { 68 ByteArrayOutputStream os = new ByteArrayOutputStream(); 69 mDevice.dumpWindowHierarchy(os); 70 71 Log.w(LOG_TAG, "Window hierarchy:"); 72 for (String line : os.toString("UTF-8").split("\n")) { 73 Log.w(LOG_TAG, line); 74 } 75 } catch (IOException e) { 76 throw new TestHelperException(e); 77 } 78 } 79 80 @Override setUp()81 public void setUp() throws TestHelperException { 82 try { 83 // Prevent rotation 84 mDevice.freezeRotation(); 85 while (!mDevice.isNaturalOrientation()) { 86 mDevice.setOrientationNatural(); 87 mDevice.waitForIdle(); 88 } 89 } catch (RemoteException e) { 90 throw new TestHelperException("Failed to freeze device rotation", e); 91 } 92 } 93 94 @Override tearDown()95 public void tearDown() throws TestHelperException { 96 try { 97 // Allow rotation 98 mDevice.unfreezeRotation(); 99 } catch (RemoteException e) { 100 throw new TestHelperException("Failed to unfreeze device rotation", e); 101 } 102 } 103 104 @Override submitPrintJob()105 public void submitPrintJob() throws TestHelperException { 106 Log.d(LOG_TAG, "Clicking print button"); 107 108 mDevice.waitForIdle(); 109 110 UiObject2 printButton = 111 mDevice.wait( 112 Until.findObject(By.res("com.android.printspooler:id/print_button")), 113 OPERATION_TIMEOUT_MILLIS); 114 if (printButton == null) { 115 dumpWindowHierarchy(); 116 throw new TestHelperException("print button not found"); 117 } 118 119 printButton.click(); 120 } 121 122 @Override retryPrintJob()123 public void retryPrintJob() throws TestHelperException { 124 try { 125 UiObject retryButton = mDevice.findObject(new UiSelector().resourceId( 126 "com.android.printspooler:id/action_button")); 127 retryButton.click(); 128 } catch (UiObjectNotFoundException e) { 129 dumpWindowHierarchy(); 130 throw new TestHelperException("Retry button not found", e); 131 } 132 } 133 134 @Override canSubmitJob()135 public boolean canSubmitJob() { 136 return mDevice.hasObject(By.res("com.android.printspooler:id/print_button")); 137 } 138 139 @Override answerPrintServicesWarning(boolean confirm)140 public void answerPrintServicesWarning(boolean confirm) throws TestHelperException { 141 try { 142 mDevice.waitForIdle(); 143 UiObject button; 144 if (confirm) { 145 button = mDevice.findObject(new UiSelector().resourceId("android:id/button1")); 146 } else { 147 button = mDevice.findObject(new UiSelector().resourceId("android:id/button2")); 148 } 149 button.click(); 150 } catch (UiObjectNotFoundException e) { 151 dumpWindowHierarchy(); 152 throw new TestHelperException("Unable to find print service dialog button", e); 153 } 154 } 155 156 @Override selectPrinter(String printerName, long timeout)157 public void selectPrinter(String printerName, long timeout) throws TestHelperException { 158 Log.d(LOG_TAG, "Selecting printer " + printerName); 159 try { 160 UiObject2 destinationSpinner = 161 mDevice.wait( 162 Until.findObject( 163 By.res("com.android.printspooler:id/destination_spinner")), 164 timeout); 165 166 if (destinationSpinner != null) { 167 destinationSpinner.click(); 168 mDevice.waitForIdle(); 169 } 170 171 UiObject2 printerOption = mDevice.wait(Until.findObject(By.text(printerName)), timeout); 172 if (printerOption == null) { 173 throw new UiObjectNotFoundException(printerName + " not found"); 174 } 175 176 printerOption.click(); 177 mDevice.waitForIdle(); 178 } catch (Exception e) { 179 dumpWindowHierarchy(); 180 throw new TestHelperException("Failed to select printer", e); 181 } 182 } 183 184 @Override selectPrinterWhenAvailable(String printerName)185 public void selectPrinterWhenAvailable(String printerName) throws TestHelperException { 186 try { 187 while (true) { 188 UiObject printerItem = mDevice.findObject( 189 new UiSelector().text(printerName)); 190 191 if (printerItem.isEnabled()) { 192 printerItem.click(); 193 break; 194 } else { 195 Thread.sleep(100); 196 } 197 } 198 } catch (UiObjectNotFoundException e) { 199 throw new TestHelperException("Failed to find printer label", e); 200 } catch (InterruptedException e) { 201 throw new TestHelperException("Interruped while waiting for printer", e); 202 } 203 } 204 205 @Override setPageOrientation(String orientation)206 public void setPageOrientation(String orientation) throws TestHelperException { 207 try { 208 UiObject orientationSpinner = mDevice.findObject(new UiSelector().resourceId( 209 "com.android.printspooler:id/orientation_spinner")); 210 orientationSpinner.click(); 211 UiObject orientationOption = mDevice.findObject(new UiSelector().text(orientation)); 212 orientationOption.click(); 213 } catch (UiObjectNotFoundException e) { 214 dumpWindowHierarchy(); 215 throw new TestHelperException("Failed to set page orientation to " + orientation, e); 216 } 217 } 218 219 @Override getPageOrientation()220 public String getPageOrientation() throws TestHelperException { 221 try { 222 UiObject orientationSpinner = mDevice.findObject(new UiSelector().resourceId( 223 "com.android.printspooler:id/orientation_spinner")); 224 return orientationSpinner.getText(); 225 } catch (UiObjectNotFoundException e) { 226 dumpWindowHierarchy(); 227 throw new TestHelperException("Failed to get page orientation", e); 228 } 229 } 230 231 @Override setMediaSize(String mediaSize)232 public void setMediaSize(String mediaSize) throws TestHelperException { 233 try { 234 UiObject mediaSizeSpinner = mDevice.findObject(new UiSelector().resourceId( 235 "com.android.printspooler:id/paper_size_spinner")); 236 mediaSizeSpinner.click(); 237 UiObject mediaSizeOption = mDevice.findObject(new UiSelector().text(mediaSize)); 238 mediaSizeOption.click(); 239 } catch (UiObjectNotFoundException e) { 240 dumpWindowHierarchy(); 241 throw new TestHelperException("Unable to set media size to " + mediaSize, e); 242 } 243 } 244 245 @Override setColorMode(String color)246 public void setColorMode(String color) throws TestHelperException { 247 try { 248 UiObject colorSpinner = mDevice.findObject(new UiSelector().resourceId( 249 "com.android.printspooler:id/color_spinner")); 250 colorSpinner.click(); 251 UiObject colorOption = mDevice.findObject(new UiSelector().text(color)); 252 colorOption.click(); 253 } catch (UiObjectNotFoundException e) { 254 dumpWindowHierarchy(); 255 throw new TestHelperException("Unable to set color mode to " + color, e); 256 } 257 } 258 259 @Override getColorMode()260 public String getColorMode() throws TestHelperException { 261 try { 262 UiObject colorSpinner = mDevice.findObject(new UiSelector().resourceId( 263 "com.android.printspooler:id/color_spinner")); 264 return colorSpinner.getText(); 265 } catch (UiObjectNotFoundException e) { 266 dumpWindowHierarchy(); 267 throw new TestHelperException("Unable to get color mode", e); 268 } 269 } 270 271 @Override setDuplexMode(String duplex)272 public void setDuplexMode(String duplex) throws TestHelperException { 273 try { 274 UiObject duplexSpinner = mDevice.findObject(new UiSelector().resourceId( 275 "com.android.printspooler:id/duplex_spinner")); 276 duplexSpinner.click(); 277 UiObject duplexOption = mDevice.findObject(new UiSelector().text(duplex)); 278 duplexOption.click(); 279 } catch (UiObjectNotFoundException e) { 280 dumpWindowHierarchy(); 281 throw new TestHelperException("Unable to set duplex mode to " + duplex, e); 282 } 283 } 284 285 @Override setCopies(int newCopies)286 public void setCopies(int newCopies) throws TestHelperException { 287 try { 288 UiObject copies = mDevice.findObject(new UiSelector().resourceId( 289 "com.android.printspooler:id/copies_edittext")); 290 copies.setText(Integer.valueOf(newCopies).toString()); 291 } catch (UiObjectNotFoundException e) { 292 dumpWindowHierarchy(); 293 throw new TestHelperException("Unable to set copies to " + newCopies, e); 294 } 295 } 296 297 @Override getCopies()298 public int getCopies() throws TestHelperException { 299 try { 300 UiObject copies = mDevice.findObject(new UiSelector().resourceId( 301 "com.android.printspooler:id/copies_edittext")); 302 return Integer.parseInt(copies.getText()); 303 } catch (UiObjectNotFoundException e) { 304 dumpWindowHierarchy(); 305 throw new TestHelperException("Unable to get number of copies", e); 306 } 307 } 308 309 @Override setPageRange(String pages, int expectedPages)310 public void setPageRange(String pages, int expectedPages) throws TestHelperException { 311 try { 312 mDevice.waitForIdle(); 313 UiObject pagesSpinner = mDevice.findObject(new UiSelector().resourceId( 314 "com.android.printspooler:id/range_options_spinner")); 315 pagesSpinner.click(); 316 317 mDevice.waitForIdle(); 318 UiObject rangeOption = mDevice.findObject(new UiSelector().textContains("Range of " 319 + expectedPages)); 320 rangeOption.click(); 321 322 mDevice.waitForIdle(); 323 UiObject pagesEditText = mDevice.findObject(new UiSelector().resourceId( 324 "com.android.printspooler:id/page_range_edittext")); 325 pagesEditText.setText(pages); 326 327 mDevice.waitForIdle(); 328 // Hide the keyboard. 329 mDevice.pressBack(); 330 } catch (UiObjectNotFoundException e) { 331 dumpWindowHierarchy(); 332 throw new TestHelperException("Unable to set page range", e); 333 } 334 } 335 336 @Override getPageRange(int docPages)337 public String getPageRange(int docPages) throws TestHelperException { 338 final String fullRange = "All " + docPages; 339 340 try { 341 if (mDevice.hasObject(By.text(fullRange))) { 342 return fullRange; 343 } 344 345 UiObject pagesEditText = mDevice.findObject(new UiSelector().resourceId( 346 "com.android.printspooler:id/page_range_edittext")); 347 348 return pagesEditText.getText(); 349 } catch (UiObjectNotFoundException e) { 350 dumpWindowHierarchy(); 351 throw new TestHelperException("Unable to get page range", e); 352 } 353 } 354 355 @Override getStatusMessage()356 public String getStatusMessage() throws TestHelperException { 357 UiObject2 message = mDevice.wait(Until.findObject( 358 By.res("com.android.printspooler:id/message")), OPERATION_TIMEOUT_MILLIS); 359 360 if (message == null) { 361 dumpWindowHierarchy(); 362 throw new TestHelperException("Cannot find status message"); 363 } 364 365 return message.getText(); 366 } 367 368 @Override openPrintOptions()369 public void openPrintOptions() throws TestHelperException { 370 try { 371 UiObject expandHandle = mDevice.findObject(new UiSelector().resourceId( 372 "com.android.printspooler:id/expand_collapse_handle")); 373 expandHandle.click(); 374 } catch (UiObjectNotFoundException e) { 375 dumpWindowHierarchy(); 376 throw new TestHelperException("Unable to find print options handle", e); 377 } 378 } 379 380 @Override openCustomPrintOptions()381 public void openCustomPrintOptions() throws TestHelperException { 382 try { 383 UiObject expandHandle = mDevice.findObject(new UiSelector().resourceId( 384 "com.android.printspooler:id/more_options_button")); 385 expandHandle.click(); 386 } catch (UiObjectNotFoundException e) { 387 dumpWindowHierarchy(); 388 throw new TestHelperException("Unable to find print options handle", e); 389 } 390 } 391 392 @Override displayPrinterList()393 public void displayPrinterList() throws TestHelperException { 394 try { 395 // Open destination spinner 396 UiObject destinationSpinner = mDevice.findObject(new UiSelector().resourceId( 397 "com.android.printspooler:id/destination_spinner")); 398 destinationSpinner.click(); 399 400 // Wait until spinner is opened 401 mDevice.waitForIdle(); 402 } catch (UiObjectNotFoundException e) { 403 throw new TestHelperException("Unable to find destination spinner", e); 404 } 405 } 406 407 @Override displayMoreInfo()408 public void displayMoreInfo() throws TestHelperException { 409 mDevice.waitForIdle(); 410 mDevice.wait( 411 Until.findObject(By.res("com.android.printspooler:id/more_info")), 412 OPERATION_TIMEOUT_MILLIS).click(); 413 } 414 415 @Override closePrinterList()416 public void closePrinterList() { 417 mDevice.pressBack(); 418 } 419 420 @Override closeCustomPrintOptions()421 public void closeCustomPrintOptions() { 422 mDevice.pressBack(); 423 } 424 425 @Override closePrintOptions()426 public void closePrintOptions() { 427 mDevice.pressBack(); 428 } 429 430 @Override cancelPrinting()431 public void cancelPrinting() throws TestHelperException { 432 try { 433 mDevice.wakeUp(); 434 mDevice.pressBack(); 435 mDevice.waitForIdle(); 436 } catch (RemoteException e) { 437 throw new TestHelperException("Failed to cancel printing", e); 438 } 439 } 440 } 441