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

Commit 561b8931 authored by Svet Ganov's avatar Svet Ganov Committed by Android (Google) Code Review
Browse files

Merge "Move print rendering in an isolated process." into lmp-dev

parents 8c8fbcf3 13f542ca
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -195,6 +195,7 @@ public final class PdfRenderer implements AutoCloseable {
    public Page openPage(int index) {
        throwIfClosed();
        throwIfPageOpened();
        throwIfPageNotInDocument(index);
        mCurrentPage = new Page(index);
        return mCurrentPage;
    }
@@ -237,6 +238,12 @@ public final class PdfRenderer implements AutoCloseable {
        }
    }

    private void throwIfPageNotInDocument(int pageIndex) {
        if (pageIndex >= mPageCount) {
            throw new IllegalArgumentException("Invalid page index");
        }
    }

    /**
     * This class represents a PDF document page for rendering.
     */
+1 −0
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := optional

LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_SRC_FILES += src/com/android/printspooler/renderer/IPdfRenderer.aidl

LOCAL_PACKAGE_NAME := PrintSpooler

+5 −0
Original line number Diff line number Diff line
@@ -53,6 +53,11 @@
            android:permission="android.permission.BIND_PRINT_SPOOLER_SERVICE">
        </service>

        <service
            android:name=".renderer.PdfRendererService"
            android:isolatedProcess="true">
        </service>

        <activity
            android:name=".ui.PrintActivity"
            android:configChanges="orientation|screenSize"
+100 −95
Original line number Diff line number Diff line
@@ -17,24 +17,31 @@
package com.android.printspooler.model;

import android.app.ActivityManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.res.Configuration;
import android.content.Intent;
import android.content.ServiceConnection;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.pdf.PdfRenderer;
import android.os.AsyncTask;
import android.os.IBinder;
import android.os.ParcelFileDescriptor;
import android.print.PrintAttributes.MediaSize;
import android.print.PrintAttributes.Margins;
import android.os.RemoteException;
import android.print.PrintAttributes;
import android.print.PrintDocumentInfo;
import android.util.ArrayMap;
import android.util.Log;
import android.view.View;
import com.android.internal.annotations.GuardedBy;
import com.android.printspooler.renderer.IPdfRenderer;
import com.android.printspooler.renderer.PdfRendererService;
import dalvik.system.CloseGuard;
import libcore.io.IoUtils;

