1 // Copyright 2013 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 package org.chromium.android_webview; 6 7 import android.os.CancellationSignal; 8 import android.os.ParcelFileDescriptor; 9 import android.print.PrintAttributes; 10 import android.util.Log; 11 import android.view.ViewGroup; 12 import android.webkit.ValueCallback; 13 14 import org.chromium.base.CalledByNative; 15 import org.chromium.base.JNINamespace; 16 17 /** 18 * Export the android webview as a PDF. 19 * @TODO(sgurun) explain the ownership of this class and its native counterpart 20 */ 21 @JNINamespace("android_webview") 22 public class AwPdfExporter { 23 24 private static final String TAG = "AwPdfExporter"; 25 private long mNativeAwPdfExporter; 26 // TODO(sgurun) result callback should return an int/object indicating errors. 27 // potential errors: invalid print parameters, already pending, IO error 28 private ValueCallback<Boolean> mResultCallback; 29 private PrintAttributes mAttributes; 30 private ParcelFileDescriptor mFd; 31 // Maintain a reference to the top level object (i.e. WebView) since in a common 32 // use case (offscreen webview) application may expect the framework's print manager 33 // to own the Webview (via PrintDocumentAdapter). 34 // NOTE: it looks unused, but please do not remove this reference. 35 private ViewGroup mContainerView; 36 AwPdfExporter(ViewGroup containerView)37 AwPdfExporter(ViewGroup containerView) { 38 setContainerView(containerView); 39 } 40 setContainerView(ViewGroup containerView)41 public void setContainerView(ViewGroup containerView) { 42 mContainerView = containerView; 43 } 44 exportToPdf(final ParcelFileDescriptor fd, PrintAttributes attributes, ValueCallback<Boolean> resultCallback, CancellationSignal cancellationSignal)45 public void exportToPdf(final ParcelFileDescriptor fd, PrintAttributes attributes, 46 ValueCallback<Boolean> resultCallback, CancellationSignal cancellationSignal) { 47 48 if (fd == null) { 49 throw new IllegalArgumentException("fd cannot be null"); 50 } 51 if (resultCallback == null) { 52 throw new IllegalArgumentException("resultCallback cannot be null"); 53 } 54 if (mResultCallback != null) { 55 throw new IllegalStateException("printing is already pending"); 56 } 57 if (attributes.getMediaSize() == null) { 58 throw new IllegalArgumentException("attributes must specify a media size"); 59 } 60 if (attributes.getResolution() == null) { 61 throw new IllegalArgumentException("attributes must specify print resolution"); 62 } 63 if (attributes.getMinMargins() == null) { 64 throw new IllegalArgumentException("attributes must specify margins"); 65 } 66 if (mNativeAwPdfExporter == 0) { 67 resultCallback.onReceiveValue(false); 68 return; 69 } 70 mResultCallback = resultCallback; 71 mAttributes = attributes; 72 mFd = fd; 73 nativeExportToPdf(mNativeAwPdfExporter, mFd.getFd(), cancellationSignal); 74 } 75 76 @CalledByNative setNativeAwPdfExporter(long nativePdfExporter)77 private void setNativeAwPdfExporter(long nativePdfExporter) { 78 mNativeAwPdfExporter = nativePdfExporter; 79 // Handle the cornercase that Webview.Destroy is called before the native side 80 // has a chance to complete the pdf exporting. 81 if (nativePdfExporter == 0 && mResultCallback != null) { 82 mResultCallback.onReceiveValue(false); 83 mResultCallback = null; 84 } 85 } 86 getPrintDpi(PrintAttributes attributes)87 private static int getPrintDpi(PrintAttributes attributes) { 88 // TODO(sgurun) android print attributes support horizontal and 89 // vertical DPI. Chrome has only one DPI. Revisit this. 90 int horizontalDpi = attributes.getResolution().getHorizontalDpi(); 91 int verticalDpi = attributes.getResolution().getVerticalDpi(); 92 if (horizontalDpi != verticalDpi) { 93 Log.w(TAG, "Horizontal and vertical DPIs differ. Using horizontal DPI " + 94 " hDpi=" + horizontalDpi + " vDPI=" + verticalDpi); 95 } 96 return horizontalDpi; 97 } 98 99 @CalledByNative didExportPdf(boolean success)100 private void didExportPdf(boolean success) { 101 mResultCallback.onReceiveValue(success); 102 mResultCallback = null; 103 mAttributes = null; 104 // The caller should close the file. 105 mFd = null; 106 } 107 108 @CalledByNative getPageWidth()109 private int getPageWidth() { 110 return mAttributes.getMediaSize().getWidthMils(); 111 } 112 113 @CalledByNative getPageHeight()114 private int getPageHeight() { 115 return mAttributes.getMediaSize().getHeightMils(); 116 } 117 118 @CalledByNative getDpi()119 private int getDpi() { 120 return getPrintDpi(mAttributes); 121 } 122 123 @CalledByNative getLeftMargin()124 private int getLeftMargin() { 125 return mAttributes.getMinMargins().getLeftMils(); 126 } 127 128 @CalledByNative getRightMargin()129 private int getRightMargin() { 130 return mAttributes.getMinMargins().getRightMils(); 131 } 132 133 @CalledByNative getTopMargin()134 private int getTopMargin() { 135 return mAttributes.getMinMargins().getTopMils(); 136 } 137 138 @CalledByNative getBottomMargin()139 private int getBottomMargin() { 140 return mAttributes.getMinMargins().getBottomMils(); 141 } 142 nativeExportToPdf(long nativeAwPdfExporter, int fd, CancellationSignal cancellationSignal)143 private native void nativeExportToPdf(long nativeAwPdfExporter, int fd, 144 CancellationSignal cancellationSignal); 145 } 146