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 static android.print.test.Utils.assertException; 20 21 import static org.junit.Assert.assertEquals; 22 import static org.junit.Assert.assertTrue; 23 24 import android.os.ParcelFileDescriptor; 25 import android.platform.test.annotations.Presubmit; 26 import android.print.PageRange; 27 import android.print.PrintAttributes; 28 import android.print.PrintAttributes.Margins; 29 import android.print.PrintAttributes.MediaSize; 30 import android.print.PrintAttributes.Resolution; 31 import android.print.PrintDocumentAdapter; 32 import android.print.PrintDocumentAdapter.LayoutResultCallback; 33 import android.print.PrintDocumentAdapter.WriteResultCallback; 34 import android.print.PrintDocumentInfo; 35 import android.print.PrinterCapabilitiesInfo; 36 import android.print.PrinterId; 37 import android.print.PrinterInfo; 38 import android.print.test.BasePrintTest; 39 import android.print.test.services.FirstPrintService; 40 import android.print.test.services.PrintServiceCallbacks; 41 import android.print.test.services.PrinterDiscoverySessionCallbacks; 42 import android.print.test.services.SecondPrintService; 43 import android.print.test.services.StubbablePrinterDiscoverySession; 44 45 import androidx.test.runner.AndroidJUnit4; 46 47 import org.junit.Test; 48 import org.junit.runner.RunWith; 49 50 import java.util.ArrayList; 51 import java.util.function.Consumer; 52 import java.util.function.Function; 53 54 /** 55 * This test verifies changes to the printer capabilities are applied correctly. 56 */ 57 @Presubmit 58 @RunWith(AndroidJUnit4.class) 59 public class PrinterCapabilitiesTest extends BasePrintTest { 60 private static final String PRINTER_NAME = "Test printer"; 61 62 private static final Margins DEFAULT_MARGINS = new Margins(0, 0, 0, 0); 63 private static final PrintAttributes.Resolution RESOLUTION_300 = 64 new PrintAttributes.Resolution("300", "300", 300, 300); 65 private static final PrintAttributes.Resolution RESOLUTION_600 = 66 new PrintAttributes.Resolution("600", "600", 600, 600); 67 private static boolean sDefaultPrinterBeenSet; 68 69 /** 70 * That that you cannot create illegal PrinterCapabilityInfos. 71 * 72 * @throws Exception If anything is unexpected 73 */ 74 @Test illegalPrinterCapabilityInfos()75 public void illegalPrinterCapabilityInfos() throws Exception { 76 final PrinterDiscoverySessionCallbacks firstSessionCallbacks = 77 createMockPrinterDiscoverySessionCallbacks(invocation -> { 78 StubbablePrinterDiscoverySession session = 79 ((PrinterDiscoverySessionCallbacks) 80 invocation.getMock()).getSession(); 81 82 PrinterId printerId = session.getService().generatePrinterId(PRINTER_NAME); 83 84 // printerId need to be set 85 assertException(() -> new PrinterCapabilitiesInfo.Builder(null), 86 IllegalArgumentException.class); 87 88 // All capability fields (beside duplex) need to be initialized: 89 // Test no color 90 assertException(() -> 91 (new PrinterCapabilitiesInfo.Builder(printerId)) 92 .setMinMargins(DEFAULT_MARGINS) 93 .addMediaSize(MediaSize.ISO_A4, true) 94 .addResolution(RESOLUTION_300, true).build(), 95 IllegalStateException.class); 96 // Test bad colors 97 assertException(() -> 98 (new PrinterCapabilitiesInfo.Builder(printerId)) 99 .setColorModes(0xffff, 100 PrintAttributes.COLOR_MODE_MONOCHROME), 101 IllegalArgumentException.class); 102 // Test bad duplex mode 103 assertException(() -> 104 (new PrinterCapabilitiesInfo.Builder(printerId)) 105 .setDuplexModes(0xffff, 106 PrintAttributes.DUPLEX_MODE_NONE), 107 IllegalArgumentException.class); 108 // Test no mediasize 109 assertException(() -> 110 (new PrinterCapabilitiesInfo.Builder(printerId)) 111 .setColorModes(PrintAttributes.COLOR_MODE_COLOR, 112 PrintAttributes.COLOR_MODE_COLOR) 113 .setMinMargins(DEFAULT_MARGINS) 114 .addResolution(RESOLUTION_300, true).build(), 115 IllegalStateException.class); 116 // Test no default mediasize 117 assertException(() -> 118 (new PrinterCapabilitiesInfo.Builder(printerId)) 119 .setColorModes(PrintAttributes.COLOR_MODE_COLOR, 120 PrintAttributes.COLOR_MODE_COLOR) 121 .setMinMargins(DEFAULT_MARGINS) 122 .addMediaSize(MediaSize.ISO_A4, false) 123 .addResolution(RESOLUTION_300, true).build(), 124 IllegalStateException.class); 125 // Test two default mediasizes 126 assertException(() -> 127 (new PrinterCapabilitiesInfo.Builder(printerId)) 128 .addMediaSize(MediaSize.ISO_A4, true) 129 .addMediaSize(MediaSize.ISO_A5, true), 130 IllegalArgumentException.class); 131 // Test no resolution 132 assertException(() -> 133 (new PrinterCapabilitiesInfo.Builder(printerId)) 134 .setColorModes(PrintAttributes.COLOR_MODE_COLOR, 135 PrintAttributes.COLOR_MODE_COLOR) 136 .setMinMargins(DEFAULT_MARGINS) 137 .addMediaSize(MediaSize.ISO_A4, true).build(), 138 IllegalStateException.class); 139 // Test no default resolution 140 assertException(() -> 141 (new PrinterCapabilitiesInfo.Builder(printerId)) 142 .setColorModes(PrintAttributes.COLOR_MODE_COLOR, 143 PrintAttributes.COLOR_MODE_COLOR) 144 .setMinMargins(DEFAULT_MARGINS) 145 .addMediaSize(MediaSize.ISO_A4, true) 146 .addResolution(RESOLUTION_300, false).build(), 147 IllegalStateException.class); 148 // Test two default resolutions 149 assertException(() -> 150 (new PrinterCapabilitiesInfo.Builder(printerId)) 151 .addResolution(RESOLUTION_300, true) 152 .addResolution(RESOLUTION_600, true), 153 IllegalArgumentException.class); 154 155 onPrinterDiscoverySessionCreateCalled(); 156 return null; 157 }, null, null, null, null, null, invocation -> { 158 onPrinterDiscoverySessionDestroyCalled(); 159 return null; 160 }); 161 162 // Create the service callbacks for the first print service. 163 PrintServiceCallbacks firstServiceCallbacks = createMockPrintServiceCallbacks( 164 invocation -> firstSessionCallbacks, null, null); 165 166 // Configure the print services. 167 FirstPrintService.setCallbacks(firstServiceCallbacks); 168 SecondPrintService.setCallbacks(createMockPrintServiceCallbacks(null, null, null)); 169 170 PrintDocumentAdapter adapter = createMockPrintDocumentAdapter(null, null, null); 171 172 // Start printing. 173 print(adapter); 174 175 waitForPrinterDiscoverySessionCreateCallbackCalled(); 176 177 getActivity().finish(); 178 179 waitForPrinterDiscoverySessionDestroyCallbackCalled(1); 180 } 181 182 /** 183 * That that you can use all sane legal PrinterCapabilityInfos. 184 * 185 * @throws Exception If anything is unexpected 186 */ 187 @Test sanePrinterCapabilityInfos()188 public void sanePrinterCapabilityInfos() throws Exception { 189 final PrinterDiscoverySessionCallbacks firstSessionCallbacks = 190 createMockPrinterDiscoverySessionCallbacks(invocation -> { 191 StubbablePrinterDiscoverySession session = 192 ((PrinterDiscoverySessionCallbacks) 193 invocation.getMock()).getSession(); 194 195 MediaSize[] mediaSizes = {MediaSize.ISO_A0, MediaSize.ISO_A0, 196 MediaSize.ISO_A1}; 197 Resolution[] resolutions = {RESOLUTION_300, RESOLUTION_300, 198 RESOLUTION_600}; 199 int[] colorModes = {PrintAttributes.COLOR_MODE_MONOCHROME, 200 PrintAttributes.COLOR_MODE_COLOR}; 201 int[] duplexModes = {PrintAttributes.DUPLEX_MODE_NONE, 202 PrintAttributes.DUPLEX_MODE_LONG_EDGE, 203 PrintAttributes.DUPLEX_MODE_SHORT_EDGE}; 204 205 ArrayList<PrinterInfo> printers = new ArrayList<>(); 206 for (int mediaSizeIndex = 1; mediaSizeIndex < mediaSizes.length; 207 mediaSizeIndex++) { 208 for (int resolutionIndex = 1; resolutionIndex < mediaSizes.length; 209 resolutionIndex++) { 210 for (int colorIndex = 1; colorIndex < colorModes.length; 211 colorIndex++) { 212 for (int duplexIndex = 1; duplexIndex < duplexModes.length; 213 duplexIndex++) { 214 PrinterId printerId = session.getService() 215 .generatePrinterId(Integer.valueOf(printers.size()) 216 .toString()); 217 218 // Setup capabilities 219 PrinterCapabilitiesInfo.Builder b = 220 new PrinterCapabilitiesInfo.Builder(printerId); 221 222 for (int i = 0; i < mediaSizeIndex; i++) { 223 b.addMediaSize(mediaSizes[i], i == mediaSizeIndex - 1); 224 } 225 226 for (int i = 0; i < resolutionIndex; i++) { 227 b.addResolution(resolutions[i], 228 i == resolutionIndex - 1); 229 } 230 231 int allColors = 0; 232 for (int i = 0; i < colorIndex; i++) { 233 allColors |= colorModes[i]; 234 } 235 b.setColorModes(allColors, colorModes[colorIndex - 1]); 236 237 int allDuplexModes = 0; 238 for (int i = 0; i < duplexIndex; i++) { 239 allDuplexModes |= duplexModes[i]; 240 } 241 b.setDuplexModes(allDuplexModes, 242 duplexModes[duplexIndex - 1]); 243 244 b.setMinMargins(DEFAULT_MARGINS); 245 246 // Create printer 247 PrinterInfo printer = (new PrinterInfo.Builder(printerId, 248 Integer.valueOf(printers.size()).toString(), 249 PrinterInfo.STATUS_IDLE)).setCapabilities(b.build()) 250 .build(); 251 252 // Verify capabilities 253 PrinterCapabilitiesInfo cap = printer.getCapabilities(); 254 255 assertEquals(mediaSizeIndex, cap.getMediaSizes().size()); 256 assertEquals(mediaSizes[mediaSizeIndex - 1], 257 cap.getDefaults().getMediaSize()); 258 for (int i = 0; i < mediaSizeIndex; i++) { 259 assertTrue(cap.getMediaSizes().contains(mediaSizes[i])); 260 } 261 262 assertEquals(resolutionIndex, cap.getResolutions().size()); 263 assertEquals(resolutions[resolutionIndex - 1], 264 cap.getDefaults().getResolution()); 265 for (int i = 0; i < resolutionIndex; i++) { 266 assertTrue(cap.getResolutions().contains(resolutions[i])); 267 } 268 269 assertEquals(allColors, cap.getColorModes()); 270 assertEquals(colorModes[colorIndex - 1], 271 cap.getDefaults().getColorMode()); 272 273 assertEquals(allDuplexModes, cap.getDuplexModes()); 274 assertEquals(duplexModes[duplexIndex - 1], 275 cap.getDefaults().getDuplexMode()); 276 277 assertEquals(DEFAULT_MARGINS, cap.getMinMargins()); 278 279 // Add printer 280 printers.add(printer); 281 } 282 } 283 } 284 } 285 286 session.addPrinters(printers); 287 288 onPrinterDiscoverySessionCreateCalled(); 289 return null; 290 }, null, null, null, null, null, invocation -> { 291 onPrinterDiscoverySessionDestroyCalled(); 292 return null; 293 }); 294 295 // Create the service callbacks for the first print service. 296 PrintServiceCallbacks firstServiceCallbacks = createMockPrintServiceCallbacks( 297 invocation -> firstSessionCallbacks, null, null); 298 299 // Configure the print services. 300 FirstPrintService.setCallbacks(firstServiceCallbacks); 301 SecondPrintService.setCallbacks(createMockPrintServiceCallbacks(null, null, null)); 302 303 PrintDocumentAdapter adapter = createMockPrintDocumentAdapter(null, null, null); 304 305 // Start printing. 306 print(adapter); 307 308 waitForPrinterDiscoverySessionCreateCallbackCalled(); 309 310 mPrintHelper.cancelPrinting(); 311 312 waitForPrinterDiscoverySessionDestroyCallbackCalled(1); 313 } 314 315 /** 316 * Base test that performs a print operation with a give PrinterCapabilityInfo and run a test 317 * function before finishing. 318 * 319 * @throws Exception 320 */ testPrinterCapabilityInfo(final Function<PrinterId, PrinterCapabilitiesInfo> capBuilder, Consumer<PrintAttributes> test)321 private void testPrinterCapabilityInfo(final Function<PrinterId, PrinterCapabilitiesInfo> 322 capBuilder, Consumer<PrintAttributes> test) throws Exception { 323 final PrinterDiscoverySessionCallbacks firstSessionCallbacks = 324 createMockPrinterDiscoverySessionCallbacks(invocation -> { 325 StubbablePrinterDiscoverySession session = 326 ((PrinterDiscoverySessionCallbacks) 327 invocation.getMock()).getSession(); 328 329 PrinterId printerId = session.getService() 330 .generatePrinterId(PRINTER_NAME); 331 332 ArrayList<PrinterInfo> printers = new ArrayList<>(); 333 printers.add((new PrinterInfo.Builder(printerId, PRINTER_NAME, 334 PrinterInfo.STATUS_IDLE)) 335 .setCapabilities(capBuilder.apply(printerId)).build()); 336 337 session.addPrinters(printers); 338 339 onPrinterDiscoverySessionCreateCalled(); 340 return null; 341 }, null, null, null, null, null, invocation -> { 342 onPrinterDiscoverySessionDestroyCalled(); 343 return null; 344 }); 345 346 // Create the service callbacks for the first print service. 347 PrintServiceCallbacks firstServiceCallbacks = createMockPrintServiceCallbacks( 348 invocation -> firstSessionCallbacks, null, null); 349 350 // Configure the print services. 351 FirstPrintService.setCallbacks(firstServiceCallbacks); 352 SecondPrintService.setCallbacks(createMockPrintServiceCallbacks(null, null, null)); 353 354 final PrintAttributes[] layoutAttributes = new PrintAttributes[1]; 355 356 PrintDocumentAdapter adapter = createMockPrintDocumentAdapter( 357 invocation -> { 358 LayoutResultCallback callback = (LayoutResultCallback) invocation 359 .getArguments()[3]; 360 PrintDocumentInfo info = new PrintDocumentInfo.Builder(PRINT_JOB_NAME) 361 .setPageCount(1) 362 .build(); 363 layoutAttributes[0] = (PrintAttributes) invocation.getArguments()[1]; 364 365 callback.onLayoutFinished(info, true); 366 return null; 367 }, 368 invocation -> { 369 Object[] args = invocation.getArguments(); 370 PageRange[] pages = (PageRange[]) args[0]; 371 ParcelFileDescriptor fd = (ParcelFileDescriptor) args[1]; 372 WriteResultCallback callback = (WriteResultCallback) args[3]; 373 374 writeBlankPages(layoutAttributes[0], fd, pages[0].getStart(), 375 pages[0].getEnd()); 376 fd.close(); 377 378 callback.onWriteFinished(pages); 379 return null; 380 }, null); 381 382 // Start printing. 383 print(adapter); 384 385 // make sure that options does not crash 386 openPrintOptions(); 387 388 if (!sDefaultPrinterBeenSet) { 389 // Select printer under test 390 selectPrinter(PRINTER_NAME); 391 } 392 393 mPrintHelper.submitPrintJob(); 394 395 if (!sDefaultPrinterBeenSet) { 396 answerPrintServicesWarning(true); 397 sDefaultPrinterBeenSet = true; 398 } 399 400 test.accept(layoutAttributes[0]); 401 402 waitForPrinterDiscoverySessionDestroyCallbackCalled(1); 403 } 404 405 /** 406 * That that you use a default color that is not in the allowed colors. This is allowed because 407 * of historical reasons. 408 * 409 * @throws Exception If anything is unexpected 410 */ 411 @Test invalidDefaultColor()412 public void invalidDefaultColor() throws Exception { 413 testPrinterCapabilityInfo( 414 (printerId) -> (new PrinterCapabilitiesInfo.Builder(printerId)) 415 .addMediaSize(MediaSize.ISO_A4, true) 416 .addResolution(RESOLUTION_300, true) 417 .setColorModes(PrintAttributes.COLOR_MODE_MONOCHROME, 418 PrintAttributes.COLOR_MODE_COLOR).build(), 419 (layoutAttributes) -> assertEquals(layoutAttributes.getColorMode(), 420 PrintAttributes.COLOR_MODE_MONOCHROME)); 421 } 422 423 /** 424 * That that you use a default duplex mode that is not in the allowed duplex modes. This is 425 * allowed because of historical reasons. 426 * 427 * @throws Exception If anything is unexpected 428 */ 429 @Test invalidDefaultDuplexMode()430 public void invalidDefaultDuplexMode() throws Exception { 431 testPrinterCapabilityInfo( 432 (printerId) -> (new PrinterCapabilitiesInfo.Builder(printerId)) 433 .addMediaSize(MediaSize.ISO_A4, true) 434 .addResolution(RESOLUTION_300, true) 435 .setColorModes(PrintAttributes.COLOR_MODE_MONOCHROME, 436 PrintAttributes.COLOR_MODE_MONOCHROME) 437 .setDuplexModes(PrintAttributes.DUPLEX_MODE_LONG_EDGE 438 | PrintAttributes.DUPLEX_MODE_NONE, 439 PrintAttributes.DUPLEX_MODE_SHORT_EDGE).build(), 440 (layoutAttributes) -> assertTrue(layoutAttributes.getDuplexMode() == 441 PrintAttributes.DUPLEX_MODE_LONG_EDGE || layoutAttributes.getDuplexMode() == 442 PrintAttributes.DUPLEX_MODE_NONE)); 443 } 444 } 445