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