diff options
author | dgn <dgn@chromium.org> | 2014-12-15 13:11:23 -0800 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2014-12-15 21:11:50 +0000 |
commit | 4c172eea8b6649f1c1c620d1daa20ce733cee9e1 (patch) | |
tree | 9ac7df8f0058d80866716752ec2563d6fb0b3f79 /printing | |
parent | 7dac4befc4743666c0fcbb92d02ccd3c1c6a8389 (diff) | |
download | chromium_src-4c172eea8b6649f1c1c620d1daa20ce733cee9e1.zip chromium_src-4c172eea8b6649f1c1c620d1daa20ce733cee9e1.tar.gz chromium_src-4c172eea8b6649f1c1c620d1daa20ce733cee9e1.tar.bz2 |
Implement window.print() on Android
Essentially wires up the window.print() and the basic printing path
to Android framwork's PrintManager.
The changes affect the basic printing path using
PrintingMessageFilter::OnScriptedPrint. When calling window.print() on
Android, it would now be called twice.
The first time is directly after the JS call, OnScriptedPrint is called
with a parameter telling it that it's being called from JS. It will then
end up calling PrintJobWorker::GetSettings, forwarding that information.
PrintJobWorker then takes care of calling PrintingController through JNI,
joining the same code path used when printing from chrome's menu in android:
Android framework's PrintManager is invoked, and it manages the preview, using
the tab to generate the output as the user changes his/her preferences.
Why so many changes for just that: the window.print() call is blocked until the
end of the process by message pumping. It has to be disabled when printing is
finished. It is currently done by setting a callback in the current
PrintingContext, that will be called when printing is done. PrintingController
stores the reference to it, but here we have two queries at the same time, and
only the latest PrintingContext would be stored. I added a field to store
separately the one coming from the initial call, so
that it can be used when printing is done to stop the message pumping.
TL;DR: When window.print() is called, the basic printing path is used to forward
the query to PrintManager. The PrintManager then uses almost the same path to
actually print the document (as previously implemented to power the 'Print...'
entry in the menu). The changes are mostly to ensure that JS returns when
printing is completed and not before (or never).
BUG=437338
Review URL: https://codereview.chromium.org/740983002
Cr-Commit-Position: refs/heads/master@{#308416}
Diffstat (limited to 'printing')
18 files changed, 118 insertions, 10 deletions
diff --git a/printing/android/java/src/org/chromium/printing/PrintingContext.java b/printing/android/java/src/org/chromium/printing/PrintingContext.java index e50f0ce..6dc7b55 100644 --- a/printing/android/java/src/org/chromium/printing/PrintingContext.java +++ b/printing/android/java/src/org/chromium/printing/PrintingContext.java @@ -97,6 +97,17 @@ public class PrintingContext implements PrintingContextInterface { } @CalledByNative + public void showPrintDialog() { + ThreadUtils.assertOnUiThread(); + if (mController != null) { // The native side doesn't check if printing is enabled + mController.startPendingPrint(this); + } else { + // Printing disabled. Notify the native side to stop waiting. + showSystemDialogDone(); + } + } + + @CalledByNative public static void pdfWritingDone(int fd, boolean success) { ThreadUtils.assertOnUiThread(); // TODO(cimamoglu): Do something when fd == -1. @@ -129,7 +140,14 @@ public class PrintingContext implements PrintingContextInterface { } } + @Override + public void showSystemDialogDone() { + nativeShowSystemDialogDone(mNativeObject); + } + private native void nativeAskUserForSettingsReply( long nativePrintingContextAndroid, boolean success); + + private native void nativeShowSystemDialogDone(long nativePrintingContextAndroid); } diff --git a/printing/android/java/src/org/chromium/printing/PrintingContextInterface.java b/printing/android/java/src/org/chromium/printing/PrintingContextInterface.java index 80369b3..3bc3e82 100644 --- a/printing/android/java/src/org/chromium/printing/PrintingContextInterface.java +++ b/printing/android/java/src/org/chromium/printing/PrintingContextInterface.java @@ -21,4 +21,10 @@ public interface PrintingContextInterface { * @param success True if the settings are successfully prepared to be used by the native side. */ void askUserForSettingsReply(boolean success); + + /** + * Notifies the native side that the printing process is completed. This method should be + * called when the process was initiated by the native side (window.print()) + */ + void showSystemDialogDone(); } diff --git a/printing/android/java/src/org/chromium/printing/PrintingController.java b/printing/android/java/src/org/chromium/printing/PrintingController.java index 92be968..4753373 100644 --- a/printing/android/java/src/org/chromium/printing/PrintingController.java +++ b/printing/android/java/src/org/chromium/printing/PrintingController.java @@ -73,7 +73,7 @@ public interface PrintingController { * Sets PrintingContext currently associated with the controller. * * This needs to be called after PrintingContext object is created. Firstly its native - * counterpart is created, and then the Java. PrintingController implementation + * counterpart is created, and then the Java. PrintingController implementation * needs this to interact with the native side, since JNI is built on PrintingContext. **/ void setPrintingContext(final PrintingContextInterface printingContext); @@ -82,4 +82,25 @@ public interface PrintingController { * @return Whether a complete PDF generation cycle inside Chromium has been completed. */ boolean hasPrintingFinished(); + + /** + * Sets the data required to initiate a printing process. The process can later be started using + * {@link #startPendingPrint(PrintingContextInterface)}. + * + * @param printable An object capable of starting native side PDF generation, i.e. typically + * a Tab. + * @param printManager The print manager that manages the print job. + */ + void setPendingPrint(final Printable printable, final PrintManagerDelegate printManager); + + /** + * Starts printing, provided that the current object already has sufficient data to start the + * process. (using {@link #setPendingPrint(Printable, PrintManagerDelegate)} for example) + * + * @param jsOriginatedPrintingContext The printingContext holding the callback to be used to + * reply when javascript can resume. When printing is done (or could not start), + * {@link PrintingContextInterface#showSystemDialogDone()} will be called on this object. + */ + void startPendingPrint(PrintingContextInterface jsOriginatedPrintingContext); + } diff --git a/printing/android/java/src/org/chromium/printing/PrintingControllerImpl.java b/printing/android/java/src/org/chromium/printing/PrintingControllerImpl.java index 16e0456..55915e3 100644 --- a/printing/android/java/src/org/chromium/printing/PrintingControllerImpl.java +++ b/printing/android/java/src/org/chromium/printing/PrintingControllerImpl.java @@ -10,6 +10,7 @@ import android.os.ParcelFileDescriptor; import android.print.PageRange; import android.print.PrintAttributes; import android.print.PrintDocumentInfo; +import android.util.Log; import org.chromium.base.ThreadUtils; import org.chromium.printing.PrintDocumentAdapterWrapper.PdfGenerator; @@ -47,6 +48,12 @@ public class PrintingControllerImpl implements PrintingController, PdfGenerator private PrintingContextInterface mPrintingContext; + /** + * The context of a query initiated by window.print(), stored here to allow syncrhonization + * with javascript. + */ + private PrintingContextInterface mContextFromScriptInitiation; + /** The file descriptor into which the PDF will be written. Provided by the framework. */ private int mFileDescriptor; @@ -86,6 +93,8 @@ public class PrintingControllerImpl implements PrintingController, PdfGenerator private boolean mIsBusy = false; + private PrintManagerDelegate mPrintManager; + private PrintingControllerImpl(PrintDocumentAdapterWrapper printDocumentAdapterWrapper, String errorText) { mErrorMessage = errorText; @@ -168,11 +177,30 @@ public class PrintingControllerImpl implements PrintingController, PdfGenerator } @Override - public void startPrint(final Printable printable, PrintManagerDelegate printManager) { + public void setPendingPrint(final Printable printable, PrintManagerDelegate printManager) { if (mIsBusy) return; - mIsBusy = true; mPrintable = printable; - mPrintDocumentAdapterWrapper.print(printManager, printable.getTitle()); + mPrintManager = printManager; + } + + @Override + public void startPendingPrint(PrintingContextInterface printingContext) { + if (mIsBusy || mPrintManager == null) { + Log.w(LOG_TAG, "Pending print can't be started. Is might be busy or not initialized."); + if (printingContext != null) printingContext.showSystemDialogDone(); + return; + } + mContextFromScriptInitiation = printingContext; + mIsBusy = true; + mPrintDocumentAdapterWrapper.print(mPrintManager, mPrintable.getTitle()); + mPrintManager = null; + } + + @Override + public void startPrint(final Printable printable, PrintManagerDelegate printManager) { + if (mIsBusy) return; + setPendingPrint(printable, printManager); + startPendingPrint(null); } @Override @@ -321,6 +349,12 @@ public class PrintingControllerImpl implements PrintingController, PdfGenerator mPrintingContext.updatePrintingContextMap(mFileDescriptor, true); mPrintingContext = null; } + + if (mContextFromScriptInitiation != null) { + mContextFromScriptInitiation.showSystemDialogDone(); + mContextFromScriptInitiation = null; + } + mPrintingState = PRINTING_STATE_FINISHED; closeFileDescriptor(mFileDescriptor); diff --git a/printing/printing_context.h b/printing/printing_context.h index 0cc4731..40c8d33 100644 --- a/printing/printing_context.h +++ b/printing/printing_context.h @@ -55,8 +55,12 @@ class PRINTING_EXPORT PrintingContext { // context with the select device settings. The result of the call is returned // in the callback. This is necessary for Linux, which only has an // asynchronous printing API. + // On Android, when |is_scripted| is true, calling it initiates a full + // printing flow from the framework's PrintManager. + // (see https://codereview.chromium.org/740983002/) virtual void AskUserForSettings(int max_pages, bool has_selection, + bool is_scripted, const PrintSettingsCallback& callback) = 0; // Selects the user's default printer and format. Updates the context with the diff --git a/printing/printing_context_android.cc b/printing/printing_context_android.cc index 64139c8..3be1251 100644 --- a/printing/printing_context_android.cc +++ b/printing/printing_context_android.cc @@ -82,6 +82,7 @@ PrintingContextAndroid::~PrintingContextAndroid() { void PrintingContextAndroid::AskUserForSettings( int max_pages, bool has_selection, + bool is_scripted, const PrintSettingsCallback& callback) { // This method is always run in the UI thread. callback_ = callback; @@ -93,9 +94,13 @@ void PrintingContextAndroid::AskUserForSettings( reinterpret_cast<intptr_t>(this))); } - Java_PrintingContext_pageCountEstimationDone(env, - j_printing_context_.obj(), - max_pages); + if (is_scripted) { + Java_PrintingContext_showPrintDialog(env, j_printing_context_.obj()); + } else { + Java_PrintingContext_pageCountEstimationDone(env, + j_printing_context_.obj(), + max_pages); + } } void PrintingContextAndroid::AskUserForSettingsReply(JNIEnv* env, @@ -132,6 +137,12 @@ void PrintingContextAndroid::AskUserForSettingsReply(JNIEnv* env, callback_.Run(OK); } +void PrintingContextAndroid::ShowSystemDialogDone(JNIEnv* env, + jobject obj) { + // Settings are not updated, callback is called only to unblock javascript. + callback_.Run(CANCEL); +} + PrintingContext::Result PrintingContextAndroid::UseDefaultSettings() { DCHECK(!in_print_job_); diff --git a/printing/printing_context_android.h b/printing/printing_context_android.h index 32f11be..3823b28 100644 --- a/printing/printing_context_android.h +++ b/printing/printing_context_android.h @@ -14,8 +14,7 @@ namespace printing { -// Android subclass of PrintingContext. The implementation for this header file -// resides in Chrome for Android repository. This class communicates with the +// Android subclass of PrintingContext. This class communicates with the // Java side through JNI. class PRINTING_EXPORT PrintingContextAndroid : public PrintingContext { public: @@ -30,10 +29,14 @@ class PRINTING_EXPORT PrintingContextAndroid : public PrintingContext { // printing operation is canceled. void AskUserForSettingsReply(JNIEnv* env, jobject obj, jboolean success); + // Called from Java, when a printing process initiated by a script finishes. + void ShowSystemDialogDone(JNIEnv* env, jobject obj); + // PrintingContext implementation. virtual void AskUserForSettings( int max_pages, bool has_selection, + bool is_scripted, const PrintSettingsCallback& callback) override; virtual Result UseDefaultSettings() override; virtual gfx::Size GetPdfPaperSizeDeviceUnits() override; diff --git a/printing/printing_context_linux.cc b/printing/printing_context_linux.cc index 8e23577..a1fc1f6 100644 --- a/printing/printing_context_linux.cc +++ b/printing/printing_context_linux.cc @@ -67,6 +67,7 @@ void PrintingContextLinux::PrintDocument(const MetafilePlayer& metafile) { void PrintingContextLinux::AskUserForSettings( int max_pages, bool has_selection, + bool is_scripted, const PrintSettingsCallback& callback) { if (!print_dialog_) { // Can only get here if the renderer is sending bad messages. diff --git a/printing/printing_context_linux.h b/printing/printing_context_linux.h index b0ea1f6..d6968d9 100644 --- a/printing/printing_context_linux.h +++ b/printing/printing_context_linux.h @@ -40,6 +40,7 @@ class PRINTING_EXPORT PrintingContextLinux : public PrintingContext { virtual void AskUserForSettings( int max_pages, bool has_selection, + bool is_scripted, const PrintSettingsCallback& callback) override; virtual gfx::Size GetPdfPaperSizeDeviceUnits() override; virtual Result UseDefaultSettings() override; diff --git a/printing/printing_context_mac.h b/printing/printing_context_mac.h index 561b25d..51a1a1c 100644 --- a/printing/printing_context_mac.h +++ b/printing/printing_context_mac.h @@ -27,6 +27,7 @@ class PRINTING_EXPORT PrintingContextMac : public PrintingContext { // PrintingContext implementation. void AskUserForSettings(int max_pages, bool has_selection, + bool is_scripted, const PrintSettingsCallback& callback) override; Result UseDefaultSettings() override; gfx::Size GetPdfPaperSizeDeviceUnits() override; diff --git a/printing/printing_context_mac.mm b/printing/printing_context_mac.mm index 23d2d84..be3df6d 100644 --- a/printing/printing_context_mac.mm +++ b/printing/printing_context_mac.mm @@ -85,6 +85,7 @@ PrintingContextMac::~PrintingContextMac() { void PrintingContextMac::AskUserForSettings( int max_pages, bool has_selection, + bool is_scripted, const PrintSettingsCallback& callback) { // Third-party print drivers seem to be an area prone to raising exceptions. // This will allow exceptions to be raised, but does not handle them. The diff --git a/printing/printing_context_no_system_dialog.cc b/printing/printing_context_no_system_dialog.cc index 7ae10dd..b6246d6 100644 --- a/printing/printing_context_no_system_dialog.cc +++ b/printing/printing_context_no_system_dialog.cc @@ -31,6 +31,7 @@ PrintingContextNoSystemDialog::~PrintingContextNoSystemDialog() { void PrintingContextNoSystemDialog::AskUserForSettings( int max_pages, bool has_selection, + bool is_scripted, const PrintSettingsCallback& callback) { // We don't want to bring up a dialog here. Ever. Just signal the callback. callback.Run(OK); diff --git a/printing/printing_context_no_system_dialog.h b/printing/printing_context_no_system_dialog.h index c155e33..6cc8c2a 100644 --- a/printing/printing_context_no_system_dialog.h +++ b/printing/printing_context_no_system_dialog.h @@ -24,6 +24,7 @@ class PRINTING_EXPORT PrintingContextNoSystemDialog : public PrintingContext { virtual void AskUserForSettings( int max_pages, bool has_selection, + bool is_scripted, const PrintSettingsCallback& callback) override; virtual Result UseDefaultSettings() override; virtual gfx::Size GetPdfPaperSizeDeviceUnits() override; diff --git a/printing/printing_context_system_dialog_win.cc b/printing/printing_context_system_dialog_win.cc index 4e1e8f1..19fc4271 100644 --- a/printing/printing_context_system_dialog_win.cc +++ b/printing/printing_context_system_dialog_win.cc @@ -21,6 +21,7 @@ PrintingContextSytemDialogWin::~PrintingContextSytemDialogWin() { void PrintingContextSytemDialogWin::AskUserForSettings( int max_pages, bool has_selection, + bool is_scripted, const PrintSettingsCallback& callback) { DCHECK(!in_print_job_); dialog_box_dismissed_ = false; diff --git a/printing/printing_context_system_dialog_win.h b/printing/printing_context_system_dialog_win.h index 0a797b2..216cdd3 100644 --- a/printing/printing_context_system_dialog_win.h +++ b/printing/printing_context_system_dialog_win.h @@ -25,6 +25,7 @@ class PRINTING_EXPORT PrintingContextSytemDialogWin virtual void AskUserForSettings( int max_pages, bool has_selection, + bool is_scripted, const PrintSettingsCallback& callback) override; virtual void Cancel() override; diff --git a/printing/printing_context_win.cc b/printing/printing_context_win.cc index c396b1a..678e7f2 100644 --- a/printing/printing_context_win.cc +++ b/printing/printing_context_win.cc @@ -54,6 +54,7 @@ PrintingContextWin::~PrintingContextWin() { void PrintingContextWin::AskUserForSettings( int max_pages, bool has_selection, + bool is_scripted, const PrintSettingsCallback& callback) { NOTIMPLEMENTED(); } @@ -208,7 +209,7 @@ PrintingContext::Result PrintingContextWin::UpdatePrinterSettings( // Update data using DocumentProperties. if (show_system_dialog) { PrintingContext::Result result = PrintingContext::FAILED; - AskUserForSettings(0, false, base::Bind(&AssingResult, &result)); + AskUserForSettings(0, false, false, base::Bind(&AssingResult, &result)); return result; } else { scoped_dev_mode = CreateDevMode(printer.Get(), scoped_dev_mode.get()); diff --git a/printing/printing_context_win.h b/printing/printing_context_win.h index 933162a..7ed8b27 100644 --- a/printing/printing_context_win.h +++ b/printing/printing_context_win.h @@ -24,6 +24,7 @@ class PRINTING_EXPORT PrintingContextWin : public PrintingContext { virtual void AskUserForSettings( int max_pages, bool has_selection, + bool is_scripted, const PrintSettingsCallback& callback) override; virtual Result UseDefaultSettings() override; virtual gfx::Size GetPdfPaperSizeDeviceUnits() override; diff --git a/printing/printing_context_win_unittest.cc b/printing/printing_context_win_unittest.cc index 6777434..a758ca6 100644 --- a/printing/printing_context_win_unittest.cc +++ b/printing/printing_context_win_unittest.cc @@ -161,6 +161,7 @@ TEST_F(PrintingContextTest, PrintAll) { context.AskUserForSettings( 123, false, + false, base::Bind(&PrintingContextTest::PrintSettingsCallback, base::Unretained(this))); EXPECT_EQ(PrintingContext::OK, result()); |