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