blob: e3497d03bc120aa35b9f776979039af28d98fd27 [file] [log] [blame]
/*
* Copyright (C) 2017 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 android.graphics.pdf.PdfRenderer.Page.RENDER_MODE_FOR_PRINT;
import static android.os.ParcelFileDescriptor.MODE_READ_ONLY;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.pdf.PdfDocument;
import android.graphics.pdf.PdfRenderer;
import android.os.ParcelFileDescriptor;
import android.print.PageRange;
import android.print.PrintAttributes;
import android.print.PrintDocumentAdapter;
import android.print.PrintDocumentInfo;
import android.print.PrinterCapabilitiesInfo;
import android.print.PrinterId;
import android.print.PrinterInfo;
import android.print.pdf.PrintedPdfDocument;
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 android.util.Log;
import androidx.annotation.NonNull;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Objects;
/**
* Adjust the pages to print and verify that the right pages were printed
*/
@RunWith(Parameterized.class)
public class PageRangeAdjustAndVerify extends BasePrintTest {
private static final String LOG_TAG = PageRangeAdjustAndVerify.class.getSimpleName();
private static final String FIRST_PRINTER = "First printer";
private static boolean sIsDefaultPrinterSet;
private final int[] mSelectedPages;
private final int mNumPages;
private final boolean mReportNumPagesFromLayout;
private final boolean mWriteAllPages;
@Before
public void setDefaultPrinter() throws Throwable {
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(1);
makeDefaultPrinter(adapter, FIRST_PRINTER);
resetCounters();
sIsDefaultPrinterSet = true;
}
}
@Parameterized.Parameters
public static Collection<Object[]> getParameters() {
ArrayList<Object[]> parameters = new ArrayList<>();
for (int reportNumPagesFromLayout = 0; reportNumPagesFromLayout < 2;
reportNumPagesFromLayout++) {
for (int writeAllPages = 0; writeAllPages < 2; writeAllPages++) {
for (int numPages = 5; numPages <= 100; numPages += 95) {
for (int firstGap = 0; firstGap < 3; firstGap++) {
for (int secondGap = 0; secondGap < 2; secondGap++) {
for (int thirdGap = 0; thirdGap < 2; thirdGap++) {
int[] selectedPages = new int[3];
if (firstGap == 0) {
selectedPages[0] = 0;
} else if (firstGap == 1) {
selectedPages[0] = 1;
} else {
if (numPages == 5) {
continue;
} else {
selectedPages[0] = 52;
}
}
if (secondGap == 0) {
selectedPages[1] = selectedPages[0] + 1;
} else {
selectedPages[1] = selectedPages[0] + 2;
}
if (thirdGap == 0) {
selectedPages[2] = selectedPages[1] + 1;
} else {
selectedPages[2] = numPages - 1;
}
if (selectedPages[1] < selectedPages[2]
&& selectedPages[2] <= numPages - 1
&& (numPages == 5 || selectedPages[2] >= 50)) {
parameters.add(
new Object[]{numPages, reportNumPagesFromLayout != 0,
writeAllPages != 0, selectedPages});
}
}
}
}
}
}
}
return parameters;
}
public PageRangeAdjustAndVerify(int numPages, boolean reportNumPagesFromLayout,
boolean writeAllPages, int[] selectedPages) {
mNumPages = numPages;
mReportNumPagesFromLayout = reportNumPagesFromLayout;
mWriteAllPages = writeAllPages;
mSelectedPages = selectedPages;
}
private boolean pageRangeContains(@NonNull PageRange[] pagesRanges, int pageNumber) {
for (PageRange pageRange : pagesRanges) {
if (pageRange.equals(PageRange.ALL_PAGES)
|| pageRange.getStart() <= pageNumber && pageNumber <= pageRange.getEnd()) {
return true;
}
}
return false;
}
@Test
public void adjustPageRangeAndVerifyPages() throws Throwable {
Log.i(LOG_TAG, "mNumPages=" + mNumPages + " mReportNumPagesFromLayout="
+ mReportNumPagesFromLayout + " mWriteAllPages=" + mWriteAllPages
+ " mSelectedPages=" + Arrays.toString(mSelectedPages));
// Create a callback for the target print service.
PrintServiceCallbacks firstServiceCallbacks = createMockPrintServiceCallbacks(
invocation -> createMockFirstPrinterDiscoverySessionCallbacks(),
invocation -> {
PrintJob printJob = (PrintJob) invocation.getArguments()[0];
assertEquals(mSelectedPages.length,
printJob.getDocument().getInfo().getPageCount());
assertArrayEquals(new PageRange[]{PageRange.ALL_PAGES},
printJob.getInfo().getPages());
ParcelFileDescriptor original = printJob.getDocument().getData();
// Copy in file
File copy = File.createTempFile("tmp", ".pdf", getActivity().getFilesDir());
Log.i(LOG_TAG, "File is " + copy);
try (FileInputStream in = new FileInputStream(original.getFileDescriptor());
FileOutputStream out = new FileOutputStream(copy)) {
byte[] buffer = new byte[1024];
while (true) {
int numRead = in.read(buffer);
if (numRead == -1) {
break;
}
out.write(buffer, 0, numRead);
}
}
original.close();
printJob.start();
// Verify that the selected pages are colored correctly
try (PdfRenderer renderer = new PdfRenderer(ParcelFileDescriptor.open(copy,
MODE_READ_ONLY))) {
assertEquals(mSelectedPages.length, renderer.getPageCount());
Bitmap rendering = Bitmap.createBitmap(50, 50, Bitmap.Config.ARGB_8888);
for (int i = 0; i < 3; i++) {
try (PdfRenderer.Page page = renderer.openPage(i)) {
page.render(rendering, null, null, RENDER_MODE_FOR_PRINT);
}
int color;
switch (i) {
case 0:
color = 0xffff0000;
break;
case 1:
color = 0xff00ff00;
break;
case 2:
color = 0xff0000ff;
break;
default:
color = 0xffffffff;
break;
}
assertEquals(mSelectedPages[i] + "@" + i, color,
rendering.getPixel(25, 25));
}
rendering.recycle();
}
printJob.complete();
onPrintJobQueuedCalled();
return null;
}, null);
final PrintAttributes[] printAttributes = new PrintAttributes[1];
FirstPrintService.setCallbacks(firstServiceCallbacks);
SecondPrintService.setCallbacks(createSecondMockPrintServiceCallbacks());
final PrintDocumentAdapter adapter = createMockPrintDocumentAdapter(
invocation -> {
boolean changed = !Objects.equals(printAttributes[0],
invocation.getArguments()[1]);
printAttributes[0] = (PrintAttributes) invocation.getArguments()[1];
PrintDocumentInfo.Builder docBuilder =
new PrintDocumentInfo.Builder(PRINT_JOB_NAME);
if (mReportNumPagesFromLayout) {
docBuilder.setPageCount(mNumPages);
}
((PrintDocumentAdapter.LayoutResultCallback) invocation.getArguments()[3])
.onLayoutFinished(
docBuilder.build(), changed);
onLayoutCalled();
return null;
}, invocation -> {
Object[] args = invocation.getArguments();
PageRange[] requestedPageRanges = (PageRange[]) args[0];
ParcelFileDescriptor fd = (ParcelFileDescriptor) args[1];
PrintDocumentAdapter.WriteResultCallback
callback = (PrintDocumentAdapter.WriteResultCallback) args[3];
// Remember which pages to create
boolean[] pagesToPrint = new boolean[mNumPages];
for (int pageNumber = 0; pageNumber < mNumPages; pageNumber++) {
if (pageRangeContains(requestedPageRanges, pageNumber)) {
pagesToPrint[pageNumber] = true;
}
}
PrintedPdfDocument document = new PrintedPdfDocument(getActivity(),
printAttributes[0]);
Paint paint = new Paint();
paint.setStyle(Paint.Style.FILL);
// Create pages
ArrayList<PageRange> printedPages = new ArrayList<>();
for (int pageNumber = 0; pageNumber < mNumPages; pageNumber++) {
if (!mWriteAllPages && !pagesToPrint[pageNumber]) {
continue;
}
printedPages.add(new PageRange(pageNumber, pageNumber));
int color = 0xffffffff;
if (pageNumber == mSelectedPages[0]) {
color = 0xffff0000;
} else if (pageNumber == mSelectedPages[1]) {
color = 0xff00ff00;
} else if (pageNumber == mSelectedPages[2]) {
color = 0xff0000ff;
}
PdfDocument.Page page = document.startPage(pageNumber);
// Color selected pages
if (color != 0xffffffff) {
Canvas canvas = page.getCanvas();
paint.setColor(color);
canvas.drawRect(new Rect(0, 0, canvas.getWidth(), canvas.getHeight()),
paint);
}
document.finishPage(page);
}
try (FileOutputStream fos = new FileOutputStream(fd.getFileDescriptor())) {
document.writeTo(fos);
fos.flush();
document.close();
}
fd.close();
callback.onWriteFinished(
printedPages.toArray(new PageRange[printedPages.size()]));
onWriteCalled();
return null;
}, invocation -> {
onFinishCalled();
return null;
});
print(adapter);
waitForWriteAdapterCallback(1);
openPrintOptions();
selectPages((mSelectedPages[0] + 1) + ", " + (mSelectedPages[1] + 1) + ", "
+ (mSelectedPages[2] + 1), mNumPages);
mPrintHelper.submitPrintJob();
waitForAdapterFinishCallbackCalled();
waitForServiceOnPrintJobQueuedCallbackCalled(1);
}
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)
.addMediaSize(PrintAttributes.MediaSize.ISO_A4, true)
.addResolution(new PrintAttributes.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);
}
}