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