Merge "Adding CTS test for printer discovery session lifycycle."
diff --git a/tests/tests/print/AndroidManifest.xml b/tests/tests/print/AndroidManifest.xml
index 82715cb..4c94fd5 100644
--- a/tests/tests/print/AndroidManifest.xml
+++ b/tests/tests/print/AndroidManifest.xml
@@ -23,7 +23,7 @@
 
         <uses-library android:name="android.test.runner"/>
 
-        <activity android:name="android.print.cts.PrintDocumentAdapterContractActivity"/>
+        <activity android:name="android.print.cts.PrintDocumentActivity"/>
 
         <service
             android:name="android.print.cts.services.FirstPrintService"
diff --git a/tests/tests/print/src/android/print/cts/BasePrintTest.java b/tests/tests/print/src/android/print/cts/BasePrintTest.java
index c1973ca..d193bb0 100644
--- a/tests/tests/print/src/android/print/cts/BasePrintTest.java
+++ b/tests/tests/print/src/android/print/cts/BasePrintTest.java
@@ -71,7 +71,7 @@
 
     protected static final String PRINT_JOB_NAME = "Test";
 
-    private PrintDocumentAdapterContractActivity mActivity;
+    private PrintDocumentActivity mActivity;
 
     private Locale mOldLocale;
 
@@ -79,6 +79,7 @@
     private CallCounter mWriteCallCounter;
     private CallCounter mFinishCallCounter;
     private CallCounter mPrintJobQueuedCallCounter;
+    private CallCounter mDestroySessionCallCounter;
 
     @Override
     public void setUp() throws Exception {
@@ -107,6 +108,7 @@
         mWriteCallCounter = new CallCounter();
         mFinishCallCounter = new CallCounter();
         mPrintJobQueuedCallCounter = new CallCounter();
+        mDestroySessionCallCounter = new CallCounter();
 
         // Create the activity for the right locale.
         createActivity();
@@ -159,12 +161,21 @@
         mPrintJobQueuedCallCounter.call();
     }
 
+    protected void onPrinterDiscoverySessionDestroyCalled() {
+        mDestroySessionCallCounter.call();
+    }
+
+    protected void waitForPrinterDiscoverySessionDestroyCallbackCalled() {
+        waitForCallbackCallCount(mDestroySessionCallCounter, 1,
+                "Did not get expected call to onDestroyPrinterDiscoverySession.");
+    }
+
     protected void waitForServiceOnPrintJobQueuedCallbackCalled() {
         waitForCallbackCallCount(mPrintJobQueuedCallCounter, 1,
                 "Did not get expected call to onPrintJobQueued.");
     }
 
-    protected void waitForAdapterCallbackFinish() {
+    protected void waitForAdapterFinishCallbackCalled() {
         waitForCallbackCallCount(mFinishCallCounter, 1,
                 "Did not get expected call to finish.");
     }
@@ -224,14 +235,14 @@
         printButton.click();
     }
 
