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