import java.io.FileDescriptor;
import java.io.IOException;
import java.util.Iterator;
import java.util.LinkedHashMap;
@@ -55,9 +62,6 @@ public final class PageContentRepository {

    private static final int BYTES_PER_MEGABYTE = 1048576;

    private static final int MILS_PER_INCH = 1000;
    private static final int POINTS_IN_INCH = 72;

    private final CloseGuard mCloseGuard = CloseGuard.get();

    private final ArrayMap<Integer, PageContentProvider> mPageContentProviders =
@@ -115,7 +119,6 @@ public final class PageContentRepository {
        if (DEBUG) {
            Log.i(LOG_TAG, "STATE_DESTROYED");
        }
        throwIfNotClosed();
        doDestroy();
    }

@@ -351,15 +354,13 @@ public final class PageContentRepository {
    public static final class RenderSpec {
        final int bitmapWidth;
        final int bitmapHeight;
        final MediaSize mediaSize;
        final Margins minMargins;
        final PrintAttributes printAttributes;

        public RenderSpec(int bitmapWidth, int bitmapHeight,
                MediaSize mediaSize, Margins minMargins) {
                PrintAttributes printAttributes) {
            this.bitmapWidth = bitmapWidth;
            this.bitmapHeight = bitmapHeight;
            this.mediaSize = mediaSize;
            this.minMargins = minMargins;
            this.printAttributes = printAttributes;
        }

        @Override
@@ -380,18 +381,11 @@ public final class PageContentRepository {
            if (bitmapWidth != other.bitmapWidth) {
                return false;
            }
            if (mediaSize != null) {
                if (!mediaSize.equals(other.mediaSize)) {
                    return false;
                }
            } else if (other.mediaSize != null) {
            if (printAttributes != null) {
                if (!printAttributes.equals(other.printAttributes)) {
                    return false;
                }
            if (minMargins != null) {
                if (!minMargins.equals(other.minMargins)) {
                    return false;
                }
            } else if (other.minMargins != null) {
            } else if (other.printAttributes != null) {
                return false;
            }
            return true;
@@ -407,8 +401,7 @@ public final class PageContentRepository {
        public int hashCode() {
            int result = bitmapWidth;
            result = 31 * result + bitmapHeight;
            result = 31 * result + (mediaSize != null ? mediaSize.hashCode() : 0);
            result = 31 * result + (minMargins != null ? minMargins.hashCode() : 0);
            result = 31 * result + (printAttributes != null ? printAttributes.hashCode() : 0);
            return result;
        }
    }
@@ -440,13 +433,11 @@ public final class PageContentRepository {
        }
    }

    private static int pointsFromMils(int mils) {
        return (int) (((float) mils / MILS_PER_INCH) * POINTS_IN_INCH);
    }

    private static class AsyncRenderer {
    private static final class AsyncRenderer implements ServiceConnection {
        private static final int MALFORMED_PDF_FILE_ERROR = -2;

        private final Object mLock = new Object();

        private final Context mContext;

        private final PageContentLruCache mPageContentCache;
@@ -457,8 +448,8 @@ public final class PageContentRepository {

        private int mPageCount = PrintDocumentInfo.PAGE_COUNT_UNKNOWN;

        // Accessed only by the executor thread.
        private PdfRenderer mRenderer;
        @GuardedBy("mLock")
        private IPdfRenderer mRenderer;

        public AsyncRenderer(Context context, OnMalformedPdfFileListener malformedPdfFileListener) {
            mContext = context;
@@ -470,6 +461,21 @@ public final class PageContentRepository {
            mPageContentCache = new PageContentLruCache(cacheSizeInBytes);
        }

        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            synchronized (mLock) {
                mRenderer = IPdfRenderer.Stub.asInterface(service);
                mLock.notifyAll();
            }
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            synchronized (mLock) {
                mRenderer = null;
            }
        }

        public void open(final ParcelFileDescriptor source, final Runnable callback) {
            // Opening a new document invalidates the cache as it has pages
            // from the last document. We keep the cache even when the document
@@ -478,16 +484,30 @@ public final class PageContentRepository {
            mPageContentCache.invalidate();

            new AsyncTask<Void, Void, Integer>() {
                @Override
                protected void onPreExecute() {
                    Intent intent = new Intent(mContext, PdfRendererService.class);
                    mContext.bindService(intent, AsyncRenderer.this, Context.BIND_AUTO_CREATE);
                }

                @Override
                protected Integer doInBackground(Void... params) {
                    synchronized (mLock) {
                        while (mRenderer == null) {
                            try {
                        mRenderer = new PdfRenderer(source);
                        return mRenderer.getPageCount();
                    } catch (IOException ioe) {
                                mLock.wait();
                            } catch (InterruptedException ie) {
                                /* ignore */
                            }
                        }
                        try {
                            return mRenderer.openDocument(source);
                        } catch (RemoteException re) {
                            Log.e(LOG_TAG, "Cannot open PDF document");
                            return MALFORMED_PDF_FILE_ERROR;
                        }
                    }
                }

                @Override
                public void onPostExecute(Integer pageCount) {
@@ -510,7 +530,13 @@ public final class PageContentRepository {
            new AsyncTask<Void, Void, Void>() {
                @Override
                protected Void doInBackground(Void... params) {
                    mRenderer.close();
                    synchronized (mLock) {
                        try {
                            mRenderer.closeDocument();
                        } catch (RemoteException re) {
                            /* ignore */
                        }
                    }
                    return null;
                }

@@ -525,9 +551,20 @@ public final class PageContentRepository {
        }

        public void destroy() {
            new AsyncTask<Void, Void, Void>() {
                @Override
                protected Void doInBackground(Void... params) {
                    return null;
                }

                @Override
                public void onPostExecute(Void result) {
                    mContext.unbindService(AsyncRenderer.this);
                    mPageContentCache.invalidate();
                    mPageContentCache.clear();
                }
            }.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, (Void[]) null);
        }

        public void startPreload(int firstShownPage, int lastShownPage, RenderSpec renderSpec) {
            if (DEBUG) {
@@ -752,63 +789,31 @@ public final class PageContentRepository {
                    return mRenderedPage;
                }

                PdfRenderer.Page page = mRenderer.openPage(mPageIndex);

                if (isCancelled()) {
                    page.close();
                    return mRenderedPage;
                }

                Bitmap bitmap = mRenderedPage.content.getBitmap();

                final int srcWidthPts = page.getWidth();
                final int srcHeightPts = page.getHeight();

                final int dstWidthPts = pointsFromMils(mRenderSpec.mediaSize.getWidthMils());
                final int dstHeightPts = pointsFromMils(mRenderSpec.mediaSize.getHeightMils());

                final boolean scaleContent = mRenderer.shouldScaleForPrinting();
                final boolean contentLandscape = !mRenderSpec.mediaSize.isPortrait();

                final float displayScale;
                Matrix matrix = new Matrix();

                if (scaleContent) {
                    displayScale = Math.min((float) bitmap.getWidth() / srcWidthPts,
                            (float) bitmap.getHeight() / srcHeightPts);
                } else {
                    if (contentLandscape) {
                        displayScale = (float) bitmap.getHeight() / dstHeightPts;
                    } else {
                        displayScale = (float) bitmap.getWidth() / dstWidthPts;
                    }
                }
                matrix.postScale(displayScale, displayScale);

                Configuration configuration = mContext.getResources().getConfiguration();
                if (configuration.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL) {
                    matrix.postTranslate(bitmap.getWidth() - srcWidthPts * displayScale, 0);
                }

                final int paddingLeftPts = pointsFromMils(mRenderSpec.minMargins.getLeftMils());
                final int paddingTopPts = pointsFromMils(mRenderSpec.minMargins.getTopMils());
                final int paddingRightPts = pointsFromMils(mRenderSpec.minMargins.getRightMils());
                final int paddingBottomPts = pointsFromMils(mRenderSpec.minMargins.getBottomMils());

                Rect clip = new Rect();
                clip.left = (int) (paddingLeftPts * displayScale);
                clip.top = (int) (paddingTopPts * displayScale);
                clip.right = (int) (bitmap.getWidth() - paddingRightPts * displayScale);
                clip.bottom = (int) (bitmap.getHeight() - paddingBottomPts * displayScale);

                if (DEBUG) {
                    Log.i(LOG_TAG, "Rendering page:" + mPageIndex + " of " + mPageCount);
                ParcelFileDescriptor[] pipe = null;
                try {
                    pipe = ParcelFileDescriptor.createPipe();
                    ParcelFileDescriptor source = pipe[0];
                    ParcelFileDescriptor destination = pipe[1];

                    mRenderer.renderPage(mPageIndex, bitmap.getWidth(), bitmap.getHeight(),
                            mRenderSpec.printAttributes, destination);

                    // We passed the file descriptor to the other side which took
                    // ownership, so close our copy for the write to complete.
                    destination.close();

                    BitmapFactory.Options options = new BitmapFactory.Options();
                    options.inBitmap = bitmap;
                    BitmapFactory.decodeFileDescriptor(source.getFileDescriptor(), null, options);
                } catch (IOException|RemoteException e) {
                    Log.e(LOG_TAG, "Error rendering page:" + mPageIndex, e);
                } finally {
                    IoUtils.closeQuietly(pipe[0]);
                    IoUtils.closeQuietly(pipe[1]);
                }

                page.render(bitmap, clip, matrix, PdfRenderer.Page.RENDER_MODE_FOR_DISPLAY);

                page.close();

                return mRenderedPage;
            }

+33 −0
Original line number Diff line number Diff line
/*
 * 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 com.android.printspooler.renderer;

import android.graphics.Rect;
import android.os.ParcelFileDescriptor;
import android.print.PageRange;
import android.print.PrintAttributes;

/**
 * Interface for communication with a remote pdf renderer.
 */
interface IPdfRenderer {
    int openDocument(in ParcelFileDescriptor source);
    oneway void renderPage(int pageIndex, int bitmapWidth, int bitmapHeight,
        in PrintAttributes attributes, in ParcelFileDescriptor destination);
    oneway void closeDocument();
    oneway void writePages(in PageRange[] pages);
}
Loading