blob: 4a9e7af40f491cbd691a831653bcf65b8a115029 [file] [log] [blame]
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.print.cts;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.never;
import android.os.ParcelFileDescriptor;
import android.print.PageRange;
import android.print.PrintAttributes;
import android.print.PrintAttributes.Margins;
import android.print.PrintAttributes.MediaSize;
import android.print.PrintAttributes.Resolution;
import android.print.PrintDocumentAdapter;
import android.print.PrintDocumentAdapter.LayoutResultCallback;
import android.print.PrintDocumentAdapter.WriteResultCallback;
import android.print.PrintDocumentInfo;
import android.print.PrintJobInfo;
import android.print.PrinterCapabilitiesInfo;
import android.print.PrinterId;
import android.print.PrinterInfo;
import android.print.test.BasePrintTest;
import android.print.test.services.FirstPrintService;
import android.print.test.services.PrintServiceCallbacks;
import android.print.test.services.PrinterDiscoverySessionCallbacks;
import android.print.test.services.SecondPrintService;
import android.print.test.services.StubbablePrinterDiscoverySession;
import android.printservice.PrintJob;
import android.printservice.PrintService;
import androidx.test.runner.AndroidJUnit4;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InOrder;
import java.util.ArrayList;
import java.util.List;
/**
* This test verifies that the system correctly adjust the
* page ranges to be printed depending whether the app gave
* the requested pages, more pages, etc.
*/
@RunWith(AndroidJUnit4.class)
public class PageRangeAdjustmentTest extends BasePrintTest {
private static final int MAX_PREVIEW_PAGES_BATCH = 50;
private static final int PAGE_COUNT = 60;
private static final String FIRST_PRINTER = "First printer";
private static boolean sIsDefaultPrinterSet;
@Before
public void setDefaultPrinter() throws Exception {
if (!sIsDefaultPrinterSet) {
// Create a callback for the target print service.
PrintServiceCallbacks firstServiceCallbacks = createMockPrintServiceCallbacks(
invocation -> createMockFirstPrinterDiscoverySessionCallbacks(),
invocation -> {
PrintJob printJob = (PrintJob) invocation.getArguments()[0];
printJob.complete();
return null;
}, null);
// Configure the print services.
FirstPrintService.setCallbacks(firstServiceCallbacks);
SecondPrintService.setCallbacks(createSecondMockPrintServiceCallbacks());
// Create a mock print adapter.
final PrintDocumentAdapter adapter = createDefaultPrintDocumentAdapter(PAGE_COUNT);
makeDefaultPrinter(adapter, FIRST_PRINTER);
resetCounters();
sIsDefaultPrinterSet = true;
}
}
@Test
public void allPagesWantedAndAllPagesWritten() throws Exception {
// Create a callback for the target print service.
PrintServiceCallbacks firstServiceCallbacks = createMockPrintServiceCallbacks(
invocation -> createMockFirstPrinterDiscoverySessionCallbacks(),
invocation -> {
PrintJob printJob = (PrintJob) invocation.getArguments()[0];
PageRange[] pages = printJob.getInfo().getPages();
assertTrue(pages.length == 1 && PageRange.ALL_PAGES.equals(pages[0]));
printJob.complete();
onPrintJobQueuedCalled();
return null;
}, null);
// Configure the print services.
FirstPrintService.setCallbacks(firstServiceCallbacks);
SecondPrintService.setCallbacks(createSecondMockPrintServiceCallbacks());
// Create a mock print adapter.
final PrintDocumentAdapter adapter = createDefaultPrintDocumentAdapter(PAGE_COUNT);
// Start printing.
print(adapter);
// Wait for write.
waitForWriteAdapterCallback(1);
// Click the print button.
clickPrintButton();
// Wait for finish.
waitForAdapterFinishCallbackCalled();
// Wait for the print job.
waitForServiceOnPrintJobQueuedCallbackCalled(1);
// Verify the expected calls.
InOrder inOrder = inOrder(firstServiceCallbacks);
// We create a new session first.
inOrder.verify(firstServiceCallbacks)
.onCreatePrinterDiscoverySessionCallbacks();
// Next we wait for a call with the print job.
inOrder.verify(firstServiceCallbacks).onPrintJobQueued(
any(PrintJob.class));
}
@Test
public void somePagesWantedAndAllPagesWritten() throws Exception {
// Create a callback for the target print service.
PrintServiceCallbacks firstServiceCallbacks = createMockPrintServiceCallbacks(
invocation -> createMockFirstPrinterDiscoverySessionCallbacks(),
invocation -> {
PrintJob printJob = (PrintJob) invocation.getArguments()[0];
PageRange[] pages = printJob.getInfo().getPages();
// We asked for some pages, the app wrote more, but the system
// pruned extra pages, hence we expect to print all pages.
assertTrue(pages.length == 1 && PageRange.ALL_PAGES.equals(pages[0]));
printJob.complete();
onPrintJobQueuedCalled();
return null;
}, null);
final PrintAttributes[] printAttributes = new PrintAttributes[1];
// Configure the print services.
FirstPrintService.setCallbacks(firstServiceCallbacks);
SecondPrintService.setCallbacks(createSecondMockPrintServiceCallbacks());
// Create a mock print adapter.
final PrintDocumentAdapter adapter = createMockPrintDocumentAdapter(
invocation -> {
printAttributes[0] = (PrintAttributes) invocation.getArguments()[1];
LayoutResultCallback callback = (LayoutResultCallback) invocation.getArguments()[3];
PrintDocumentInfo info = new PrintDocumentInfo.Builder(PRINT_JOB_NAME)
.setContentType(PrintDocumentInfo.CONTENT_TYPE_DOCUMENT)
.setPageCount(PAGE_COUNT)
.build();
callback.onLayoutFinished(info, false);
// Mark layout was called.
onLayoutCalled();
return null;
}, invocation -> {
Object[] args = invocation.getArguments();
PageRange[] pages = (PageRange[]) args[0];
assertTrue(pages[pages.length - 1].getEnd() < PAGE_COUNT);
ParcelFileDescriptor fd = (ParcelFileDescriptor) args[1];
WriteResultCallback callback = (WriteResultCallback) args[3];
writeBlankPages(printAttributes[0], fd, 0, PAGE_COUNT - 1);
fd.close();
callback.onWriteFinished(new PageRange[] {PageRange.ALL_PAGES});
// Mark write was called.
onWriteCalled();
return null;
}, invocation -> {
// Mark finish was called.
onFinishCalled();
return null;
});
// Start printing.
print(adapter);
// Wait for write.
waitForWriteAdapterCallback(1);
// Open the print options.
openPrintOptions();
// Select only the second page.
selectPages("2", PAGE_COUNT);
// Click the print button.
clickPrintButton();
// Wait for finish.
waitForAdapterFinishCallbackCalled();
// Wait for the print job.
waitForServiceOnPrintJobQueuedCallbackCalled(1);
// Verify the expected calls.
InOrder inOrder = inOrder(firstServiceCallbacks);
// We create a new session first.
inOrder.verify(firstServiceCallbacks)
.onCreatePrinterDiscoverySessionCallbacks();
// Next we wait for a call with the print job.
inOrder.verify(firstServiceCallbacks).onPrintJobQueued(
any(PrintJob.class));
}
@Test
public void somePagesWantedAndSomeMorePagesWritten() throws Exception {
final int REQUESTED_PAGE = 55;
// Create a callback for the target print service.
PrintServiceCallbacks firstServiceCallbacks = createMockPrintServiceCallbacks(
invocation -> createMockFirstPrinterDiscoverySessionCallbacks(),
invocation -> {
PrintJob printJob = (PrintJob) invocation.getArguments()[0];
PrintJobInfo printJobInfo = printJob.getInfo();
PageRange[] pages = printJobInfo.getPages();
// We asked only for page 55 (index 54) but got 55 and 56 (indices
// 54, 55), but the system pruned the extra page, hence we expect
// to print all pages.
assertTrue(pages.length == 1 && PageRange.ALL_PAGES.equals(pages[0]));
assertSame(printJob.getDocument().getInfo().getPageCount(), 1);
printJob.complete();
onPrintJobQueuedCalled();
return null;
}, null);
final PrintAttributes[] printAttributes = new PrintAttributes[1];
// Configure the print services.
FirstPrintService.setCallbacks(firstServiceCallbacks);
SecondPrintService.setCallbacks(createSecondMockPrintServiceCallbacks());
// Create a mock print adapter.
final PrintDocumentAdapter adapter = createMockPrintDocumentAdapter(
invocation -> {
printAttributes[0] = (PrintAttributes) invocation.getArguments()[1];
LayoutResultCallback callback = (LayoutResultCallback) invocation.getArguments()[3];
PrintDocumentInfo info = new PrintDocumentInfo.Builder(PRINT_JOB_NAME)
.setContentType(PrintDocumentInfo.CONTENT_TYPE_DOCUMENT)
.setPageCount(PAGE_COUNT)
.build();
callback.onLayoutFinished(info, false);
// Mark layout was called.
onLayoutCalled();
return null;
}, invocation -> {
Object[] args = invocation.getArguments();
PageRange[] pages = (PageRange[]) args[0];
ParcelFileDescriptor fd = (ParcelFileDescriptor) args[1];
WriteResultCallback callback = (WriteResultCallback) args[3];
// We expect a single range as it is either the pages for
// preview or the page we selected in the UI.
assertSame(pages.length, 1);
// The first write request for some pages to preview.
if (getWriteCallCount() == 0) {
// Write all requested pages.
writeBlankPages(printAttributes[0], fd, pages[0].getStart(), pages[0].getEnd());
callback.onWriteFinished(pages);
} else {
// Otherwise write a page more that the one we selected.
writeBlankPages(printAttributes[0], fd, REQUESTED_PAGE - 1, REQUESTED_PAGE);
callback.onWriteFinished(new PageRange[] {new PageRange(REQUESTED_PAGE - 1,
REQUESTED_PAGE)});
}
fd.close();
// Mark write was called.
onWriteCalled();
return null;
}, invocation -> {
// Mark finish was called.
onFinishCalled();
return null;
});
// Start printing.
print(adapter);
// Wait for write.
waitForWriteAdapterCallback(1);
// Open the print options.
openPrintOptions();
// Select a page not written for preview.
selectPages(Integer.valueOf(REQUESTED_PAGE).toString(), PAGE_COUNT);
// Click the print button.
clickPrintButton();
// Wait for finish.
waitForAdapterFinishCallbackCalled();
// Wait for the print job.
waitForServiceOnPrintJobQueuedCallbackCalled(1);
// Verify the expected calls.
InOrder inOrder = inOrder(firstServiceCallbacks);
// We create a new session first.
inOrder.verify(firstServiceCallbacks)
.onCreatePrinterDiscoverySessionCallbacks();
// Next we wait for a call with the print job.
inOrder.verify(firstServiceCallbacks).onPrintJobQueued(
any(PrintJob.class));
}
@Test
public void somePagesWantedAndNotWritten() throws Exception {
// Create a callback for the target print service.
PrintServiceCallbacks firstServiceCallbacks = createMockPrintServiceCallbacks(
invocation -> createMockFirstPrinterDiscoverySessionCallbacks(),
null, null);
final PrintAttributes[] printAttributes = new PrintAttributes[1];
// Configure the print services.
FirstPrintService.setCallbacks(firstServiceCallbacks);
SecondPrintService.setCallbacks(createSecondMockPrintServiceCallbacks());
// Create a mock print adapter.
final PrintDocumentAdapter adapter = createMockPrintDocumentAdapter(
invocation -> {
printAttributes[0] = (PrintAttributes) invocation.getArguments()[1];
LayoutResultCallback callback = (LayoutResultCallback) invocation.getArguments()[3];
PrintDocumentInfo info = new PrintDocumentInfo.Builder(PRINT_JOB_NAME)
.setContentType(PrintDocumentInfo.CONTENT_TYPE_DOCUMENT)
.setPageCount(PAGE_COUNT)
.build();
callback.onLayoutFinished(info, false);
// Mark layout was called.
onLayoutCalled();
return null;
}, invocation -> {
Object[] args = invocation.getArguments();
PageRange[] pages = (PageRange[]) args[0];
ParcelFileDescriptor fd = (ParcelFileDescriptor) args[1];
WriteResultCallback callback = (WriteResultCallback) args[3];
assertSame(pages.length, 1);
// We should be asked for some pages...
assertSame(pages[0].getStart(), 0);
assertTrue(pages[0].getEnd() == MAX_PREVIEW_PAGES_BATCH - 1);
writeBlankPages(printAttributes[0], fd, pages[0].getStart(), pages[0].getEnd());
fd.close();
callback.onWriteFinished(new PageRange[]{new PageRange(1, 1)});
// Mark write was called.
onWriteCalled();
return null;
}, invocation -> {
// Mark finish was called.
onFinishCalled();
return null;
});
// Start printing.
print(adapter);
// Wait for write.
waitForWriteAdapterCallback(1);
// Cancel printing.
getUiDevice().pressBack(); // wakes up the device.
getUiDevice().pressBack();
// Wait for finish.
waitForAdapterFinishCallbackCalled();
// Verify the expected calls.
InOrder inOrder = inOrder(firstServiceCallbacks);
// We create a new session first.
inOrder.verify(firstServiceCallbacks)
.onCreatePrinterDiscoverySessionCallbacks();
// We should not receive a print job callback.
inOrder.verify(firstServiceCallbacks, never()).onPrintJobQueued(
any(PrintJob.class));
}
@Test
public void wantedPagesAlreadyWrittenForPreview() throws Exception {
// Create a callback for the target print service.
PrintServiceCallbacks firstServiceCallbacks = createMockPrintServiceCallbacks(
invocation -> createMockFirstPrinterDiscoverySessionCallbacks(), invocation -> {
PrintJob printJob = (PrintJob) invocation.getArguments()[0];
PrintJobInfo printJobInfo = printJob.getInfo();
PageRange[] pages = printJobInfo.getPages();
// We asked only for page 3 (index 2) but got this page when
// we were getting the pages for preview (indices 0 - 49),
// but the framework pruned extra pages, hence we should be asked
// to print all pages from a single page document.
assertTrue(pages.length == 1 && PageRange.ALL_PAGES.equals(pages[0]));
assertSame(printJob.getDocument().getInfo().getPageCount(), 1);
printJob.complete();
onPrintJobQueuedCalled();
return null;
}, null);
final PrintAttributes[] printAttributes = new PrintAttributes[1];
// Configure the print services.
FirstPrintService.setCallbacks(firstServiceCallbacks);
SecondPrintService.setCallbacks(createSecondMockPrintServiceCallbacks());
// Create a mock print adapter.
final PrintDocumentAdapter adapter = createMockPrintDocumentAdapter(
invocation -> {
printAttributes[0] = (PrintAttributes) invocation.getArguments()[1];
LayoutResultCallback callback = (LayoutResultCallback) invocation.getArguments()[3];
PrintDocumentInfo info = new PrintDocumentInfo.Builder(PRINT_JOB_NAME)
.setContentType(PrintDocumentInfo.CONTENT_TYPE_DOCUMENT)
.setPageCount(PAGE_COUNT)
.build();
callback.onLayoutFinished(info, false);
// Mark layout was called.
onLayoutCalled();
return null;
}, invocation -> {
Object[] args = invocation.getArguments();
PageRange[] pages = (PageRange[]) args[0];
ParcelFileDescriptor fd = (ParcelFileDescriptor) args[1];
WriteResultCallback callback = (WriteResultCallback) args[3];
// We expect a single range as it is either the pages for
// preview or the page we selected in the UI.
assertSame(pages.length, 1);
// Write all requested pages.
writeBlankPages(printAttributes[0], fd, pages[0].getStart(), pages[0].getEnd());
callback.onWriteFinished(pages);
fd.close();
// Mark write was called.
onWriteCalled();
return null;
}, invocation -> {
// Mark finish was called.
onFinishCalled();
return null;
});
// Start printing.
print(adapter);
// Wait for write.
waitForWriteAdapterCallback(1);
// Open the print options.
openPrintOptions();
// Select a page not written for preview.
selectPages("3", PAGE_COUNT);
// Click the print button.
clickPrintButton();
// Wait for finish.
waitForAdapterFinishCallbackCalled();
// Wait for the print job.
waitForServiceOnPrintJobQueuedCallbackCalled(1);
// Verify the expected calls.
InOrder inOrder = inOrder(firstServiceCallbacks);
// We create a new session first.
inOrder.verify(firstServiceCallbacks)
.onCreatePrinterDiscoverySessionCallbacks();
// Next we wait for a call with the print job.
inOrder.verify(firstServiceCallbacks).onPrintJobQueued(
any(PrintJob.class));
}
private PrinterDiscoverySessionCallbacks createMockFirstPrinterDiscoverySessionCallbacks() {
return createMockPrinterDiscoverySessionCallbacks(invocation -> {
PrinterDiscoverySessionCallbacks mock = (PrinterDiscoverySessionCallbacks)
invocation.getMock();
StubbablePrinterDiscoverySession session = mock.getSession();
PrintService service = session.getService();
if (session.getPrinters().isEmpty()) {
List<PrinterInfo> printers = new ArrayList<>();
// Add one printer.
PrinterId firstPrinterId = service.generatePrinterId("first_printer");
PrinterCapabilitiesInfo firstCapabilities =
new PrinterCapabilitiesInfo.Builder(firstPrinterId)
.setMinMargins(new Margins(200, 200, 200, 200))
.addMediaSize(MediaSize.ISO_A4, true)
.addMediaSize(MediaSize.ISO_A5, false)
.addResolution(new Resolution("300x300", "300x300", 300, 300), true)
.setColorModes(PrintAttributes.COLOR_MODE_COLOR,
PrintAttributes.COLOR_MODE_COLOR)
.build();
PrinterInfo firstPrinter = new PrinterInfo.Builder(firstPrinterId,
FIRST_PRINTER, PrinterInfo.STATUS_IDLE)
.setCapabilities(firstCapabilities)
.build();
printers.add(firstPrinter);
session.addPrinters(printers);
}
return null;
}, null, null, null, null, null, invocation -> {
onPrinterDiscoverySessionDestroyCalled();
return null;
});
}
private PrintServiceCallbacks createSecondMockPrintServiceCallbacks() {
return createMockPrintServiceCallbacks(null, null, null);
}
}