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