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