Move print rendering in an isolated process.
Security review of the PDF rendering code revealed that it is not sercure. Therefore, this code must be run in a sandbox. This change moves the rendering code in an isolated process. bug:16897933 Change-Id: I711ce42a56892db1837950137bfaa79e1d61a7c4
This commit is contained in:
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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)) {
|
||||
if (printAttributes != null) {
|
||||
if (!printAttributes.equals(other.printAttributes)) {
|
||||
return false;
|
||||
}
|
||||
} else if (other.mediaSize != null) {
|
||||
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,14 +484,28 @@ 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) {
|
||||
try {
|
||||
mRenderer = new PdfRenderer(source);
|
||||
return mRenderer.getPageCount();
|
||||
} catch (IOException ioe) {
|
||||
Log.e(LOG_TAG, "Cannot open PDF document");
|
||||
return MALFORMED_PDF_FILE_ERROR;
|
||||
synchronized (mLock) {
|
||||
while (mRenderer == null) {
|
||||
try {
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,8 +551,19 @@ public final class PageContentRepository {
|
||||
}
|
||||
|
||||
public void destroy() {
|
||||
mPageContentCache.invalidate();
|
||||
mPageContentCache.clear();
|
||||
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) {
|
||||
@@ -752,62 +789,30 @@ 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();
|
||||
ParcelFileDescriptor[] pipe = null;
|
||||
try {
|
||||
pipe = ParcelFileDescriptor.createPipe();
|
||||
ParcelFileDescriptor source = pipe[0];
|
||||
ParcelFileDescriptor destination = pipe[1];
|
||||
|
||||
final int dstWidthPts = pointsFromMils(mRenderSpec.mediaSize.getWidthMils());
|
||||
final int dstHeightPts = pointsFromMils(mRenderSpec.mediaSize.getHeightMils());
|
||||
mRenderer.renderPage(mPageIndex, bitmap.getWidth(), bitmap.getHeight(),
|
||||
mRenderSpec.printAttributes, destination);
|
||||
|
||||
final boolean scaleContent = mRenderer.shouldScaleForPrinting();
|
||||
final boolean contentLandscape = !mRenderSpec.mediaSize.isPortrait();
|
||||
// We passed the file descriptor to the other side which took
|
||||
// ownership, so close our copy for the write to complete.
|
||||
destination.close();
|
||||
|
||||
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;
|
||||
}
|
||||
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]);
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
page.render(bitmap, clip, matrix, PdfRenderer.Page.RENDER_MODE_FOR_DISPLAY);
|
||||
|
||||
page.close();
|
||||
|
||||
return mRenderedPage;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
@@ -0,0 +1,198 @@
|
||||
/*
|
||||
* 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.app.Service;
|
||||
import android.content.Intent;
|
||||
import android.content.res.Configuration;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Matrix;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.pdf.PdfRenderer;
|
||||
import android.os.IBinder;
|
||||
import android.os.ParcelFileDescriptor;
|
||||
import android.os.RemoteException;
|
||||
import android.print.PageRange;
|
||||
import android.print.PrintAttributes;
|
||||
import android.print.PrintAttributes.Margins;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import libcore.io.IoUtils;
|
||||
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Service for rendering PDF documents in an isolated process.
|
||||
*/
|
||||
public final class PdfRendererService extends Service {
|
||||
private static final String LOG_TAG = "PdfRendererService";
|
||||
private static final boolean DEBUG = false;
|
||||
|
||||
private static final int MILS_PER_INCH = 1000;
|
||||
private static final int POINTS_IN_INCH = 72;
|
||||
|
||||
@Override
|
||||
public IBinder onBind(Intent intent) {
|
||||
return new PdfRendererImpl();
|
||||
}
|
||||
|
||||
private final class PdfRendererImpl extends IPdfRenderer.Stub {
|
||||
private final Object mLock = new Object();
|
||||
|
||||
private Bitmap mBitmap;
|
||||
private PdfRenderer mRenderer;
|
||||
|
||||
@Override
|
||||
public int openDocument(ParcelFileDescriptor source) throws RemoteException {
|
||||
synchronized (mLock) {
|
||||
throwIfOpened();
|
||||
if (DEBUG) {
|
||||
Log.i(LOG_TAG, "openDocument()");
|
||||
}
|
||||
try {
|
||||
mRenderer = new PdfRenderer(source);
|
||||
return mRenderer.getPageCount();
|
||||
} catch (IOException ioe) {
|
||||
throw new RemoteException("Cannot open file");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void renderPage(int pageIndex, int bitmapWidth, int bitmapHeight,
|
||||
PrintAttributes attributes, ParcelFileDescriptor destination) {
|
||||
FileOutputStream out = null;
|
||||
synchronized (mLock) {
|
||||
try {
|
||||
throwIfNotOpened();
|
||||
|
||||
PdfRenderer.Page page = mRenderer.openPage(pageIndex);
|
||||
|
||||
final int srcWidthPts = page.getWidth();
|
||||
final int srcHeightPts = page.getHeight();
|
||||
|
||||
final int dstWidthPts = pointsFromMils(
|
||||
attributes.getMediaSize().getWidthMils());
|
||||
final int dstHeightPts = pointsFromMils(
|
||||
attributes.getMediaSize().getHeightMils());
|
||||
|
||||
final boolean scaleContent = mRenderer.shouldScaleForPrinting();
|
||||
final boolean contentLandscape = !attributes.getMediaSize().isPortrait();
|
||||
|
||||
final float displayScale;
|
||||
Matrix matrix = new Matrix();
|
||||
|
||||
if (scaleContent) {
|
||||
displayScale = Math.min((float) bitmapWidth / srcWidthPts,
|
||||
(float) bitmapHeight / srcHeightPts);
|
||||
} else {
|
||||
if (contentLandscape) {
|
||||
displayScale = (float) bitmapHeight / dstHeightPts;
|
||||
} else {
|
||||
displayScale = (float) bitmapWidth / dstWidthPts;
|
||||
}
|
||||
}
|
||||
matrix.postScale(displayScale, displayScale);
|
||||
|
||||
Configuration configuration = PdfRendererService.this.getResources()
|
||||
.getConfiguration();
|
||||
if (configuration.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL) {
|
||||
matrix.postTranslate(bitmapWidth - srcWidthPts * displayScale, 0);
|
||||
}
|
||||
|
||||
Margins minMargins = attributes.getMinMargins();
|
||||
final int paddingLeftPts = pointsFromMils(minMargins.getLeftMils());
|
||||
final int paddingTopPts = pointsFromMils(minMargins.getTopMils());
|
||||
final int paddingRightPts = pointsFromMils(minMargins.getRightMils());
|
||||
final int paddingBottomPts = pointsFromMils(minMargins.getBottomMils());
|
||||
|
||||
Rect clip = new Rect();
|
||||
clip.left = (int) (paddingLeftPts * displayScale);
|
||||
clip.top = (int) (paddingTopPts * displayScale);
|
||||
clip.right = (int) (bitmapWidth - paddingRightPts * displayScale);
|
||||
clip.bottom = (int) (bitmapHeight - paddingBottomPts * displayScale);
|
||||
|
||||
if (DEBUG) {
|
||||
Log.i(LOG_TAG, "Rendering page:" + pageIndex);
|
||||
}
|
||||
|
||||
Bitmap bitmap = getBitmapForSize(bitmapWidth, bitmapHeight);
|
||||
page.render(bitmap, clip, matrix, PdfRenderer.Page.RENDER_MODE_FOR_DISPLAY);
|
||||
|
||||
page.close();
|
||||
|
||||
out = new FileOutputStream(destination.getFileDescriptor());
|
||||
bitmap.compress(Bitmap.CompressFormat.PNG, 0, out);
|
||||
} finally {
|
||||
IoUtils.closeQuietly(out);
|
||||
IoUtils.closeQuietly(destination);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void closeDocument() {
|
||||
synchronized (mLock) {
|
||||
throwIfNotOpened();
|
||||
if (DEBUG) {
|
||||
Log.i(LOG_TAG, "openDocument()");
|
||||
}
|
||||
mRenderer.close();
|
||||
mRenderer = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writePages(PageRange[] pages) {
|
||||
synchronized (mLock) {
|
||||
throwIfNotOpened();
|
||||
if (DEBUG) {
|
||||
Log.i(LOG_TAG, "writePages()");
|
||||
}
|
||||
// TODO: Implement dropping undesired pages.
|
||||
}
|
||||
}
|
||||
|
||||
private Bitmap getBitmapForSize(int width, int height) {
|
||||
if (mBitmap != null) {
|
||||
if (mBitmap.getWidth() == width && mBitmap.getHeight() == height) {
|
||||
return mBitmap;
|
||||
}
|
||||
mBitmap.recycle();
|
||||
}
|
||||
mBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
|
||||
return mBitmap;
|
||||
}
|
||||
|
||||
private void throwIfOpened() {
|
||||
if (mRenderer != null) {
|
||||
throw new IllegalStateException("Already opened");
|
||||
}
|
||||
}
|
||||
|
||||
private void throwIfNotOpened() {
|
||||
if (mRenderer == null) {
|
||||
throw new IllegalStateException("Not opened");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static int pointsFromMils(int mils) {
|
||||
return (int) (((float) mils / MILS_PER_INCH) * POINTS_IN_INCH);
|
||||
}
|
||||
}
|
||||
@@ -319,6 +319,7 @@ public class PrintActivity extends Activity implements RemotePrintDocument.Updat
|
||||
|
||||
mProgressMessageController.cancel();
|
||||
mPrinterRegistry.setTrackedPrinter(null);
|
||||
mPrintPreviewController.destroy();
|
||||
mSpoolerProvider.destroy();
|
||||
mPrintedDocument.finish();
|
||||
mPrintedDocument.destroy();
|
||||
|
||||
@@ -191,6 +191,9 @@ class PrintPreviewController implements MutexFileProvider.OnReleaseRequestCallba
|
||||
}
|
||||
|
||||
public void destroy() {
|
||||
if (mPageAdapter.isOpened()) {
|
||||
mPageAdapter.close(null);
|
||||
}
|
||||
mPageAdapter.destroy();
|
||||
}
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ import android.content.Context;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
import android.graphics.drawable.ColorDrawable;
|
||||
import android.print.PrintAttributes;
|
||||
import android.print.PrintAttributes.MediaSize;
|
||||
import android.print.PrintAttributes.Margins;
|
||||
import android.util.AttributeSet;
|
||||
@@ -38,13 +39,12 @@ import com.android.printspooler.model.PageContentRepository.RenderSpec;
|
||||
public class PageContentView extends View
|
||||
implements PageContentRepository.OnPageContentAvailableCallback {
|
||||
|
||||
private final PrintAttributes mAttributes = new PrintAttributes.Builder().build();
|
||||
|
||||
private final ColorDrawable mEmptyState;
|
||||
|
||||
private PageContentProvider mProvider;
|
||||
|
||||
private MediaSize mMediaSize;
|
||||
private Margins mMinMargins;
|
||||
|
||||
private boolean mContentRequested;
|
||||
|
||||
public PageContentView(Context context, AttributeSet attrs) {
|
||||
@@ -83,15 +83,17 @@ public class PageContentView extends View
|
||||
}
|
||||
|
||||
public void init(PageContentProvider provider, MediaSize mediaSize, Margins minMargins) {
|
||||
if (mProvider == provider
|
||||
&& ((mMediaSize == null) ? mediaSize == null : mMediaSize.equals(mediaSize))
|
||||
&& ((mMinMargins == null) ? minMargins == null : mMinMargins.equals(minMargins))) {
|
||||
if (mProvider == null ? provider == null : mProvider.equals(provider)
|
||||
&& ((mAttributes.getMediaSize() == null)
|
||||
? mediaSize == null : mAttributes.getMediaSize().equals(mediaSize))
|
||||
&& ((mAttributes.getMinMargins() == null)
|
||||
? minMargins == null : mAttributes.getMinMargins().equals(minMargins))) {
|
||||
return;
|
||||
}
|
||||
|
||||
mProvider = provider;
|
||||
mMediaSize = mediaSize;
|
||||
mMinMargins = minMargins;
|
||||
mAttributes.setMediaSize(mediaSize);
|
||||
mAttributes.setMinMargins(minMargins);
|
||||
mContentRequested = false;
|
||||
|
||||
// If there is no provider we want immediately to switch to
|
||||
@@ -106,8 +108,7 @@ public class PageContentView extends View
|
||||
private void requestPageContentIfNeeded() {
|
||||
if (getWidth() > 0 && getHeight() > 0 && !mContentRequested && mProvider != null) {
|
||||
mContentRequested = true;
|
||||
mProvider.getPageContent(new RenderSpec(getWidth(), getHeight(), mMediaSize,
|
||||
mMinMargins), this);
|
||||
mProvider.getPageContent(new RenderSpec(getWidth(), getHeight(), mAttributes), this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user