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