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