1 /* 2 * Copyright (C) 2014 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.print.cts; 18 19 import static android.print.test.Utils.eventually; 20 import static android.print.test.Utils.runOnMainThread; 21 22 import static org.junit.Assert.assertEquals; 23 import static org.junit.Assert.assertFalse; 24 import static org.junit.Assert.assertNotNull; 25 import static org.junit.Assert.assertTrue; 26 import static org.mockito.Mockito.inOrder; 27 28 import android.print.PrintAttributes; 29 import android.print.PrintAttributes.Margins; 30 import android.print.PrintAttributes.MediaSize; 31 import android.print.PrintAttributes.Resolution; 32 import android.print.PrintDocumentAdapter; 33 import android.print.PrinterCapabilitiesInfo; 34 import android.print.PrinterId; 35 import android.print.PrinterInfo; 36 import android.print.test.BasePrintTest; 37 import android.print.test.services.FirstPrintService; 38 import android.print.test.services.PrintServiceCallbacks; 39 import android.print.test.services.PrinterDiscoverySessionCallbacks; 40 import android.print.test.services.SecondPrintService; 41 import android.print.test.services.StubbablePrinterDiscoverySession; 42 import android.printservice.PrintJob; 43 import android.printservice.PrinterDiscoverySession; 44 import androidx.annotation.NonNull; 45 import android.support.test.runner.AndroidJUnit4; 46 import android.support.test.uiautomator.UiObject; 47 import android.support.test.uiautomator.UiSelector; 48 49 import org.junit.Before; 50 import org.junit.Test; 51 import org.junit.runner.RunWith; 52 import org.mockito.InOrder; 53 import org.mockito.exceptions.verification.VerificationInOrderFailure; 54 55 import java.util.ArrayList; 56 import java.util.Collections; 57 import java.util.List; 58 59 /** 60 * This test verifies that the system respects the {@link PrinterDiscoverySession} 61 * contract is respected. 62 */ 63 @RunWith(AndroidJUnit4.class) 64 public class PrinterDiscoverySessionLifecycleTest extends BasePrintTest { 65 private static final String FIRST_PRINTER_LOCAL_ID = "first_printer"; 66 private static final String SECOND_PRINTER_LOCAL_ID = "second_printer"; 67 68 private static StubbablePrinterDiscoverySession sSession; 69 70 @Before clearPrintSpoolerState()71 public void clearPrintSpoolerState() throws Exception { 72 clearPrintSpoolerData(); 73 } 74 75 /** 76 * Add a printer to {@#sSession}. 77 * 78 * @param localId The id of the printer to add 79 * @param hasCapabilities If the printer has capabilities 80 */ addPrinter(@onNull String localId, boolean hasCapabilities)81 private void addPrinter(@NonNull String localId, boolean hasCapabilities) { 82 // Add the first printer. 83 PrinterId firstPrinterId = sSession.getService().generatePrinterId( 84 localId); 85 86 PrinterInfo.Builder printer = new PrinterInfo.Builder(firstPrinterId, 87 localId, PrinterInfo.STATUS_IDLE); 88 89 if (hasCapabilities) { 90 printer.setCapabilities(new PrinterCapabilitiesInfo.Builder(firstPrinterId) 91 .setMinMargins(new Margins(200, 200, 200, 200)) 92 .addMediaSize(MediaSize.ISO_A0, true) 93 .addResolution(new Resolution("300x300", "300x300", 300, 300), true) 94 .setColorModes(PrintAttributes.COLOR_MODE_COLOR, 95 PrintAttributes.COLOR_MODE_COLOR) 96 .build()); 97 } 98 99 sSession.addPrinters(Collections.singletonList(printer.build())); 100 } 101 102 /** 103 * Make {@code localPrinterId} the default printer. This requires a full print workflow. 104 * 105 * As a side-effect also approved the print service. 106 * 107 * @param localPrinterId The printer to make default 108 */ makeDefaultPrinter(String localPrinterId)109 private void makeDefaultPrinter(String localPrinterId) throws Throwable { 110 PrintDocumentAdapter adapter = createDefaultPrintDocumentAdapter(1); 111 112 print(adapter); 113 waitForWriteAdapterCallback(1); 114 115 runOnMainThread(() -> addPrinter(localPrinterId, true)); 116 selectPrinter(localPrinterId); 117 waitForWriteAdapterCallback(2); 118 119 clickPrintButton(); 120 answerPrintServicesWarning(true); 121 122 waitForPrinterDiscoverySessionDestroyCallbackCalled(1); 123 resetCounters(); 124 } 125 126 /** 127 * Select a printer in the all printers activity 128 * 129 * @param printerName The name of the printer to select 130 */ selectInAllPrintersActivity(@onNull String printerName)131 private void selectInAllPrintersActivity(@NonNull String printerName) throws Exception { 132 while (true) { 133 UiObject printerItem = getUiDevice().findObject( 134 new UiSelector().text(printerName)); 135 136 if (printerItem.isEnabled()) { 137 printerItem.click(); 138 break; 139 } else { 140 Thread.sleep(100); 141 } 142 } 143 } 144 145 @Test defaultPrinterBecomesAvailableWhileInBackground()146 public void defaultPrinterBecomesAvailableWhileInBackground() throws Throwable { 147 // Create the session callbacks that we will be checking. 148 final PrinterDiscoverySessionCallbacks firstSessionCallbacks = 149 createMockPrinterDiscoverySessionCallbacks(invocation -> { 150 sSession = 151 ((PrinterDiscoverySessionCallbacks) invocation.getMock()).getSession(); 152 153 onPrinterDiscoverySessionCreateCalled(); 154 return null; 155 }, null, null, null, null, null, invocation -> { 156 onPrinterDiscoverySessionDestroyCalled(); 157 return null; 158 }); 159 160 // Create the service callbacks for the first print service. 161 PrintServiceCallbacks firstServiceCallbacks = createMockPrintServiceCallbacks( 162 invocation -> firstSessionCallbacks, null, null); 163 164 // Configure the print services. 165 FirstPrintService.setCallbacks(firstServiceCallbacks); 166 SecondPrintService.setCallbacks(createSecondMockPrintServiceCallbacks()); 167 168 makeDefaultPrinter(FIRST_PRINTER_LOCAL_ID); 169 170 PrintDocumentAdapter adapter = createDefaultPrintDocumentAdapter(1); 171 print(adapter); 172 waitForPrinterDiscoverySessionCreateCallbackCalled(); 173 174 waitForPrinterUnavailable(); 175 176 selectPrinter("All printers…"); 177 // Let all printers activity start 178 Thread.sleep(500); 179 180 // Add printer 181 runOnMainThread(() -> addPrinter(FIRST_PRINTER_LOCAL_ID, true)); 182 183 // Select printer once available (this returns to main print activity) 184 selectInAllPrintersActivity(FIRST_PRINTER_LOCAL_ID); 185 186 // Wait for preview to load and finish print 187 waitForWriteAdapterCallback(1); 188 clickPrintButton(); 189 waitForPrinterDiscoverySessionDestroyCallbackCalled(1); 190 } 191 192 @Test defaultPrinterBecomesUsableWhileInBackground()193 public void defaultPrinterBecomesUsableWhileInBackground() throws Throwable { 194 // Create the session callbacks that we will be checking. 195 final PrinterDiscoverySessionCallbacks firstSessionCallbacks = 196 createMockPrinterDiscoverySessionCallbacks(invocation -> { 197 sSession = 198 ((PrinterDiscoverySessionCallbacks) invocation.getMock()).getSession(); 199 200 onPrinterDiscoverySessionCreateCalled(); 201 return null; 202 }, null, null, null, null, null, invocation -> { 203 onPrinterDiscoverySessionDestroyCalled(); 204 return null; 205 }); 206 207 // Create the service callbacks for the first print service. 208 PrintServiceCallbacks firstServiceCallbacks = createMockPrintServiceCallbacks( 209 invocation -> firstSessionCallbacks, null, null); 210 211 // Configure the print services. 212 FirstPrintService.setCallbacks(firstServiceCallbacks); 213 SecondPrintService.setCallbacks(createSecondMockPrintServiceCallbacks()); 214 215 makeDefaultPrinter(FIRST_PRINTER_LOCAL_ID); 216 217 PrintDocumentAdapter adapter = createDefaultPrintDocumentAdapter(1); 218 print(adapter); 219 waitForPrinterDiscoverySessionCreateCallbackCalled(); 220 221 // Add printer but do not enable it (capabilities == null) 222 runOnMainThread(() -> addPrinter(FIRST_PRINTER_LOCAL_ID, false)); 223 waitForPrinterUnavailable(); 224 225 selectPrinter("All printers…"); 226 // Let all printers activity start 227 Thread.sleep(500); 228 229 // Enable printer 230 runOnMainThread(() -> addPrinter(FIRST_PRINTER_LOCAL_ID, true)); 231 232 // Select printer once available (this returns to main print activity) 233 selectInAllPrintersActivity(FIRST_PRINTER_LOCAL_ID); 234 235 // Wait for preview to load and finish print 236 waitForWriteAdapterCallback(1); 237 clickPrintButton(); 238 waitForPrinterDiscoverySessionDestroyCallbackCalled(1); 239 } 240 241 @Test normalLifecycle()242 public void normalLifecycle() throws Throwable { 243 // Create the session callbacks that we will be checking. 244 final PrinterDiscoverySessionCallbacks firstSessionCallbacks = 245 createFirstMockPrinterDiscoverySessionCallbacks(); 246 247 // Create the service callbacks for the first print service. 248 PrintServiceCallbacks firstServiceCallbacks = createMockPrintServiceCallbacks( 249 invocation -> firstSessionCallbacks, 250 invocation -> { 251 PrintJob printJob = (PrintJob) invocation.getArguments()[0]; 252 // We pretend the job is handled immediately. 253 printJob.complete(); 254 return null; 255 }, null); 256 257 // Configure the print services. 258 FirstPrintService.setCallbacks(firstServiceCallbacks); 259 SecondPrintService.setCallbacks(createSecondMockPrintServiceCallbacks()); 260 261 // Create a print adapter that respects the print contract. 262 PrintDocumentAdapter adapter = createDefaultPrintDocumentAdapter(1); 263 264 // Start printing. 265 print(adapter); 266 267 // Wait for write of the first page. 268 waitForWriteAdapterCallback(1); 269 270 runOnMainThread(() -> assertFalse(sSession.isDestroyed())); 271 runOnMainThread(() -> assertEquals(0, sSession.getTrackedPrinters().size())); 272 273 // Select the first printer. 274 selectPrinter(FIRST_PRINTER_LOCAL_ID); 275 276 eventually(() -> runOnMainThread(() -> assertEquals(FIRST_PRINTER_LOCAL_ID, 277 sSession.getTrackedPrinters().get(0).getLocalId()))); 278 runOnMainThread(() -> assertTrue(sSession.isPrinterDiscoveryStarted())); 279 runOnMainThread(() -> assertEquals(1, sSession.getTrackedPrinters().size())); 280 281 // Wait for layout as the printer has different capabilities. 282 waitForLayoutAdapterCallbackCount(2); 283 284 // Select the second printer (same capabilities as the other 285 // one so no layout should happen). 286 selectPrinter(SECOND_PRINTER_LOCAL_ID); 287 288 eventually(() -> runOnMainThread(() -> assertEquals(SECOND_PRINTER_LOCAL_ID, 289 sSession.getTrackedPrinters().get(0).getLocalId()))); 290 runOnMainThread(() -> assertEquals(1, sSession.getTrackedPrinters().size())); 291 292 // While the printer discovery session is still alive store the 293 // ids of printers as we want to make some assertions about them 294 // but only the print service can create printer ids which means 295 // that we need to get the created ones. 296 PrinterId firstPrinterId = getAddedPrinterIdForLocalId( 297 FIRST_PRINTER_LOCAL_ID); 298 PrinterId secondPrinterId = getAddedPrinterIdForLocalId( 299 SECOND_PRINTER_LOCAL_ID); 300 assertNotNull("Coundn't find printer:" + FIRST_PRINTER_LOCAL_ID, firstPrinterId); 301 assertNotNull("Coundn't find printer:" + SECOND_PRINTER_LOCAL_ID, secondPrinterId); 302 303 // Click the print button. 304 clickPrintButton(); 305 306 // Answer the dialog for the print service cloud warning 307 answerPrintServicesWarning(true); 308 309 // Wait for all print jobs to be handled after which the session destroyed. 310 waitForPrinterDiscoverySessionDestroyCallbackCalled(1); 311 312 runOnMainThread(() -> assertTrue(sSession.isDestroyed())); 313 runOnMainThread(() -> assertFalse(sSession.isPrinterDiscoveryStarted())); 314 runOnMainThread(() -> assertEquals(0, sSession.getTrackedPrinters().size())); 315 316 // Verify the expected calls. 317 InOrder inOrder = inOrder(firstSessionCallbacks); 318 319 // We start discovery as the print dialog was up. 320 List<PrinterId> emptyPrinterIdList = Collections.emptyList(); 321 inOrder.verify(firstSessionCallbacks).onStartPrinterDiscovery( 322 emptyPrinterIdList); 323 324 // We selected the first printer and now it should be tracked. 325 inOrder.verify(firstSessionCallbacks).onStartPrinterStateTracking( 326 firstPrinterId); 327 328 // We selected the second printer so the first should not be tracked. 329 inOrder.verify(firstSessionCallbacks).onStopPrinterStateTracking( 330 firstPrinterId); 331 332 // We selected the second printer and now it should be tracked. 333 inOrder.verify(firstSessionCallbacks).onStartPrinterStateTracking( 334 secondPrinterId); 335 336 // The print dialog went away so we first stop the printer tracking... 337 inOrder.verify(firstSessionCallbacks).onStopPrinterStateTracking( 338 secondPrinterId); 339 340 // ... next we stop printer discovery... 341 inOrder.verify(firstSessionCallbacks).onStopPrinterDiscovery(); 342 343 // ... last the session is destroyed. 344 inOrder.verify(firstSessionCallbacks).onDestroy(); 345 } 346 347 @Test cancelPrintServicesAlertDialog()348 public void cancelPrintServicesAlertDialog() throws Throwable { 349 // Create the session callbacks that we will be checking. 350 final PrinterDiscoverySessionCallbacks firstSessionCallbacks = 351 createFirstMockPrinterDiscoverySessionCallbacks(); 352 353 // Create the service callbacks for the first print service. 354 PrintServiceCallbacks firstServiceCallbacks = createMockPrintServiceCallbacks( 355 invocation -> firstSessionCallbacks, 356 invocation -> { 357 PrintJob printJob = (PrintJob) invocation.getArguments()[0]; 358 // We pretend the job is handled immediately. 359 printJob.complete(); 360 return null; 361 }, null); 362 363 // Configure the print services. 364 FirstPrintService.setCallbacks(firstServiceCallbacks); 365 SecondPrintService.setCallbacks(createSecondMockPrintServiceCallbacks()); 366 367 // Create a print adapter that respects the print contract. 368 PrintDocumentAdapter adapter = createDefaultPrintDocumentAdapter(1); 369 370 // Start printing. 371 print(adapter); 372 373 // Wait for write of the first page. 374 waitForWriteAdapterCallback(1); 375 376 runOnMainThread(() -> assertFalse(sSession.isDestroyed())); 377 runOnMainThread(() -> assertEquals(0, sSession.getTrackedPrinters().size())); 378 379 // Select the first printer. 380 selectPrinter(FIRST_PRINTER_LOCAL_ID); 381 382 eventually(() -> runOnMainThread(() -> assertEquals(FIRST_PRINTER_LOCAL_ID, 383 sSession.getTrackedPrinters().get(0).getLocalId()))); 384 runOnMainThread(() -> assertTrue(sSession.isPrinterDiscoveryStarted())); 385 runOnMainThread(() -> assertEquals(1, sSession.getTrackedPrinters().size())); 386 387 // While the printer discovery session is still alive store the 388 // ids of printers as we want to make some assertions about them 389 // but only the print service can create printer ids which means 390 // that we need to get the created ones. 391 PrinterId firstPrinterId = getAddedPrinterIdForLocalId( 392 FIRST_PRINTER_LOCAL_ID); 393 assertNotNull("Coundn't find printer:" + FIRST_PRINTER_LOCAL_ID, firstPrinterId); 394 395 // Click the print button. 396 clickPrintButton(); 397 398 // Cancel the dialog for the print service cloud warning 399 answerPrintServicesWarning(false); 400 401 // Click the print button again. 402 clickPrintButton(); 403 404 // Answer the dialog for the print service cloud warning 405 answerPrintServicesWarning(true); 406 407 // Wait for all print jobs to be handled after which the session destroyed. 408 waitForPrinterDiscoverySessionDestroyCallbackCalled(1); 409 410 runOnMainThread(() -> assertTrue(sSession.isDestroyed())); 411 runOnMainThread(() -> assertFalse(sSession.isPrinterDiscoveryStarted())); 412 runOnMainThread(() -> assertEquals(0, sSession.getTrackedPrinters().size())); 413 414 // Verify the expected calls. 415 InOrder inOrder = inOrder(firstSessionCallbacks); 416 417 // We start discovery as the print dialog was up. 418 List<PrinterId> emptyPrinterIdList = Collections.emptyList(); 419 inOrder.verify(firstSessionCallbacks).onStartPrinterDiscovery( 420 emptyPrinterIdList); 421 422 // We selected the first printer and now it should be tracked. 423 inOrder.verify(firstSessionCallbacks).onStartPrinterStateTracking( 424 firstPrinterId); 425 426 // We selected the second printer so the first should not be tracked. 427 inOrder.verify(firstSessionCallbacks).onStopPrinterStateTracking( 428 firstPrinterId); 429 430 // ... next we stop printer discovery... 431 inOrder.verify(firstSessionCallbacks).onStopPrinterDiscovery(); 432 433 // ... last the session is destroyed. 434 inOrder.verify(firstSessionCallbacks).onDestroy(); 435 } 436 437 @Test startPrinterDiscoveryWithHistoricalPrinters()438 public void startPrinterDiscoveryWithHistoricalPrinters() throws Throwable { 439 // Create the session callbacks that we will be checking. 440 final PrinterDiscoverySessionCallbacks firstSessionCallbacks = 441 createFirstMockPrinterDiscoverySessionCallbacks(); 442 443 // Create the service callbacks for the first print service. 444 PrintServiceCallbacks firstServiceCallbacks = createMockPrintServiceCallbacks( 445 invocation -> firstSessionCallbacks, 446 invocation -> { 447 PrintJob printJob = (PrintJob) invocation.getArguments()[0]; 448 // We pretend the job is handled immediately. 449 printJob.complete(); 450 return null; 451 }, null); 452 453 // Configure the print services. 454 FirstPrintService.setCallbacks(firstServiceCallbacks); 455 SecondPrintService.setCallbacks(createSecondMockPrintServiceCallbacks()); 456 457 // Create a print adapter that respects the print contract. 458 PrintDocumentAdapter adapter = createDefaultPrintDocumentAdapter(1); 459 460 // Start printing. 461 print(adapter); 462 463 // Wait for write of the first page. 464 waitForWriteAdapterCallback(1); 465 466 runOnMainThread(() -> assertFalse(sSession.isDestroyed())); 467 runOnMainThread(() -> assertEquals(0, sSession.getTrackedPrinters().size())); 468 469 // Select the first printer. 470 selectPrinter(FIRST_PRINTER_LOCAL_ID); 471 472 eventually(() -> runOnMainThread(() -> assertEquals(FIRST_PRINTER_LOCAL_ID, 473 sSession.getTrackedPrinters().get(0).getLocalId()))); 474 runOnMainThread(() -> assertTrue(sSession.isPrinterDiscoveryStarted())); 475 runOnMainThread(() -> assertEquals(1, sSession.getTrackedPrinters().size())); 476 477 // Wait for a layout to finish - first layout was for the 478 // PDF printer, second for the first printer in preview mode. 479 waitForLayoutAdapterCallbackCount(2); 480 481 // While the printer discovery session is still alive store the 482 // ids of printer as we want to make some assertions about it 483 // but only the print service can create printer ids which means 484 // that we need to get the created one. 485 PrinterId firstPrinterId = getAddedPrinterIdForLocalId( 486 FIRST_PRINTER_LOCAL_ID); 487 488 // Click the print button. 489 clickPrintButton(); 490 491 // Answer the dialog for the print service cloud warning 492 answerPrintServicesWarning(true); 493 494 // Wait for the print to complete. 495 waitForAdapterFinishCallbackCalled(); 496 497 // Now print again as we want to confirm that the start 498 // printer discovery passes in the priority list. 499 print(adapter); 500 501 // Wait for a layout to finish - first layout was for the 502 // PDF printer, second for the first printer in preview mode, 503 // the third for the first printer in non-preview mode, and 504 // now a fourth for the PDF printer as we are printing again. 505 waitForLayoutAdapterCallbackCount(4); 506 507 // Cancel the printing. 508 getUiDevice().pressBack(); // wakes up the device. 509 getUiDevice().pressBack(); 510 511 // Wait for all print jobs to be handled after which the is session destroyed. 512 waitForPrinterDiscoverySessionDestroyCallbackCalled(1); 513 514 runOnMainThread(() -> assertTrue(sSession.isDestroyed())); 515 runOnMainThread(() -> assertFalse(sSession.isPrinterDiscoveryStarted())); 516 runOnMainThread(() -> assertEquals(0, sSession.getTrackedPrinters().size())); 517 518 // Verify the expected calls. 519 InOrder inOrder = inOrder(firstSessionCallbacks); 520 521 // We start discovery with no printer history. 522 List<PrinterId> priorityList = new ArrayList<>(); 523 inOrder.verify(firstSessionCallbacks).onStartPrinterDiscovery( 524 priorityList); 525 526 // We selected the first printer and now it should be tracked. 527 inOrder.verify(firstSessionCallbacks).onStartPrinterStateTracking( 528 firstPrinterId); 529 530 // We confirmed print so the first should not be tracked. 531 inOrder.verify(firstSessionCallbacks).onStopPrinterStateTracking( 532 firstPrinterId); 533 534 // This is tricky. It is possible that the print activity was not 535 // destroyed (the platform delays destruction at convenient time as 536 // an optimization) and we get the same instance which means that 537 // the discovery session may not have been destroyed. We try the 538 // case with the activity being destroyed and if this fails the 539 // case with the activity brought to front. 540 priorityList.add(firstPrinterId); 541 try { 542 inOrder.verify(firstSessionCallbacks).onStartPrinterDiscovery(priorityList); 543 } catch (VerificationInOrderFailure error) { 544 inOrder.verify(firstSessionCallbacks).onValidatePrinters(priorityList); 545 } 546 547 // The system selects the highest ranked historical printer. 548 inOrder.verify(firstSessionCallbacks).onStartPrinterStateTracking( 549 firstPrinterId); 550 551 // We canceled print so the first should not be tracked. 552 inOrder.verify(firstSessionCallbacks).onStopPrinterStateTracking( 553 firstPrinterId); 554 555 556 // Discovery is always stopped before the session is always destroyed. 557 inOrder.verify(firstSessionCallbacks).onStopPrinterDiscovery(); 558 559 // ...last the session is destroyed. 560 inOrder.verify(firstSessionCallbacks).onDestroy(); 561 } 562 563 @Test addRemovePrinters()564 public void addRemovePrinters() throws Throwable { 565 StubbablePrinterDiscoverySession[] session = new StubbablePrinterDiscoverySession[1]; 566 567 // Create the session callbacks that we will be checking. 568 final PrinterDiscoverySessionCallbacks firstSessionCallbacks = 569 createMockPrinterDiscoverySessionCallbacks(invocation -> { 570 session[0] = ((PrinterDiscoverySessionCallbacks) 571 invocation.getMock()).getSession(); 572 573 onPrinterDiscoverySessionCreateCalled(); 574 return null; 575 }, null, null, null, null, null, invocation -> { 576 onPrinterDiscoverySessionDestroyCalled(); 577 return null; 578 }); 579 580 // Create the service callbacks for the first print service. 581 PrintServiceCallbacks firstServiceCallbacks = createMockPrintServiceCallbacks( 582 invocation -> firstSessionCallbacks, null, null); 583 584 // Configure the print services. 585 FirstPrintService.setCallbacks(firstServiceCallbacks); 586 SecondPrintService.setCallbacks(createSecondMockPrintServiceCallbacks()); 587 588 print(createDefaultPrintDocumentAdapter(1)); 589 590 waitForPrinterDiscoverySessionCreateCallbackCalled(); 591 592 runOnMainThread(() -> assertEquals(0, session[0].getPrinters().size())); 593 594 PrinterId[] printerIds = new PrinterId[3]; 595 runOnMainThread(() -> { 596 printerIds[0] = session[0].getService().generatePrinterId("0"); 597 printerIds[1] = session[0].getService().generatePrinterId("1"); 598 printerIds[2] = session[0].getService().generatePrinterId("2"); 599 }); 600 601 PrinterInfo printer1 = (new PrinterInfo.Builder(printerIds[0], "0", 602 PrinterInfo.STATUS_IDLE)).build(); 603 604 PrinterInfo printer2 = (new PrinterInfo.Builder(printerIds[1], "1", 605 PrinterInfo.STATUS_IDLE)).build(); 606 607 PrinterInfo printer3 = (new PrinterInfo.Builder(printerIds[2], "2", 608 PrinterInfo.STATUS_IDLE)).build(); 609 610 ArrayList<PrinterInfo> printers = new ArrayList<>(); 611 printers.add(printer1); 612 runOnMainThread(() -> session[0].addPrinters(printers)); 613 eventually(() -> runOnMainThread(() -> assertEquals(1, session[0].getPrinters().size()))); 614 615 printers.add(printer2); 616 printers.add(printer3); 617 runOnMainThread(() -> session[0].addPrinters(printers)); 618 eventually(() -> runOnMainThread(() -> assertEquals(3, session[0].getPrinters().size()))); 619 620 ArrayList<PrinterId> printerIdsToRemove = new ArrayList<>(); 621 printerIdsToRemove.add(printer1.getId()); 622 runOnMainThread(() -> session[0].removePrinters(printerIdsToRemove)); 623 eventually(() -> runOnMainThread(() -> assertEquals(2, session[0].getPrinters().size()))); 624 625 printerIdsToRemove.add(printer2.getId()); 626 printerIdsToRemove.add(printer3.getId()); 627 runOnMainThread(() -> session[0].removePrinters(printerIdsToRemove)); 628 eventually(() -> runOnMainThread(() -> assertEquals(0, session[0].getPrinters().size()))); 629 630 getUiDevice().pressBack(); 631 632 waitForPrinterDiscoverySessionDestroyCallbackCalled(1); 633 } 634 getAddedPrinterIdForLocalId(String printerLocalId)635 private PrinterId getAddedPrinterIdForLocalId(String printerLocalId) throws Throwable { 636 final List<PrinterInfo> reportedPrinters = new ArrayList<>(); 637 runOnMainThread(() -> { 638 // Grab the printer ids as only the service can create such. 639 reportedPrinters.addAll(sSession.getPrinters()); 640 }); 641 642 final int reportedPrinterCount = reportedPrinters.size(); 643 for (int i = 0; i < reportedPrinterCount; i++) { 644 PrinterInfo reportedPrinter = reportedPrinters.get(i); 645 String localId = reportedPrinter.getId().getLocalId(); 646 if (printerLocalId.equals(localId)) { 647 return reportedPrinter.getId(); 648 } 649 } 650 651 return null; 652 } 653 createSecondMockPrintServiceCallbacks()654 private PrintServiceCallbacks createSecondMockPrintServiceCallbacks() { 655 return createMockPrintServiceCallbacks(null, null, null); 656 } 657 createFirstMockPrinterDiscoverySessionCallbacks()658 private PrinterDiscoverySessionCallbacks createFirstMockPrinterDiscoverySessionCallbacks() { 659 return createMockPrinterDiscoverySessionCallbacks(invocation -> { 660 // Get the session. 661 sSession = ((PrinterDiscoverySessionCallbacks) 662 invocation.getMock()).getSession(); 663 664 assertTrue(sSession.isPrinterDiscoveryStarted()); 665 666 addPrinter(FIRST_PRINTER_LOCAL_ID, false); 667 addPrinter(SECOND_PRINTER_LOCAL_ID, false); 668 669 return null; 670 }, invocation -> { 671 assertFalse(sSession.isPrinterDiscoveryStarted()); 672 return null; 673 }, null, invocation -> { 674 // Get the session. 675 StubbablePrinterDiscoverySession session = ((PrinterDiscoverySessionCallbacks) 676 invocation.getMock()).getSession(); 677 678 PrinterId trackedPrinterId = (PrinterId) invocation.getArguments()[0]; 679 List<PrinterInfo> reportedPrinters = session.getPrinters(); 680 681 // We should be tracking a printer that we added. 682 PrinterInfo trackedPrinter = null; 683 final int reportedPrinterCount = reportedPrinters.size(); 684 for (int i = 0; i < reportedPrinterCount; i++) { 685 PrinterInfo reportedPrinter = reportedPrinters.get(i); 686 if (reportedPrinter.getId().equals(trackedPrinterId)) { 687 trackedPrinter = reportedPrinter; 688 break; 689 } 690 } 691 assertNotNull("Can track only added printers", trackedPrinter); 692 693 assertTrue(sSession.getTrackedPrinters().contains(trackedPrinter.getId())); 694 assertEquals(1, sSession.getTrackedPrinters().size()); 695 696 // If the printer does not have capabilities reported add them. 697 if (trackedPrinter.getCapabilities() == null) { 698 699 // Add the capabilities to emulate lazy discovery. 700 // Same for each printer is fine for what we test. 701 PrinterCapabilitiesInfo capabilities = 702 new PrinterCapabilitiesInfo.Builder(trackedPrinterId) 703 .setMinMargins(new Margins(200, 200, 200, 200)) 704 .addMediaSize(MediaSize.ISO_A4, true) 705 .addMediaSize(MediaSize.ISO_A5, false) 706 .addResolution(new Resolution("300x300", "300x300", 300, 300), true) 707 .setColorModes(PrintAttributes.COLOR_MODE_COLOR, 708 PrintAttributes.COLOR_MODE_COLOR) 709 .build(); 710 PrinterInfo updatedPrinter = new PrinterInfo.Builder(trackedPrinter) 711 .setCapabilities(capabilities) 712 .build(); 713 714 // Update the printer. 715 List<PrinterInfo> printers = new ArrayList<>(); 716 printers.add(updatedPrinter); 717 session.addPrinters(printers); 718 } 719 720 return null; 721 }, null, null, invocation -> { 722 assertTrue(sSession.isDestroyed()); 723 724 // Take a note onDestroy was called. 725 onPrinterDiscoverySessionDestroyCalled(); 726 return null; 727 }); 728 } 729 } 730