1 /*
2  * Copyright (C) 2016 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 android.app.Activity;
20 import android.app.PendingIntent;
21 import android.content.Intent;
22 import android.print.PrintAttributes;
23 import android.print.PrintAttributes.Margins;
24 import android.print.PrintAttributes.MediaSize;
25 import android.print.PrintAttributes.Resolution;
26 import android.print.PrintDocumentAdapter;
27 import android.print.PrinterCapabilitiesInfo;
28 import android.print.PrinterId;
29 import android.print.PrinterInfo;
30 import android.print.test.BasePrintTest;
31 import android.print.test.services.FirstPrintService;
32 import android.print.test.services.PrintServiceCallbacks;
33 import android.print.test.services.PrinterDiscoverySessionCallbacks;
34 import android.print.test.services.SecondPrintService;
35 import android.print.test.services.StubbablePrinterDiscoverySession;
36 import android.support.test.uiautomator.UiObject;
37 import android.support.test.uiautomator.UiSelector;
38 import android.text.TextUtils;
39 
40 import androidx.test.runner.AndroidJUnit4;
41 
42 import org.junit.Test;
43 import org.junit.runner.RunWith;
44 
45 import java.util.ArrayList;
46 import java.util.List;
47 
48 /**
49  * Tests all allowed types of printerInfo
50  */
51 @RunWith(AndroidJUnit4.class)
52 public class PrinterInfoTest extends BasePrintTest {
53     private static final String NAMED_PRINTERS_NAME_PREFIX = "Printer ";
54 
55     /** The printer discovery session used in this test */
56     private static StubbablePrinterDiscoverySession sDiscoverySession;
57 
isValidStatus(int status)58     private boolean isValidStatus(int status) {
59         return status == PrinterInfo.STATUS_IDLE
60                 || status == PrinterInfo.STATUS_BUSY
61                 || status == PrinterInfo.STATUS_UNAVAILABLE;
62     }
63 
64     /**
65      * Create a mock {@link PrinterDiscoverySessionCallbacks} that discovers a printers with all
66      * possible combinations of interesting printers.
67      *
68      * @return The mock session callbacks
69      */
createFirstMockPrinterDiscoverySessionCallbacks()70     private PrinterDiscoverySessionCallbacks createFirstMockPrinterDiscoverySessionCallbacks() {
71         return createMockPrinterDiscoverySessionCallbacks(invocation -> {
72             // Get the session.
73             sDiscoverySession = ((PrinterDiscoverySessionCallbacks) invocation.getMock())
74                     .getSession();
75 
76             if (sDiscoverySession.getPrinters().isEmpty()) {
77                 final int INVALID_RES_ID = 0xffffffff;
78 
79                 final PrinterInfo.Builder badPrinter = new PrinterInfo.Builder(
80                         sDiscoverySession.getService().generatePrinterId("bad printer"),
81                         "badPrinter", PrinterInfo.STATUS_UNAVAILABLE);
82 
83                 String[] localPrinterIds = {
84                         "Printer", null
85                 };
86 
87                 String[] names = {
88                         NAMED_PRINTERS_NAME_PREFIX, "", null
89                 };
90                 int[] statusList = {
91                         PrinterInfo.STATUS_IDLE, PrinterInfo.STATUS_BUSY,
92                         PrinterInfo.STATUS_UNAVAILABLE, 0, 42
93                 };
94                 int[] iconResourceIds = {
95                         R.drawable.red_printer, 0, INVALID_RES_ID, -1
96                 };
97 
98                 boolean[] hasCustomPrinterIcons = {
99                         true, false
100                 };
101 
102                 String[] descriptions = {
103                         "Description", "", null
104                 };
105 
106                 PendingIntent[] infoIntents = {
107                         PendingIntent.getActivity(getActivity(), 0,
108                                 new Intent(getActivity(), Activity.class),
109                                 PendingIntent.FLAG_IMMUTABLE),
110                         null
111                 };
112 
113                 PrinterCapabilitiesInfo[] capabilityList = {
114                         // The printerId not used in PrinterCapabilitiesInfo
115                         new PrinterCapabilitiesInfo.Builder(sDiscoverySession.getService()
116                                 .generatePrinterId("unused"))
117                                         .setMinMargins(new Margins(200, 200, 200, 200))
118                                         .addMediaSize(MediaSize.ISO_A4, true)
119                                         .addResolution(
120                                                 new Resolution("300x300", "300x300", 300, 300),
121                                                 true)
122                                         .setColorModes(PrintAttributes.COLOR_MODE_COLOR,
123                                                 PrintAttributes.COLOR_MODE_COLOR)
124                                         .build(),
125                         null
126                 };
127 
128                 List<PrinterInfo> printers = new ArrayList<>();
129                 for (String localPrinterId : localPrinterIds) {
130                     for (String name : names) {
131                         for (int status : statusList) {
132                             for (int iconResourceId : iconResourceIds) {
133                                 for (boolean hasCustomPrinterIcon : hasCustomPrinterIcons) {
134                                     for (String description : descriptions) {
135                                         for (PendingIntent infoIntent : infoIntents) {
136                                             for (PrinterCapabilitiesInfo capabilities
137                                                     : capabilityList) {
138                                                 // printerId
139                                                 RuntimeException e = null;
140                                                 PrinterId printerId = null;
141                                                 try {
142                                                     if (localPrinterId == null) {
143                                                         printerId = sDiscoverySession
144                                                                 .getService()
145                                                                 .generatePrinterId(
146                                                                         localPrinterId);
147                                                     } else {
148                                                         printerId = sDiscoverySession
149                                                                 .getService()
150                                                                 .generatePrinterId(
151                                                                         localPrinterId
152                                                                                 + printers
153                                                                                         .size());
154                                                     }
155                                                 } catch (RuntimeException ex) {
156                                                     e = ex;
157                                                 }
158 
159                                                 // Expect exception if localId is null
160                                                 if (localPrinterId == null) {
161                                                     if (e == null) {
162                                                         throw new IllegalStateException();
163                                                     }
164                                                 } else if (e != null) {
165                                                     throw e;
166                                                 }
167 
168                                                 // Constructor
169                                                 PrinterInfo.Builder b = null;
170                                                 e = null;
171                                                 try {
172                                                     b = new PrinterInfo.Builder(
173                                                             printerId, name, status);
174                                                 } catch (RuntimeException ex) {
175                                                     e = ex;
176                                                 }
177 
178                                                 // Expect exception if any of the parameters was
179                                                 // bad
180                                                 if (printerId == null
181                                                         || TextUtils.isEmpty(name)
182                                                         || !isValidStatus(status)) {
183                                                     if (e == null) {
184                                                         throw new IllegalStateException();
185                                                     } else {
186                                                         b = badPrinter;
187                                                     }
188                                                 } else if (e != null) {
189                                                     throw e;
190                                                 }
191 
192                                                 // IconResourceId
193                                                 e = null;
194                                                 try {
195                                                     b.setIconResourceId(iconResourceId);
196                                                 } catch (RuntimeException ex) {
197                                                     e = ex;
198                                                 }
199 
200                                                 // Expect exception if iconResourceId was bad
201                                                 // We do allow invalid Ids as the printerInfo
202                                                 // might be created after the package of the
203                                                 // printer is already gone if the printer is a
204                                                 // historical printer.
205                                                 if (iconResourceId < 0) {
206                                                     if (e == null) {
207                                                         throw new IllegalStateException();
208                                                     } else {
209                                                         b = badPrinter;
210                                                     }
211                                                 } else if (e != null) {
212                                                     throw e;
213                                                 }
214 
215                                                 // Status
216                                                 e = null;
217                                                 try {
218                                                     b.setStatus(status);
219                                                 } catch (RuntimeException ex) {
220                                                     e = ex;
221                                                 }
222 
223                                                 // Expect exception is status is not valid
224                                                 if (!isValidStatus(status)) {
225                                                     if (e == null) {
226                                                         throw new IllegalStateException();
227                                                     } else {
228                                                         b = badPrinter;
229                                                     }
230                                                 } else if (e != null) {
231                                                     throw e;
232                                                 }
233 
234                                                 // Name
235                                                 e = null;
236                                                 try {
237                                                     b.setName(name);
238                                                 } catch (RuntimeException ex) {
239                                                     e = ex;
240                                                 }
241 
242                                                 // Expect exception if name is empty
243                                                 if (TextUtils.isEmpty(name)) {
244                                                     if (e == null) {
245                                                         throw new IllegalStateException();
246                                                     } else {
247                                                         b = badPrinter;
248                                                     }
249                                                 } else if (e != null) {
250                                                     throw e;
251                                                 }
252 
253                                                 // hasCustomPrinterIcon
254                                                 b.setHasCustomPrinterIcon(hasCustomPrinterIcon);
255 
256                                                 // Description
257                                                 b.setDescription(description);
258 
259                                                 // InfoIntent
260                                                 b.setInfoIntent(infoIntent);
261 
262                                                 // Capabilities
263                                                 b.setCapabilities(capabilities);
264 
265                                                 PrinterInfo printer = b.build();
266 
267                                                 // Don't create bad printers
268                                                 if (b == badPrinter) {
269                                                     continue;
270                                                 }
271 
272                                                 // Verify get* methods
273                                                 if (printer.getId() != printerId
274                                                         || printer.getName() != name
275                                                         || printer.getStatus() != status
276                                                         || printer
277                                                                 .getDescription() != description
278                                                         || printer.getCapabilities()
279                                                                 != capabilities) {
280                                                     throw new IllegalStateException();
281                                                 }
282 
283                                                 printers.add(printer);
284                                             }
285                                         }
286                                     }
287                                 }
288                             }
289                         }
290                     }
291                 }
292 
293                 sDiscoverySession.addPrinters(printers);
294             }
295             return null;
296         }, null, null, invocation -> null, invocation -> null, null, invocation -> {
297             // Take a note onDestroy was called.
298             onPrinterDiscoverySessionDestroyCalled();
299             return null;
300         });
301     }
302 
303     /**
304      * Create mock service callback for a session.
305      *
306      * @param sessionCallbacks The callbacks of the session
307      */
createFirstMockPrinterServiceCallbacks( final PrinterDiscoverySessionCallbacks sessionCallbacks)308     private PrintServiceCallbacks createFirstMockPrinterServiceCallbacks(
309             final PrinterDiscoverySessionCallbacks sessionCallbacks) {
310         return createMockPrintServiceCallbacks(
311                 invocation -> sessionCallbacks,
312                 null, null);
313     }
314 
315     /**
316      * Test that all printInfos possible can be used and that invalid printInfos throw exceptions.
317      *
318      * @throws Exception If anything is unexpected.
319      */
320     @Test
printerInfos()321     public void printerInfos() throws Exception {
322         // Create the session of the printers that we will be checking.
323         PrinterDiscoverySessionCallbacks sessionCallbacks
324                 = createFirstMockPrinterDiscoverySessionCallbacks();
325 
326         // Create the service callbacks for the first print service.
327         PrintServiceCallbacks serviceCallbacks = createFirstMockPrinterServiceCallbacks(
328                 sessionCallbacks);
329 
330         // Configure the print services.
331         FirstPrintService.setCallbacks(serviceCallbacks);
332 
333         // We don't use the second service, but we have to still configure it
334         SecondPrintService.setCallbacks(createMockPrintServiceCallbacks(null, null, null));
335 
336         // Create a print adapter that respects the print contract.
337         PrintDocumentAdapter adapter = createDefaultPrintDocumentAdapter(1);
338 
339         // Start printing.
340         print(adapter);
341 
342         // Wait for write of the first page.
343         waitForWriteAdapterCallback(1);
344 
345         // Open destination spinner
346         UiObject destinationSpinner = getUiDevice().findObject(new UiSelector().resourceId(
347                 "com.android.printspooler:id/destination_spinner"));
348         destinationSpinner.click();
349 
350         // Wait until spinner is opened
351         getUiDevice().waitForIdle();
352 
353         // Exit print spooler
354         getUiDevice().pressBack();
355         getUiDevice().pressBack();
356         getUiDevice().pressBack();
357     }
358 }
359