-    protected PrintDocumentAdapterContractActivity getActivity() {
+    protected PrintDocumentActivity getActivity() {
         return mActivity;
     }
 
     private void createActivity() {
         mActivity = launchActivity(
                 getInstrumentation().getTargetContext().getPackageName(),
-                PrintDocumentAdapterContractActivity.class, null);
+                PrintDocumentActivity.class, null);
     }
 
     protected void clearPrintSpoolerData() throws Exception {
diff --git a/tests/tests/print/src/android/print/cts/PageRangeAdjustmentTest.java b/tests/tests/print/src/android/print/cts/PageRangeAdjustmentTest.java
index cf28800..d3d5a4c 100644
--- a/tests/tests/print/src/android/print/cts/PageRangeAdjustmentTest.java
+++ b/tests/tests/print/src/android/print/cts/PageRangeAdjustmentTest.java
@@ -139,7 +139,7 @@
         clickPrintButton();
 
         // Wait for finish.
-        waitForAdapterCallbackFinish();
+        waitForAdapterFinishCallbackCalled();
 
         // Wait for the print job.
         waitForServiceOnPrintJobQueuedCallbackCalled();
@@ -239,7 +239,7 @@
         clickPrintButton();
 
         // Wait for finish.
-        waitForAdapterCallbackFinish();
+        waitForAdapterFinishCallbackCalled();
 
         // Wait for the print job.
         waitForServiceOnPrintJobQueuedCallbackCalled();
@@ -351,7 +351,7 @@
         clickPrintButton();
 
         // Wait for finish.
-        waitForAdapterCallbackFinish();
+        waitForAdapterFinishCallbackCalled();
 
         // Wait for the print job.
         waitForServiceOnPrintJobQueuedCallbackCalled();
@@ -439,7 +439,7 @@
         UiDevice.getInstance().pressBack();
 
         // Wait for finish.
-        waitForAdapterCallbackFinish();
+        waitForAdapterFinishCallbackCalled();
 
         // Verify the expected calls.
         InOrder inOrder = inOrder(firstServiceCallbacks);
@@ -491,7 +491,7 @@
                                 PrintAttributes.COLOR_MODE_COLOR)
                         .build();
                     PrinterInfo firstPrinter = new PrinterInfo.Builder(firstPrinterId,
-                            "First printer", PrinterInfo.STATUS_IDLE)
+                            FIRST_PRINTER, PrinterInfo.STATUS_IDLE)
                         .setCapabilities(firstCapabilities)
                         .build();
                     printers.add(firstPrinter);
diff --git a/tests/tests/print/src/android/print/cts/PrintDocumentAdapterContractActivity.java b/tests/tests/print/src/android/print/cts/PrintDocumentActivity.java
similarity index 92%
rename from tests/tests/print/src/android/print/cts/PrintDocumentAdapterContractActivity.java
rename to tests/tests/print/src/android/print/cts/PrintDocumentActivity.java
index eb80bb7..6a191a6 100644
--- a/tests/tests/print/src/android/print/cts/PrintDocumentAdapterContractActivity.java
+++ b/tests/tests/print/src/android/print/cts/PrintDocumentActivity.java
@@ -19,7 +19,7 @@
 import android.app.Activity;
 import android.os.Bundle;
 
