Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a5c560b3 authored by Philip P. Moltmann's avatar Philip P. Moltmann Committed by Android (Google) Code Review
Browse files

Merge "Handle corrupted files when cutting out pages"

parents 7d50ff11 f7a5b4fb
Loading
Loading
Loading
Loading
+27 −14
Original line number Original line Diff line number Diff line
@@ -94,10 +94,10 @@ public final class RemotePrintDocument {
                    // but the content has changed.
                    // but the content has changed.
                    if (mNextCommand == null) {
                    if (mNextCommand == null) {
                        if (mUpdateSpec.pages != null && (mDocumentInfo.changed
                        if (mUpdateSpec.pages != null && (mDocumentInfo.changed
                                || mDocumentInfo.writtenPages == null
                                || mDocumentInfo.pagesWrittenToFile == null
                                || (mDocumentInfo.info.getPageCount()
                                || (mDocumentInfo.info.getPageCount()
                                        != PrintDocumentInfo.PAGE_COUNT_UNKNOWN
                                        != PrintDocumentInfo.PAGE_COUNT_UNKNOWN
                                && !PageRangeUtils.contains(mDocumentInfo.writtenPages,
                                && !PageRangeUtils.contains(mDocumentInfo.pagesWrittenToFile,
                                        mUpdateSpec.pages, mDocumentInfo.info.getPageCount())))) {
                                        mUpdateSpec.pages, mDocumentInfo.info.getPageCount())))) {
                            mNextCommand = new WriteCommand(mContext, mLooper,
                            mNextCommand = new WriteCommand(mContext, mLooper,
                                    mPrintDocumentAdapter, mDocumentInfo,
                                    mPrintDocumentAdapter, mDocumentInfo,
@@ -106,8 +106,9 @@ public final class RemotePrintDocument {
                        } else {
                        } else {
                            if (mUpdateSpec.pages != null) {
                            if (mUpdateSpec.pages != null) {
                                // If we have the requested pages, update which ones to be printed.
                                // If we have the requested pages, update which ones to be printed.
                                mDocumentInfo.printedPages = PageRangeUtils.computePrintedPages(
                                mDocumentInfo.pagesInFileToPrint =
                                        mUpdateSpec.pages, mDocumentInfo.writtenPages,
                                        PageRangeUtils.computeWhichPagesInFileToPrint(
                                                mUpdateSpec.pages, mDocumentInfo.pagesWrittenToFile,
                                                mDocumentInfo.info.getPageCount());
                                                mDocumentInfo.info.getPageCount());
                            }
                            }
                            // Notify we are done.
                            // Notify we are done.
@@ -514,8 +515,20 @@ public final class RemotePrintDocument {
        public PrintAttributes attributes;
        public PrintAttributes attributes;
        public Bundle metadata;
        public Bundle metadata;
        public PrintDocumentInfo info;
        public PrintDocumentInfo info;
        public PageRange[] printedPages;

        public PageRange[] writtenPages;
        /**
         * Which pages out of the ones written to the file to print. This is not indexed by the
         * document pages, but by the page number in the file.
         * <p>E.g. if a document has 10 pages, we want pages 4-5 and 7, but only page 3-9 are in the
         * file. This would contain 1-2 and 4.</p>
         *
         * @see PageRangeUtils#computeWhichPagesInFileToPrint
         */
        public PageRange[] pagesInFileToPrint;

        /** Pages of the whole document that are currently written to file */
        public PageRange[] pagesWrittenToFile;

        public MutexFileProvider fileProvider;
        public MutexFileProvider fileProvider;
        public boolean changed;
        public boolean changed;
        public boolean updated;
        public boolean updated;
@@ -783,8 +796,8 @@ public final class RemotePrintDocument {
            if (changed || !equalsIgnoreSize(mDocument.info, info)) {
            if (changed || !equalsIgnoreSize(mDocument.info, info)) {
                // If the content changed we throw away all pages as
                // If the content changed we throw away all pages as
                // we will request them again with the new content.
                // we will request them again with the new content.
                mDocument.writtenPages = null;
                mDocument.pagesWrittenToFile = null;
                mDocument.printedPages = null;
                mDocument.pagesInFileToPrint = null;
                mDocument.changed = true;
                mDocument.changed = true;
            }
            }


@@ -1098,17 +1111,17 @@ public final class RemotePrintDocument {
            }
            }


            PageRange[] writtenPages = PageRangeUtils.normalize(pages);
            PageRange[] writtenPages = PageRangeUtils.normalize(pages);
            PageRange[] printedPages = PageRangeUtils.computePrintedPages(
            PageRange[] printedPages = PageRangeUtils.computeWhichPagesInFileToPrint(
                    mPages, writtenPages, mPageCount);
                    mPages, writtenPages, mPageCount);


            // Handle if we got invalid pages
            // Handle if we got invalid pages
            if (printedPages != null) {
            if (printedPages != null) {
                mDocument.writtenPages = writtenPages;
                mDocument.pagesWrittenToFile = writtenPages;
                mDocument.printedPages = printedPages;
                mDocument.pagesInFileToPrint = printedPages;
                completed();
                completed();
            } else {
            } else {
                mDocument.writtenPages = null;
                mDocument.pagesWrittenToFile = null;
                mDocument.printedPages = null;
                mDocument.pagesInFileToPrint = null;
                failed(mContext.getString(R.string.print_error_default_message));
                failed(mContext.getString(R.string.print_error_default_message));
            }
            }


+25 −21
Original line number Original line Diff line number Diff line
@@ -85,8 +85,8 @@ import android.widget.EditText;
import android.widget.ImageView;
import android.widget.ImageView;
import android.widget.Spinner;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.TextView;

import android.widget.Toast;
import android.widget.Toast;

import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.printspooler.R;
import com.android.printspooler.R;
@@ -120,6 +120,7 @@ import java.util.Collection;
import java.util.Collections;
import java.util.Collections;
import java.util.List;
import java.util.List;
import java.util.Objects;
import java.util.Objects;
import java.util.function.Consumer;


public class PrintActivity extends Activity implements RemotePrintDocument.UpdateResultCallbacks,
public class PrintActivity extends Activity implements RemotePrintDocument.UpdateResultCallbacks,
        PrintErrorFragment.OnActionListener, PageAdapter.ContentCallbacks,
        PrintErrorFragment.OnActionListener, PageAdapter.ContentCallbacks,
@@ -543,8 +544,8 @@ public class PrintActivity extends Activity implements RemotePrintDocument.Updat
        // pages in the printed document.
        // pages in the printed document.
        PrintDocumentInfo info = document.info;
        PrintDocumentInfo info = document.info;
        if (info != null) {
        if (info != null) {
            final int pageCount = PageRangeUtils.getNormalizedPageCount(document.writtenPages,
            final int pageCount = PageRangeUtils.getNormalizedPageCount(
                    getAdjustedPageCount(info));
                    document.pagesWrittenToFile, getAdjustedPageCount(info));
            PrintDocumentInfo adjustedInfo = new PrintDocumentInfo.Builder(info.getName())
            PrintDocumentInfo adjustedInfo = new PrintDocumentInfo.Builder(info.getName())
                    .setContentType(info.getContentType())
                    .setContentType(info.getContentType())
                    .setPageCount(pageCount)
                    .setPageCount(pageCount)
@@ -558,7 +559,7 @@ public class PrintActivity extends Activity implements RemotePrintDocument.Updat
            }
            }


            mPrintJob.setDocumentInfo(adjustedInfo);
            mPrintJob.setDocumentInfo(adjustedInfo);
            mPrintJob.setPages(document.printedPages);
            mPrintJob.setPages(document.pagesInFileToPrint);
        }
        }


        switch (mState) {
        switch (mState) {
@@ -627,7 +628,7 @@ public class PrintActivity extends Activity implements RemotePrintDocument.Updat
        // Update the preview controller.
        // Update the preview controller.
        mPrintPreviewController.onContentUpdated(contentUpdated,
        mPrintPreviewController.onContentUpdated(contentUpdated,
                getAdjustedPageCount(documentInfo.info),
                getAdjustedPageCount(documentInfo.info),
                mPrintedDocument.getDocumentInfo().writtenPages,
                mPrintedDocument.getDocumentInfo().pagesWrittenToFile,
                mSelectedPages, mPrintJob.getAttributes().getMediaSize(),
                mSelectedPages, mPrintJob.getAttributes().getMediaSize(),
                mPrintJob.getAttributes().getMinMargins());
                mPrintJob.getAttributes().getMinMargins());
    }
    }
@@ -2105,14 +2106,15 @@ public class PrintActivity extends Activity implements RemotePrintDocument.Updat
        // If saving to PDF, apply the attibutes as we are acting as a print service.
        // If saving to PDF, apply the attibutes as we are acting as a print service.
        PrintAttributes attributes = mDestinationSpinnerAdapter.getPdfPrinter() == mCurrentPrinter
        PrintAttributes attributes = mDestinationSpinnerAdapter.getPdfPrinter() == mCurrentPrinter
                ?  mPrintJob.getAttributes() : null;
                ?  mPrintJob.getAttributes() : null;
        new DocumentTransformer(this, mPrintJob, mFileProvider, attributes, new Runnable() {
        new DocumentTransformer(this, mPrintJob, mFileProvider, attributes, error -> {
            @Override
            if (error == null) {
            public void run() {
                if (writeToUri != null) {
                if (writeToUri != null) {
                    mPrintedDocument.writeContent(getContentResolver(), writeToUri);
                    mPrintedDocument.writeContent(getContentResolver(), writeToUri);
                }
                }
                setState(STATE_PRINT_COMPLETED);
                setState(STATE_PRINT_COMPLETED);
                doFinish();
                doFinish();
            } else {
                onPrintDocumentError(error);
            }
            }
        }).transform();
        }).transform();
    }
    }
@@ -3096,11 +3098,11 @@ public class PrintActivity extends Activity implements RemotePrintDocument.Updat


        private final PrintAttributes mAttributesToApply;
        private final PrintAttributes mAttributesToApply;


        private final Runnable mCallback;
        private final Consumer<String> mCallback;


        public DocumentTransformer(Context context, PrintJobInfo printJob,
        public DocumentTransformer(Context context, PrintJobInfo printJob,
                MutexFileProvider fileProvider, PrintAttributes attributes,
                MutexFileProvider fileProvider, PrintAttributes attributes,
                Runnable callback) {
                Consumer<String> callback) {
            mContext = context;
            mContext = context;
            mPrintJob = printJob;
            mPrintJob = printJob;
            mFileProvider = fileProvider;
            mFileProvider = fileProvider;
@@ -3112,7 +3114,7 @@ public class PrintActivity extends Activity implements RemotePrintDocument.Updat
        public void transform() {
        public void transform() {
            // If we have only the pages we want, done.
            // If we have only the pages we want, done.
            if (mPagesToShred.length <= 0 && mAttributesToApply == null) {
            if (mPagesToShred.length <= 0 && mAttributesToApply == null) {
                mCallback.run();
                mCallback.accept(null);
                return;
                return;
            }
            }


@@ -3126,22 +3128,26 @@ public class PrintActivity extends Activity implements RemotePrintDocument.Updat
        @Override
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
        public void onServiceConnected(ComponentName name, IBinder service) {
            final IPdfEditor editor = IPdfEditor.Stub.asInterface(service);
            final IPdfEditor editor = IPdfEditor.Stub.asInterface(service);
            new AsyncTask<Void, Void, Void>() {
            new AsyncTask<Void, Void, String>() {
                @Override
                @Override
                protected Void doInBackground(Void... params) {
                protected String doInBackground(Void... params) {
                    // It's OK to access the data members as they are
                    // It's OK to access the data members as they are
                    // final and this code is the last one to touch
                    // final and this code is the last one to touch
                    // them as shredding is the very last step, so the
                    // them as shredding is the very last step, so the
                    // UI is not interactive at this point.
                    // UI is not interactive at this point.
                    try {
                        doTransform(editor);
                        doTransform(editor);
                        updatePrintJob();
                        updatePrintJob();
                        return null;
                        return null;
                    } catch (IOException | RemoteException | IllegalStateException e) {
                        return e.toString();
                    }
                }
                }


                @Override
                @Override
                protected void onPostExecute(Void aVoid) {
                protected void onPostExecute(String error) {
                    mContext.unbindService(DocumentTransformer.this);
                    mContext.unbindService(DocumentTransformer.this);
                    mCallback.run();
                    mCallback.accept(error);
                }
                }
            }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
            }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
        }
        }
@@ -3151,7 +3157,7 @@ public class PrintActivity extends Activity implements RemotePrintDocument.Updat
            /* do nothing */
            /* do nothing */
        }
        }


        private void doTransform(IPdfEditor editor) {
        private void doTransform(IPdfEditor editor) throws IOException, RemoteException {
            File tempFile = null;
            File tempFile = null;
            ParcelFileDescriptor src = null;
            ParcelFileDescriptor src = null;
            ParcelFileDescriptor dst = null;
            ParcelFileDescriptor dst = null;
@@ -3190,8 +3196,6 @@ public class PrintActivity extends Activity implements RemotePrintDocument.Updat
                in = new FileInputStream(tempFile);
                in = new FileInputStream(tempFile);
                out = new FileOutputStream(jobFile);
                out = new FileOutputStream(jobFile);
                Streams.copy(in, out);
                Streams.copy(in, out);
            } catch (IOException|RemoteException e) {
                Log.e(LOG_TAG, "Error dropping pages", e);
            } finally {
            } finally {
                IoUtils.closeQuietly(src);
                IoUtils.closeQuietly(src);
                IoUtils.closeQuietly(dst);
                IoUtils.closeQuietly(dst);
+21 −12
Original line number Original line Diff line number Diff line
@@ -394,33 +394,42 @@ public final class PageRangeUtils {
        return pageRanges.getStart() == 0 && pageRanges.getEnd() == pageCount - 1;
        return pageRanges.getStart() == 0 && pageRanges.getEnd() == pageCount - 1;
    }
    }


    public static PageRange[] computePrintedPages(PageRange[] requestedPages,
    /**
            PageRange[] writtenPages, int pageCount) {
     * Compute the pages of the file that correspond to the requested pages in the doc.
     *
     * @param pagesInDocRequested The requested pages, doc-indexed
     * @param pagesWrittenToFile The pages in the file
     * @param pageCount The number of pages in the doc
     *
     * @return The pages, file-indexed
     */
    public static PageRange[] computeWhichPagesInFileToPrint(PageRange[] pagesInDocRequested,
            PageRange[] pagesWrittenToFile, int pageCount) {
        // Adjust the print job pages based on what was requested and written.
        // Adjust the print job pages based on what was requested and written.
        // The cases are ordered in the most expected to the least expected
        // The cases are ordered in the most expected to the least expected
        // with a special case first where the app does not know the page count
        // with a special case first where the app does not know the page count
        // so we ask for all to be written.
        // so we ask for all to be written.
        if (Arrays.equals(requestedPages, ALL_PAGES_RANGE)
        if (Arrays.equals(pagesInDocRequested, ALL_PAGES_RANGE)
                && pageCount == PrintDocumentInfo.PAGE_COUNT_UNKNOWN) {
                && pageCount == PrintDocumentInfo.PAGE_COUNT_UNKNOWN) {
            return ALL_PAGES_RANGE;
            return ALL_PAGES_RANGE;
        } else if (Arrays.equals(writtenPages, requestedPages)) {
        } else if (Arrays.equals(pagesWrittenToFile, pagesInDocRequested)) {
            // We got a document with exactly the pages we wanted. Hence,
            // We got a document with exactly the pages we wanted. Hence,
            // the printer has to print all pages in the data.
            // the printer has to print all pages in the data.
            return ALL_PAGES_RANGE;
            return ALL_PAGES_RANGE;
        } else if (Arrays.equals(writtenPages, ALL_PAGES_RANGE)) {
        } else if (Arrays.equals(pagesWrittenToFile, ALL_PAGES_RANGE)) {
            // We requested specific pages but got all of them. Hence,
            // We requested specific pages but got all of them. Hence,
            // the printer has to print only the requested pages.
            // the printer has to print only the requested pages.
            return requestedPages;
            return pagesInDocRequested;
        } else if (PageRangeUtils.contains(writtenPages, requestedPages, pageCount)) {
        } else if (PageRangeUtils.contains(pagesWrittenToFile, pagesInDocRequested, pageCount)) {
            // We requested specific pages and got more but not all pages.
            // We requested specific pages and got more but not all pages.
            // Hence, we have to offset appropriately the printed pages to
            // Hence, we have to offset appropriately the printed pages to
            // be based off the start of the written ones instead of zero.
            // be based off the start of the written ones instead of zero.
            // The written pages are always non-null and not empty.
            // The written pages are always non-null and not empty.
            final int offset = -writtenPages[0].getStart();
            final int offset = -pagesWrittenToFile[0].getStart();
            PageRangeUtils.offset(requestedPages, offset);
            PageRangeUtils.offset(pagesInDocRequested, offset);
            return requestedPages;
            return pagesInDocRequested;
        } else if (Arrays.equals(requestedPages, ALL_PAGES_RANGE)
        } else if (Arrays.equals(pagesInDocRequested, ALL_PAGES_RANGE)
                && isAllPages(writtenPages, pageCount)) {
                && isAllPages(pagesWrittenToFile, pageCount)) {
            // We requested all pages via the special constant and got all
            // We requested all pages via the special constant and got all
            // of them as an explicit enumeration. Hence, the printer has
            // of them as an explicit enumeration. Hence, the printer has
            // to print only the requested pages.
            // to print only the requested pages.