diff options
12 files changed, 165 insertions, 39 deletions
diff --git a/core/java/android/print/IPrintDocumentAdapter.aidl b/core/java/android/print/IPrintDocumentAdapter.aidl index 9d384fb..8f33e0b 100644 --- a/core/java/android/print/IPrintDocumentAdapter.aidl +++ b/core/java/android/print/IPrintDocumentAdapter.aidl @@ -37,4 +37,5 @@ oneway interface IPrintDocumentAdapter { void write(in PageRange[] pages, in ParcelFileDescriptor fd, IWriteResultCallback callback, int sequence); void finish(); + void kill(String reason); } diff --git a/core/java/android/print/PrintManager.java b/core/java/android/print/PrintManager.java index bf8ac65..3fb812e 100644 --- a/core/java/android/print/PrintManager.java +++ b/core/java/android/print/PrintManager.java @@ -634,6 +634,17 @@ public final class PrintManager { } @Override + public void kill(String reason) { + synchronized (mLock) { + // If destroyed the handler is null. + if (!isDestroyedLocked()) { + mHandler.obtainMessage(MyHandler.MSG_ON_KILL, + reason).sendToTarget(); + } + } + } + + @Override public void onActivityPaused(Activity activity) { /* do nothing */ } @@ -719,6 +730,7 @@ public final class PrintManager { public static final int MSG_ON_LAYOUT = 2; public static final int MSG_ON_WRITE = 3; public static final int MSG_ON_FINISH = 4; + public static final int MSG_ON_KILL = 5; public MyHandler(Looper looper) { super(looper, null, true); @@ -794,6 +806,15 @@ public final class PrintManager { } } break; + case MSG_ON_KILL: { + if (DEBUG) { + Log.i(LOG_TAG, "onKill()"); + } + + String reason = (String) message.obj; + throw new RuntimeException(reason); + } + default: { throw new IllegalArgumentException("Unknown message: " + message.what); diff --git a/core/jni/android/graphics/pdf/PdfEditor.cpp b/core/jni/android/graphics/pdf/PdfEditor.cpp index 2b756e2..ed6f1d6 100644 --- a/core/jni/android/graphics/pdf/PdfEditor.cpp +++ b/core/jni/android/graphics/pdf/PdfEditor.cpp @@ -89,8 +89,17 @@ static jlong nativeOpen(JNIEnv* env, jclass thiz, jint fd, jlong size) { if (!document) { const long error = FPDF_GetLastError(); - jniThrowException(env, "java/io/IOException", - "cannot create document. Error:" + error); + switch (error) { + case FPDF_ERR_PASSWORD: + case FPDF_ERR_SECURITY: { + jniThrowException(env, "java/lang/SecurityException", + "cannot create document. Error:" + error); + } break; + default: { + jniThrowException(env, "java/io/IOException", + "cannot create document. Error:" + error); + } break; + } destroyLibraryIfNeeded(); return -1; } diff --git a/core/jni/android/graphics/pdf/PdfRenderer.cpp b/core/jni/android/graphics/pdf/PdfRenderer.cpp index 303ddea..357d3c0 100644 --- a/core/jni/android/graphics/pdf/PdfRenderer.cpp +++ b/core/jni/android/graphics/pdf/PdfRenderer.cpp @@ -82,8 +82,17 @@ static jlong nativeCreate(JNIEnv* env, jclass thiz, jint fd, jlong size) { if (!document) { const long error = FPDF_GetLastError(); - jniThrowException(env, "java/io/IOException", - "cannot create document. Error:" + error); + switch (error) { + case FPDF_ERR_PASSWORD: + case FPDF_ERR_SECURITY: { + jniThrowException(env, "java/lang/SecurityException", + "cannot create document. Error:" + error); + } break; + default: { + jniThrowException(env, "java/io/IOException", + "cannot create document. Error:" + error); + } break; + } destroyLibraryIfNeeded(); return -1; } diff --git a/graphics/java/android/graphics/pdf/PdfEditor.java b/graphics/java/android/graphics/pdf/PdfEditor.java index 0b84d29..2b70b6a 100644 --- a/graphics/java/android/graphics/pdf/PdfEditor.java +++ b/graphics/java/android/graphics/pdf/PdfEditor.java @@ -59,6 +59,10 @@ public final class PdfEditor { * * @param input Seekable file descriptor to read from. * + * @throws java.io.IOException If an error occurs while reading the file. + * @throws java.lang.SecurityException If the file requires a password or + * the security scheme is not supported. + * * @see #close() */ public PdfEditor(@NonNull ParcelFileDescriptor input) throws IOException { diff --git a/graphics/java/android/graphics/pdf/PdfRenderer.java b/graphics/java/android/graphics/pdf/PdfRenderer.java index 359c294..79934da 100644 --- a/graphics/java/android/graphics/pdf/PdfRenderer.java +++ b/graphics/java/android/graphics/pdf/PdfRenderer.java @@ -131,6 +131,10 @@ public final class PdfRenderer implements AutoCloseable { * </p> * * @param input Seekable file descriptor to read from. + * + * @throws java.io.IOException If an error occurs while reading the file. + * @throws java.lang.SecurityException If the file requires a password or + * the security scheme is not supported. */ public PdfRenderer(@NonNull ParcelFileDescriptor input) throws IOException { if (input == null) { diff --git a/packages/PrintSpooler/src/com/android/printspooler/model/OpenDocumentCallback.java b/packages/PrintSpooler/src/com/android/printspooler/model/OpenDocumentCallback.java new file mode 100644 index 0000000..50f424a --- /dev/null +++ b/packages/PrintSpooler/src/com/android/printspooler/model/OpenDocumentCallback.java @@ -0,0 +1,37 @@ +/* + * 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.model; + +/** + * Callbacks interface for opening a file. + */ +public interface OpenDocumentCallback { + public static final int ERROR_MALFORMED_PDF_FILE = -1; + public static final int ERROR_SECURE_PDF_FILE = -2; + + /** + * Called after the file is opened. + */ + public void onSuccess(); + + /** + * Called after opening the file failed. + * + * @param error The error. + */ + public void onFailure(int error); +} diff --git a/packages/PrintSpooler/src/com/android/printspooler/model/PageContentRepository.java b/packages/PrintSpooler/src/com/android/printspooler/model/PageContentRepository.java index 35930cd..882b364 100644 --- a/packages/PrintSpooler/src/com/android/printspooler/model/PageContentRepository.java +++ b/packages/PrintSpooler/src/com/android/printspooler/model/PageContentRepository.java @@ -78,13 +78,8 @@ public final class PageContentRepository { public void onPageContentAvailable(BitmapDrawable content); } - public interface OnMalformedPdfFileListener { - public void onMalformedPdfFile(); - } - - public PageContentRepository(Context context, - OnMalformedPdfFileListener malformedPdfFileListener) { - mRenderer = new AsyncRenderer(context, malformedPdfFileListener); + public PageContentRepository(Context context) { + mRenderer = new AsyncRenderer(context); mState = STATE_CLOSED; if (DEBUG) { Log.i(LOG_TAG, "STATE_CLOSED"); @@ -92,7 +87,7 @@ public final class PageContentRepository { mCloseGuard.open("destroy"); } - public void open(ParcelFileDescriptor source, final Runnable callback) { + public void open(ParcelFileDescriptor source, final OpenDocumentCallback callback) { throwIfNotClosed(); mState = STATE_OPENED; if (DEBUG) { @@ -412,8 +407,6 @@ public final class PageContentRepository { private final ArrayMap<Integer, RenderPageTask> mPageToRenderTaskMap = new ArrayMap<>(); - private final OnMalformedPdfFileListener mOnMalformedPdfFileListener; - private int mPageCount = PrintDocumentInfo.PAGE_COUNT_UNKNOWN; @GuardedBy("mLock") @@ -422,9 +415,8 @@ public final class PageContentRepository { private boolean mBoundToService; private boolean mDestroyed; - public AsyncRenderer(Context context, OnMalformedPdfFileListener malformedPdfFileListener) { + public AsyncRenderer(Context context) { mContext = context; - mOnMalformedPdfFileListener = malformedPdfFileListener; ActivityManager activityManager = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE); @@ -447,7 +439,7 @@ public final class PageContentRepository { } } - public void open(final ParcelFileDescriptor source, final Runnable callback) { + public void open(final ParcelFileDescriptor source, final OpenDocumentCallback callback) { // Opening a new document invalidates the cache as it has pages // from the last document. We keep the cache even when the document // is closed to show pages while the other side is writing the new @@ -483,7 +475,7 @@ public final class PageContentRepository { return mRenderer.openDocument(source); } catch (RemoteException re) { Log.e(LOG_TAG, "Cannot open PDF document"); - return PdfManipulationService.MALFORMED_PDF_FILE_ERROR; + return PdfManipulationService.ERROR_MALFORMED_PDF_FILE; } finally { // Close the fd as we passed it to another process // which took ownership. @@ -494,14 +486,25 @@ public final class PageContentRepository { @Override public void onPostExecute(Integer pageCount) { - if (pageCount == PdfManipulationService.MALFORMED_PDF_FILE_ERROR) { - mOnMalformedPdfFileListener.onMalformedPdfFile(); - mPageCount = PrintDocumentInfo.PAGE_COUNT_UNKNOWN; - } else { - mPageCount = pageCount; - } - if (callback != null) { - callback.run(); + switch (pageCount) { + case PdfManipulationService.ERROR_MALFORMED_PDF_FILE: { + mPageCount = PrintDocumentInfo.PAGE_COUNT_UNKNOWN; + if (callback != null) { + callback.onFailure(OpenDocumentCallback.ERROR_MALFORMED_PDF_FILE); + } + } break; + case PdfManipulationService.ERROR_SECURE_PDF_FILE: { + mPageCount = PrintDocumentInfo.PAGE_COUNT_UNKNOWN; + if (callback != null) { + callback.onFailure(OpenDocumentCallback.ERROR_SECURE_PDF_FILE); + } + } break; + default: { + mPageCount = pageCount; + if (callback != null) { + callback.onSuccess(); + } + } break; } } }.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR); diff --git a/packages/PrintSpooler/src/com/android/printspooler/model/RemotePrintDocument.java b/packages/PrintSpooler/src/com/android/printspooler/model/RemotePrintDocument.java index f6ace41..1b6e9ce 100644 --- a/packages/PrintSpooler/src/com/android/printspooler/model/RemotePrintDocument.java +++ b/packages/PrintSpooler/src/com/android/printspooler/model/RemotePrintDocument.java @@ -304,6 +304,18 @@ public final class RemotePrintDocument { disconnectFromRemoteDocument(); } + public void kill(String reason) { + if (DEBUG) { + Log.i(LOG_TAG, "[CALLED] kill()"); + } + + try { + mPrintDocumentAdapter.kill(reason); + } catch (RemoteException re) { + Log.e(LOG_TAG, "Error calling kill()", re); + } + } + public boolean isUpdating() { return mState == STATE_UPDATING || mState == STATE_CANCELING; } diff --git a/packages/PrintSpooler/src/com/android/printspooler/renderer/PdfManipulationService.java b/packages/PrintSpooler/src/com/android/printspooler/renderer/PdfManipulationService.java index 0462e4d..7db2074 100644 --- a/packages/PrintSpooler/src/com/android/printspooler/renderer/PdfManipulationService.java +++ b/packages/PrintSpooler/src/com/android/printspooler/renderer/PdfManipulationService.java @@ -47,7 +47,9 @@ public final class PdfManipulationService extends Service { public static final String ACTION_GET_EDITOR = "com.android.printspooler.renderer.ACTION_GET_EDITOR"; - public static final int MALFORMED_PDF_FILE_ERROR = -2; + public static final int ERROR_MALFORMED_PDF_FILE = -2; + + public static final int ERROR_SECURE_PDF_FILE = -3; private static final String LOG_TAG = "PdfManipulationService"; private static final boolean DEBUG = false; @@ -90,7 +92,11 @@ public final class PdfManipulationService extends Service { } catch (IOException | IllegalStateException e) { IoUtils.closeQuietly(source); Log.e(LOG_TAG, "Cannot open file", e); - return MALFORMED_PDF_FILE_ERROR; + return ERROR_MALFORMED_PDF_FILE; + } catch (SecurityException e) { + IoUtils.closeQuietly(source); + Log.e(LOG_TAG, "Cannot open file", e); + return ERROR_SECURE_PDF_FILE; } } } diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/PageAdapter.java b/packages/PrintSpooler/src/com/android/printspooler/ui/PageAdapter.java index aa79568..0d2e736 100644 --- a/packages/PrintSpooler/src/com/android/printspooler/ui/PageAdapter.java +++ b/packages/PrintSpooler/src/com/android/printspooler/ui/PageAdapter.java @@ -37,6 +37,7 @@ import android.view.ViewGroup.LayoutParams; import android.view.View.MeasureSpec; import android.widget.TextView; import com.android.printspooler.R; +import com.android.printspooler.model.OpenDocumentCallback; import com.android.printspooler.model.PageContentRepository; import com.android.printspooler.model.PageContentRepository.PageContentProvider; import com.android.printspooler.util.PageRangeUtils; @@ -51,8 +52,7 @@ import java.util.List; /** * This class represents the adapter for the pages in the print preview list. */ -public final class PageAdapter extends Adapter implements - PageContentRepository.OnMalformedPdfFileListener { +public final class PageAdapter extends Adapter { private static final String LOG_TAG = "PageAdapter"; private static final int MAX_PREVIEW_PAGES_BATCH = 50; @@ -113,6 +113,7 @@ public final class PageAdapter extends Adapter implements public interface ContentCallbacks { public void onRequestContentUpdate(); public void onMalformedPdfFile(); + public void onSecurePdfFile(); } public interface PreviewArea { @@ -127,7 +128,7 @@ public final class PageAdapter extends Adapter implements mCallbacks = callbacks; mLayoutInflater = (LayoutInflater) context.getSystemService( Context.LAYOUT_INFLATER_SERVICE); - mPageContentRepository = new PageContentRepository(context, this); + mPageContentRepository = new PageContentRepository(context); mPreviewPageMargin = mContext.getResources().getDimensionPixelSize( R.dimen.preview_page_margin); @@ -156,11 +157,6 @@ public final class PageAdapter extends Adapter implements } } - @Override - public void onMalformedPdfFile() { - mCallbacks.onMalformedPdfFile(); - } - public void onOrientationChanged() { mColumnCount = mContext.getResources().getInteger( R.integer.preview_page_per_row_count); @@ -181,12 +177,25 @@ public final class PageAdapter extends Adapter implements if (DEBUG) { Log.i(LOG_TAG, "STATE_OPENED"); } - mPageContentRepository.open(source, new Runnable() { + mPageContentRepository.open(source, new OpenDocumentCallback() { @Override - public void run() { + public void onSuccess() { notifyDataSetChanged(); callback.run(); } + + @Override + public void onFailure(int error) { + switch (error) { + case OpenDocumentCallback.ERROR_MALFORMED_PDF_FILE: { + mCallbacks.onMalformedPdfFile(); + } break; + + case OpenDocumentCallback.ERROR_SECURE_PDF_FILE: { + mCallbacks.onSecurePdfFile(); + } break; + } + } }); } diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java index f361884..b76a9cd 100644 --- a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java +++ b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java @@ -378,7 +378,7 @@ public class PrintActivity extends Activity implements RemotePrintDocument.Updat return true; } - if (mState == STATE_PRINT_CANCELED ||mState == STATE_PRINT_CONFIRMED + if (mState == STATE_PRINT_CANCELED || mState == STATE_PRINT_CONFIRMED || mState == STATE_PRINT_COMPLETED) { return true; } @@ -405,12 +405,23 @@ public class PrintActivity extends Activity implements RemotePrintDocument.Updat @Override public void onMalformedPdfFile() { + onPrintDocumentError("Cannot print a malformed PDF file"); + } + + @Override + public void onSecurePdfFile() { + onPrintDocumentError("Cannot print a password protected PDF file"); + } + + private void onPrintDocumentError(String message) { mProgressMessageController.cancel(); ensureErrorUiShown(null, PrintErrorFragment.ACTION_RETRY); setState(STATE_UPDATE_FAILED); updateOptionsUi(); + + mPrintedDocument.kill(message); } @Override |