-public class PrintDocumentAdapterContractActivity extends Activity {
+public class PrintDocumentActivity extends Activity {
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
diff --git a/tests/tests/print/src/android/print/cts/PrintDocumentAdapterContractTest.java b/tests/tests/print/src/android/print/cts/PrintDocumentAdapterContractTest.java
index 64c225a..57eae3f 100644
--- a/tests/tests/print/src/android/print/cts/PrintDocumentAdapterContractTest.java
+++ b/tests/tests/print/src/android/print/cts/PrintDocumentAdapterContractTest.java
@@ -116,7 +116,7 @@
         clickPrintButton();
 
         // Wait for finish.
-        waitForAdapterCallbackFinish();
+        waitForAdapterFinishCallbackCalled();
 
         // Verify the expected calls.
         InOrder inOrder = inOrder(adapter);
@@ -220,7 +220,7 @@
         UiDevice.getInstance().pressBack();
 
         // Wait for finish.
-        waitForAdapterCallbackFinish();
+        waitForAdapterFinishCallbackCalled();
 
         // Verify the expected calls.
         InOrder inOrder = inOrder(adapter);
@@ -328,7 +328,7 @@
         clickPrintButton();
 
         // Wait for a finish.
-        waitForAdapterCallbackFinish();
+        waitForAdapterFinishCallbackCalled();
 
         // Verify the expected calls.
         InOrder inOrder = inOrder(adapter);
@@ -488,7 +488,7 @@
         clickPrintButton();
 
         // Wait for a finish.
-        waitForAdapterCallbackFinish();
+        waitForAdapterFinishCallbackCalled();
 
         // Verify the expected calls.
         InOrder inOrder = inOrder(adapter);
@@ -621,7 +621,7 @@
         clickPrintButton();
 
         // Wait for a finish.
-        waitForAdapterCallbackFinish();
+        waitForAdapterFinishCallbackCalled();
 
         // Verify the expected calls.
         InOrder inOrder = inOrder(adapter);
@@ -728,7 +728,7 @@
         clickPrintButton();
 
         // Wait for a finish.
-        waitForAdapterCallbackFinish();
+        waitForAdapterFinishCallbackCalled();
 
         // Verify the expected calls.
         InOrder inOrder = inOrder(adapter);
@@ -822,7 +822,7 @@
         clickPrintButton();
 
         // Wait for a finish.
-        waitForAdapterCallbackFinish();
+        waitForAdapterFinishCallbackCalled();
 
         // Verify the expected calls.
         InOrder inOrder = inOrder(adapter);
@@ -917,7 +917,7 @@
         UiDevice.getInstance().pressBack();
 
         // Wait for a finish.
-        waitForAdapterCallbackFinish();
+        waitForAdapterFinishCallbackCalled();
 
         // Verify the expected calls.
         InOrder inOrder = inOrder(adapter);
@@ -1001,7 +1001,7 @@
         UiDevice.getInstance().pressBack();
 
         // Wait for a finish.
-        waitForAdapterCallbackFinish();
+        waitForAdapterFinishCallbackCalled();
 
         // Verify the expected calls.
         InOrder inOrder = inOrder(adapter);
@@ -1067,7 +1067,7 @@
         UiDevice.getInstance().pressBack();
 
         // Wait for a finish.
-        waitForAdapterCallbackFinish();
+        waitForAdapterFinishCallbackCalled();
 
         // Verify the expected calls.
         InOrder inOrder = inOrder(adapter);
@@ -1143,7 +1143,7 @@
         UiDevice.getInstance().pressBack();
 
         // Wait for a finish.
-        waitForAdapterCallbackFinish();
+        waitForAdapterFinishCallbackCalled();
 
         // Verify the expected calls.
         InOrder inOrder = inOrder(adapter);
@@ -1224,7 +1224,7 @@
         UiDevice.getInstance().pressBack();
 
         // Wait for a finish.
-        waitForAdapterCallbackFinish();
+        waitForAdapterFinishCallbackCalled();
 
         // Verify the expected calls.
         InOrder inOrder = inOrder(adapter);
@@ -1289,7 +1289,7 @@
         UiDevice.getInstance().pressBack();
 
         // Wait for a finish.
-        waitForAdapterCallbackFinish();
+        waitForAdapterFinishCallbackCalled();
 
         // Verify the expected calls.
         InOrder inOrder = inOrder(adapter);
@@ -1362,7 +1362,7 @@
         UiDevice.getInstance().pressBack();
 
         // Wait for a finish.
-        waitForAdapterCallbackFinish();
+        waitForAdapterFinishCallbackCalled();
 
         // Verify the expected calls.
         InOrder inOrder = inOrder(adapter);
diff --git a/tests/tests/print/src/android/print/cts/PrinterDiscoverySessionLifecycleTest.java b/tests/tests/print/src/android/print/cts/PrinterDiscoverySessionLifecycleTest.java
new file mode 100644
index 0000000..cb6a6d1
--- /dev/null
+++ b/tests/tests/print/src/android/print/cts/PrinterDiscoverySessionLifecycleTest.java
@@ -0,0 +1,407 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.print.cts;
+
+import static org.mockito.Mockito.inOrder;
+
+import android.os.ParcelFileDescriptor;
+import android.print.PageRange;
+import android.print.PrintAttributes;
+import android.print.PrintAttributes.Margins;
+import android.print.PrintAttributes.MediaSize;
+import android.print.PrintAttributes.Resolution;
+import android.print.PrintDocumentAdapter;
+import android.print.PrintDocumentAdapter.LayoutResultCallback;
+import android.print.PrintDocumentAdapter.WriteResultCallback;
+import android.print.PrintDocumentInfo;
+import android.print.PrinterCapabilitiesInfo;
+import android.print.PrinterId;
+import android.print.PrinterInfo;
+import android.print.cts.services.FirstPrintService;
+import android.print.cts.services.PrintServiceCallbacks;
+import android.print.cts.services.PrinterDiscoverySessionCallbacks;
+import android.print.cts.services.SecondPrintService;
+import android.print.cts.services.StubbablePrinterDiscoverySession;
+import android.printservice.PrintJob;
+import android.printservice.PrinterDiscoverySession;
+import android.support.test.uiautomator.UiDevice;
+
+import org.mockito.InOrder;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * This test verifies that the system respects the {@link PrinterDiscoverySession}
+ * contract is respected.
+ */
+public class PrinterDiscoverySessionLifecycleTest extends BasePrintTest {
+    private static final String FIRST_PRINTER_NAME = "First printer";
+    private static final String SECOND_PRINTER_NAME = "Second printer";
+
+    private static final String FIRST_PRINTER_LOCAL_ID= "first_printer";
+    private static final String SECOND_PRINTER_LOCAL_ID = "second_printer";
+
+    public void testNormalLifecycle() throws Exception {
+        // Create the session callbacks that we will be checking.
+        final PrinterDiscoverySessionCallbacks firstSessionCallbacks =
+                createFirstMockPrinterDiscoverySessionCallbacks();
+
+        // Create the service callbacks for the first print service.
+        PrintServiceCallbacks firstServiceCallbacks = createMockPrintServiceCallbacks(
+                new Answer<PrinterDiscoverySessionCallbacks>() {
+                @Override
+                public PrinterDiscoverySessionCallbacks answer(InvocationOnMock invocation) {
+                        return firstSessionCallbacks;
+                    }
+                },
+                new Answer<Void>() {
+                @Override
+                public Void answer(InvocationOnMock invocation) {
+                    PrintJob printJob = (PrintJob) invocation.getArguments()[0];
+                    // We pretend the job is handled immediately.
+                    printJob.complete();
+                    return null;
+                }
+            }, null);
+
+        // Configure the print services.
+        FirstPrintService.setCallbacks(firstServiceCallbacks);
+        SecondPrintService.setCallbacks(createSecondMockPrintServiceCallbacks());
+
+        // Create a print adapter that respects the print contract.
+        PrintDocumentAdapter adapter = createMockPrintDocumentAdapter();
+
+        // Start printing.
+        print(adapter);
+
+        // Wait for write of the first page.
+        waitForWriteForAdapterCallback();
+
+        // Select the first printer.
+        selectPrinter(FIRST_PRINTER_NAME);
+
+        // Wait for layout as the printer has different capabilities.
+        waitForLayoutAdapterCallbackCount(2);
+
+        // Select the second printer (same capabilities as the other
+        // one so no layout should happen).
+        selectPrinter(SECOND_PRINTER_NAME);
+
+        // While the printer discovery session is still alive store the
+        // ids of printers as we want to make some assertions about them
+        // but only the print service can create printer ids which means
+        // that we need to get the created ones.
+        PrinterId firstPrinterId = getAddedPrinterIdForLocalId(firstSessionCallbacks,
+                FIRST_PRINTER_LOCAL_ID);
+        PrinterId secondPrinterId = getAddedPrinterIdForLocalId(firstSessionCallbacks,
+                SECOND_PRINTER_LOCAL_ID);
+        assertNotNull("Coundn't find printer:" + FIRST_PRINTER_LOCAL_ID, firstPrinterId);
+        assertNotNull("Coundn't find printer:" + SECOND_PRINTER_LOCAL_ID, secondPrinterId);
+
+        // Click the print button.
+        clickPrintButton();
+
+        // Wait for all print jobs to be handled after which the session destroyed.
+        waitForPrinterDiscoverySessionDestroyCallbackCalled();
+
+        // Verify the expected calls.
+        InOrder inOrder = inOrder(firstSessionCallbacks);
+
+        // We start discovery as the print dialog was up.
+        List<PrinterId> emptyPrinterIdList = Collections.emptyList();
+        inOrder.verify(firstSessionCallbacks).onStartPrinterDiscovery(
+                emptyPrinterIdList);
+
+        // We selected the first printer and now it should be tracked.
+        inOrder.verify(firstSessionCallbacks).onStartPrinterStateTracking(
+                firstPrinterId);
+
+        // We selected the second printer so the first should not be tracked.
+        inOrder.verify(firstSessionCallbacks).onStopPrinterStateTracking(
+                firstPrinterId);
+
+        // We selected the second printer and now it should be tracked.
+        inOrder.verify(firstSessionCallbacks).onStartPrinterStateTracking(
+                secondPrinterId);
+
+        // The print dialog went away so we first stop the printer tracking...
+        inOrder.verify(firstSessionCallbacks).onStopPrinterStateTracking(
+                secondPrinterId);
+
+        // ... next we stop printer discovery...
+        inOrder.verify(firstSessionCallbacks).onStopPrinterDiscovery();
+
+        // ... last the session is destroyed.
+        inOrder.verify(firstSessionCallbacks).onDestroy();
+    }
+
+    public void testStartPrinterDiscoveryWithHistoricalPrinters() throws Exception {
+        // Create the session callbacks that we will be checking.
+        final PrinterDiscoverySessionCallbacks firstSessionCallbacks =
+                createFirstMockPrinterDiscoverySessionCallbacks();
+
+        // Create the service callbacks for the first print service.
+        PrintServiceCallbacks firstServiceCallbacks = createMockPrintServiceCallbacks(
+                new Answer<PrinterDiscoverySessionCallbacks>() {
+                @Override
+                public PrinterDiscoverySessionCallbacks answer(InvocationOnMock invocation) {
+                        return firstSessionCallbacks;
+                    }
+                },
+                new Answer<Void>() {
+                @Override
+                public Void answer(InvocationOnMock invocation) {
+                    PrintJob printJob = (PrintJob) invocation.getArguments()[0];
+                    // We pretend the job is handled immediately.
+                    printJob.complete();
+                    return null;
+                }
+            }, null);
+
+        // Configure the print services.
+        FirstPrintService.setCallbacks(firstServiceCallbacks);
+        SecondPrintService.setCallbacks(createSecondMockPrintServiceCallbacks());
+
+        // Create a print adapter that respects the print contract.
+        PrintDocumentAdapter adapter = createMockPrintDocumentAdapter();
+
+        // Start printing.
+        print(adapter);
+
+        // Wait for write of the first page.
+        waitForWriteForAdapterCallback();
+
+        // Select the first printer.
+        selectPrinter(FIRST_PRINTER_NAME);
+
+        // Wait for a layout to finish - first layout was for the
+        // PDF printer, second for the first printer in preview mode.
+        waitForLayoutAdapterCallbackCount(2);
+
+        // While the printer discovery session is still alive store the
+        // ids of printer as we want to make some assertions about it
+        // but only the print service can create printer ids which means
+        // that we need to get the created one.
+        PrinterId firstPrinterId = getAddedPrinterIdForLocalId(
+                firstSessionCallbacks, FIRST_PRINTER_LOCAL_ID);
+
+        // Click the print button.
+        clickPrintButton();
+
+        // Wait for the print to complete.
+        waitForAdapterFinishCallbackCalled();
+
+        // Now print again as we want to confirm that the start
+        // printer discovery passes in the priority list.
+        print(adapter);
+
+        // Wait for a layout to finish - first layout was for the
+        // PDF printer, second for the first printer in preview mode,
+        // the third for the first printer in non-preview mode, and
+        // now a fourth for the PDF printer as we are printing again.
+        waitForLayoutAdapterCallbackCount(4);
+
+        // Cancel the printing.
+        UiDevice.getInstance().pressBack(); // wakes up the device.
+        UiDevice.getInstance().pressBack();
+
+        // Wait for all print jobs to be handled after which the session destroyed.
+        waitForPrinterDiscoverySessionDestroyCallbackCalled();
+
+        // Verify the expected calls.
+        InOrder inOrder = inOrder(firstSessionCallbacks);
+
+        // We start discovery as the print dialog was up.
+        List<PrinterId> priorityList = new ArrayList<PrinterId>();
+        priorityList.add(firstPrinterId);
+        inOrder.verify(firstSessionCallbacks).onStartPrinterDiscovery(
+                priorityList);
+
+        // We selected the first printer and now it should be tracked.
+        inOrder.verify(firstSessionCallbacks).onStartPrinterStateTracking(
+                firstPrinterId);
+
+        // We selected the second printer so the first should not be tracked.
+        inOrder.verify(firstSessionCallbacks).onStopPrinterStateTracking(
+                firstPrinterId);
+
+        // ...next we stop printer discovery...
+        inOrder.verify(firstSessionCallbacks).onStopPrinterDiscovery();
+
+        // ...last the session is destroyed.
+        inOrder.verify(firstSessionCallbacks).onDestroy();
+    }
+
+    private PrinterId getAddedPrinterIdForLocalId(
+            final PrinterDiscoverySessionCallbacks sessionCallbacks, String printerLocalId) {
+        final List<PrinterInfo> reportedPrinters = new ArrayList<PrinterInfo>();
+        getInstrumentation().runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                // Grab the printer ids as only the service can create such.
+                StubbablePrinterDiscoverySession session = sessionCallbacks.getSession();
+                reportedPrinters.addAll(session.getPrinters());
+            }
+        });
+
+        final int reportedPrinterCount = reportedPrinters.size();
+        for (int i = 0; i < reportedPrinterCount; i++) {
+            PrinterInfo reportedPrinter = reportedPrinters.get(i);
+            String localId = reportedPrinter.getId().getLocalId();
+            if (printerLocalId.equals(localId)) {
+                return reportedPrinter.getId();
+            }
+        }
+
+        return null;
+    }
+
+    private PrintServiceCallbacks createSecondMockPrintServiceCallbacks() {
+        return createMockPrintServiceCallbacks(null, null, null);
+    }
+
+    private PrinterDiscoverySessionCallbacks createFirstMockPrinterDiscoverySessionCallbacks() {
+        return createMockPrinterDiscoverySessionCallbacks(new Answer<Void>() {
+            @Override
+            public Void answer(InvocationOnMock invocation) {
+                // Get the session.
+                StubbablePrinterDiscoverySession session = ((PrinterDiscoverySessionCallbacks)
+                        invocation.getMock()).getSession();
+
+                if (session.getPrinters().isEmpty()) {
+                    List<PrinterInfo> printers = new ArrayList<PrinterInfo>();
+
+                    // Add the first printer.
+                    PrinterId firstPrinterId = session.getService().generatePrinterId(
+                            FIRST_PRINTER_LOCAL_ID);
+                    PrinterInfo firstPrinter = new PrinterInfo.Builder(firstPrinterId,
+                            FIRST_PRINTER_NAME, PrinterInfo.STATUS_IDLE)
+                        .build();
+                    printers.add(firstPrinter);
+
+                    // Add the first printer.
+                    PrinterId secondPrinterId = session.getService().generatePrinterId(
+                            SECOND_PRINTER_LOCAL_ID);
+                    PrinterInfo secondPrinter = new PrinterInfo.Builder(secondPrinterId,
+                            SECOND_PRINTER_NAME, PrinterInfo.STATUS_IDLE)
+                        .build();
+                    printers.add(secondPrinter);
+
+                    session.addPrinters(printers);
+                }
+                return null;
+            }
+        }, null, null, new Answer<Void>() {
+            @Override
+            public Void answer(InvocationOnMock invocation) throws Throwable {
+                // Get the session.
+                StubbablePrinterDiscoverySession session = ((PrinterDiscoverySessionCallbacks)
+                        invocation.getMock()).getSession();
+
+                PrinterId trackedPrinterId = (PrinterId) invocation.getArguments()[0];
+                List<PrinterInfo> reportedPrinters = session.getPrinters();
+
+                // We should be tracking a printer that we added.
+                PrinterInfo trackedPrinter = null;
+                final int reportedPrinterCount = reportedPrinters.size();
+                for (int i = 0; i < reportedPrinterCount; i++) {
+                    PrinterInfo reportedPrinter = reportedPrinters.get(i);
+                    if (reportedPrinter.getId().equals(trackedPrinterId)) {
+                        trackedPrinter = reportedPrinter;
+                        break;
+                    }
+                }
+                assertNotNull("Can track only added printers", trackedPrinter);
+
+                // If the printer does not have capabilities reported add them.
+                if (trackedPrinter.getCapabilities() == null) {
+
+                    // Add the capabilities to emulate lazy discovery.
+                    // Same for each printer is fine for what we test.
+                    PrinterCapabilitiesInfo capabilities =
+                            new PrinterCapabilitiesInfo.Builder(trackedPrinterId)
+                        .setMinMargins(new Margins(200, 200, 200, 200))
+                        .addMediaSize(MediaSize.ISO_A4, true)
+                        .addMediaSize(MediaSize.ISO_A5, false)
+                        .addResolution(new Resolution("300x300", "300x300", 300, 300), true)
+                        .setColorModes(PrintAttributes.COLOR_MODE_COLOR,
+                                PrintAttributes.COLOR_MODE_COLOR)
+                        .build();
+                    PrinterInfo updatedPrinter = new PrinterInfo.Builder(trackedPrinter)
+                        .setCapabilities(capabilities)
+                        .build();
+
+                    // Update the printer.
+                    List<PrinterInfo> printers = new ArrayList<PrinterInfo>();
+                    printers.add(updatedPrinter);
+                    session.addPrinters(printers);
+                }
+
+                return null;
+            }
+        }, null, new Answer<Void>() {
+            @Override
+            public Void answer(InvocationOnMock invocation) throws Throwable {
+                // Take a note onDestroy was called.
+                onPrinterDiscoverySessionDestroyCalled();
+                return null;
+            }
+        });
+    }
+
+    public PrintDocumentAdapter createMockPrintDocumentAdapter() {
+        return createMockPrintDocumentAdapter(
+            new Answer<Void>() {
+            @Override
+            public Void answer(InvocationOnMock invocation) throws Throwable {
+                LayoutResultCallback callback = (LayoutResultCallback) invocation.getArguments()[3];
+                PrintDocumentInfo info = new PrintDocumentInfo.Builder(PRINT_JOB_NAME)
+                        .setContentType(PrintDocumentInfo.CONTENT_TYPE_DOCUMENT)
+                        .setPageCount(3)
+                        .build();
+                callback.onLayoutFinished(info, false);
+                // Mark layout was called.
+                onLayoutCalled();
+                return null;
+            }
+        }, new Answer<Void>() {
+            @Override
+            public Void answer(InvocationOnMock invocation) throws Throwable {
+                Object[] args = invocation.getArguments();
+                PageRange[] pages = (PageRange[]) args[0];
+                ParcelFileDescriptor fd = (ParcelFileDescriptor) args[1];
+                WriteResultCallback callback = (WriteResultCallback) args[3];
+                fd.close();
+                callback.onWriteFinished(pages);
+                // Mark write was called.
+                onWriteCalled();
+                return null;
+            }
+        }, new Answer<Void>() {
+            @Override
+            public Void answer(InvocationOnMock invocation) throws Throwable {
+                // Mark finish was called.
+                onFinishCalled();
+                return null;
+            }
+        });
+    }
+}