Home | History | Annotate | Download | only in cts
      1 /*
      2  * Copyright (C) 2018 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.PrintAttributes.COLOR_MODE_COLOR;
     20 import static android.print.PrintAttributes.MediaSize.ISO_A5;
     21 import static android.print.PrinterInfo.STATUS_IDLE;
     22 import static android.print.PrinterInfo.STATUS_UNAVAILABLE;
     23 import static android.print.test.Utils.runOnMainThread;
     24 
     25 import android.os.CancellationSignal;
     26 import android.os.ParcelFileDescriptor;
     27 import android.print.PageRange;
     28 import android.print.PrintAttributes;
     29 import android.print.PrintAttributes.Margins;
     30 import android.print.PrintAttributes.Resolution;
     31 import android.print.PrintDocumentAdapter;
     32 import android.print.PrintDocumentAdapter.LayoutResultCallback;
     33 import android.print.PrintDocumentAdapter.WriteResultCallback;
     34 import android.print.PrintDocumentInfo;
     35 import android.print.PrinterCapabilitiesInfo;
     36 import android.print.PrinterId;
     37 import android.print.PrinterInfo;
     38 import android.print.test.BasePrintTest;
     39 import android.print.test.services.FirstPrintService;
     40 import android.print.test.services.PrinterDiscoverySessionCallbacks;
     41 import android.print.test.services.SecondPrintService;
     42 import android.print.test.services.StubbablePrinterDiscoverySession;
     43 
     44 import androidx.test.runner.AndroidJUnit4;
     45 
     46 import org.junit.Before;
     47 import org.junit.Test;
     48 import org.junit.runner.RunWith;
     49 
     50 import java.util.ArrayList;
     51 import java.util.List;
     52 
     53 /**
     54  * Tests interaction between printer discovery and print document lifecycle
     55  */
     56 @RunWith(AndroidJUnit4.class)
     57 public class InteractionBetweenPrintDocumentAndPrinterDiscovery extends BasePrintTest {
     58     static final String PRINTER_NAME = "Test printer";
     59 
     60     @Before
     61     public void clearPrintSpoolerState() throws Exception {
     62         clearPrintSpoolerData();
     63     }
     64 
     65     /**
     66      * Add or update the test printer.
     67      *
     68      * @param session The printer discovery session the printer belongs to
     69      * @param status  the status of the printer (idle, unavailable, busy)
     70      */
     71     private static void addPrinter(StubbablePrinterDiscoverySession session, int status) {
     72         List<PrinterInfo> printers = new ArrayList<>();
     73 
     74         PrinterId testId = session.getService().generatePrinterId(PRINTER_NAME);
     75         PrinterCapabilitiesInfo testCap =
     76                 new PrinterCapabilitiesInfo.Builder(testId)
     77                         .setMinMargins(new Margins(0, 0, 0, 0))
     78                         .addMediaSize(ISO_A5, true)
     79                         .addResolution(new Resolution("r", "r", 1, 1), true)
     80                         .setColorModes(COLOR_MODE_COLOR, COLOR_MODE_COLOR)
     81                         .build();
     82         PrinterInfo testPrinter = new PrinterInfo.Builder(testId, PRINTER_NAME, status)
     83                 .setCapabilities(testCap).build();
     84         printers.add(testPrinter);
     85 
     86         session.addPrinters(printers);
     87     }
     88 
     89     /**
     90      * While a print document adapter write task is getting canceled, make the printer unavailable
     91      * and available again.
     92      */
     93     @Test
     94     public void printerReappearsWhileCanceling() throws Throwable {
     95         // The session once initialized
     96         StubbablePrinterDiscoverySession[] session = new StubbablePrinterDiscoverySession[1];
     97 
     98         // Set up discovery session
     99         final PrinterDiscoverySessionCallbacks callbacks =
    100                 createMockPrinterDiscoverySessionCallbacks(inv -> {
    101                     session[0] = ((PrinterDiscoverySessionCallbacks) inv.getMock()).getSession();
    102 
    103                     addPrinter(session[0], STATUS_IDLE);
    104                     return null;
    105                 }, null, null, null, null, null, invocation -> {
    106                     onPrinterDiscoverySessionDestroyCalled();
    107                     return null;
    108                 });
    109 
    110         // Set up print services
    111         FirstPrintService.setCallbacks(createMockPrintServiceCallbacks((inv) -> callbacks, null,
    112                 null));
    113         SecondPrintService.setCallbacks(createMockPrintServiceCallbacks(null, null, null));
    114 
    115         // The print attributes set in the layout task
    116         PrintAttributes[] printAttributes = new PrintAttributes[1];
    117 
    118         // The callback for the last write task
    119         WriteResultCallback[] writeCallBack = new WriteResultCallback[1];
    120 
    121         // The adapter that will handle the print tasks
    122         final PrintDocumentAdapter adapter = createMockPrintDocumentAdapter(
    123                 invocation -> {
    124                     Object[] args = invocation.getArguments();
    125 
    126                     printAttributes[0] = (PrintAttributes) args[1];
    127                     LayoutResultCallback callback = (LayoutResultCallback) args[3];
    128                     PrintDocumentInfo info = new PrintDocumentInfo.Builder(PRINT_JOB_NAME).build();
    129                     callback.onLayoutFinished(info, true);
    130 
    131                     onLayoutCalled();
    132                     return null;
    133                 }, invocation -> {
    134                     Object[] args = invocation.getArguments();
    135 
    136                     ((CancellationSignal) args[2]).setOnCancelListener(this::onWriteCancelCalled);
    137 
    138                     // Write single page document
    139                     ParcelFileDescriptor fd = (ParcelFileDescriptor) args[1];
    140                     writeBlankPages(printAttributes[0], fd, 0, 1);
    141                     fd.close();
    142 
    143                     writeCallBack[0] = (WriteResultCallback) args[3];
    144 
    145                     onWriteCalled();
    146                     return null;
    147                 }, null);
    148 
    149         // Start printing
    150         print(adapter);
    151 
    152         // Handle write for default printer
    153         waitForWriteAdapterCallback(1);
    154         writeCallBack[0].onWriteFinished(new PageRange[]{new PageRange(0, 1)});
    155 
    156         // Select test printer
    157         selectPrinter(PRINTER_NAME);
    158 
    159         // Selecting the printer changes the document size to A5 which causes a new layout + write
    160         // Do _not_ call back from the write immediately
    161         waitForLayoutAdapterCallbackCount(2);
    162         waitForWriteAdapterCallback(2);
    163 
    164         // While write task is in progress, make the printer unavailable
    165         runOnMainThread(() -> addPrinter(session[0], STATUS_UNAVAILABLE));
    166 
    167         // This should cancel the write task
    168         waitForWriteCancelCallback(1);
    169 
    170         // Make the printer available again, this should add a new task that re-tries the canceled
    171         // task
    172         runOnMainThread(() -> addPrinter(session[0], STATUS_IDLE));
    173 
    174         // Give print preview UI some time to schedule new write task
    175         Thread.sleep(500);
    176 
    177         // Report write from above as canceled
    178         writeCallBack[0].onWriteCancelled();
    179 
    180         // Now the write that was canceled before should have been retried
    181         waitForWriteAdapterCallback(3);
    182 
    183         // Finish test: Fail pending write, exit print activity and wait for print subsystem to shut
    184         // down
    185         writeCallBack[0].onWriteFailed(null);
    186         getUiDevice().pressBack();
    187         waitForPrinterDiscoverySessionDestroyCallbackCalled(1);
    188     }
    189 }
    190