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.
5 #include "printing/printing_context_android.h"
11 #include "base/android/jni_android.h"
12 #include "base/android/jni_array.h"
13 #include "base/android/jni_string.h"
14 #include "base/files/file.h"
15 #include "base/logging.h"
16 #include "base/memory/ptr_util.h"
17 #include "base/strings/string_number_conversions.h"
18 #include "base/values.h"
19 #include "jni/PrintingContext_jni.h"
20 #include "printing/metafile.h"
21 #include "printing/print_job_constants.h"
22 #include "printing/units.h"
23 #include "third_party/icu/source/i18n/unicode/ulocdata.h"
25 using base::android::JavaParamRef;
26 using base::android::JavaRef;
27 using base::android::ScopedJavaLocalRef;
33 // Sets the page sizes for a |PrintSettings| object. |width| and |height|
34 // arguments should be in device units.
35 void SetSizes(PrintSettings* settings, int dpi, int width, int height) {
36 gfx::Size physical_size_device_units(width, height);
37 // Assume full page is printable for now.
38 gfx::Rect printable_area_device_units(0, 0, width, height);
40 settings->set_dpi(dpi);
41 settings->SetPrinterPrintableArea(physical_size_device_units,
42 printable_area_device_units,
46 void GetPageRanges(JNIEnv* env,
47 const JavaRef<jintArray>& int_arr,
48 PageRanges* range_vector) {
49 std::vector<int> pages;
50 base::android::JavaIntArrayToIntVector(env, int_arr, &pages);
51 for (int page : pages) {
55 range_vector->push_back(range);
62 std::unique_ptr<PrintingContext> PrintingContext::Create(Delegate* delegate) {
63 return base::WrapUnique(new PrintingContextAndroid(delegate));
67 void PrintingContextAndroid::PdfWritingDone(int page_count) {
68 JNIEnv* env = base::android::AttachCurrentThread();
69 Java_PrintingContext_pdfWritingDone(env, page_count);
72 PrintingContextAndroid::PrintingContextAndroid(Delegate* delegate)
73 : PrintingContext(delegate) {
74 // The constructor is run in the IO thread.
77 PrintingContextAndroid::~PrintingContextAndroid() {
80 void PrintingContextAndroid::AskUserForSettings(
84 PrintSettingsCallback callback) {
85 // This method is always run in the UI thread.
86 callback_ = std::move(callback);
88 JNIEnv* env = base::android::AttachCurrentThread();
89 if (j_printing_context_.is_null()) {
90 j_printing_context_.Reset(Java_PrintingContext_create(
92 reinterpret_cast<intptr_t>(this)));
96 Java_PrintingContext_showPrintDialog(env, j_printing_context_);
98 Java_PrintingContext_askUserForSettings(env, j_printing_context_,
103 void PrintingContextAndroid::AskUserForSettingsReply(
105 const JavaParamRef<jobject>& obj,
109 // TODO(cimamoglu): Differentiate between FAILED And CANCEL.
110 std::move(callback_).Run(FAILED);
114 // We use device name variable to store the file descriptor. This is hacky
115 // but necessary. Since device name is not necessary for the upstream
116 // printing code for Android, this is harmless.
117 // TODO(thestig): See if the call to set_device_name() can be removed.
118 fd_ = Java_PrintingContext_getFileDescriptor(env, j_printing_context_);
119 DCHECK(is_file_descriptor_valid());
120 settings_.set_device_name(base::IntToString16(fd_));
122 ScopedJavaLocalRef<jintArray> intArr =
123 Java_PrintingContext_getPages(env, j_printing_context_);
124 if (!intArr.is_null()) {
125 PageRanges range_vector;
126 GetPageRanges(env, intArr, &range_vector);
127 settings_.set_ranges(range_vector);
130 int dpi = Java_PrintingContext_getDpi(env, j_printing_context_);
131 int width = Java_PrintingContext_getWidth(env, j_printing_context_);
132 int height = Java_PrintingContext_getHeight(env, j_printing_context_);
133 width = ConvertUnit(width, kMilsPerInch, dpi);
134 height = ConvertUnit(height, kMilsPerInch, dpi);
135 SetSizes(&settings_, dpi, width, height);
137 std::move(callback_).Run(OK);
140 void PrintingContextAndroid::ShowSystemDialogDone(
142 const JavaParamRef<jobject>& obj) {
144 // Settings are not updated, callback is called only to unblock javascript.
145 std::move(callback_).Run(CANCEL);
148 void PrintingContextAndroid::PrintDocument(const MetafilePlayer& metafile) {
149 DCHECK(is_file_descriptor_valid());
151 base::File file(fd_);
152 metafile.SaveTo(&file);
153 file.TakePlatformFile();
156 PrintingContext::Result PrintingContextAndroid::UseDefaultSettings() {
157 DCHECK(!in_print_job_);
160 settings_.set_dpi(kDefaultPdfDpi);
161 gfx::Size physical_size = GetPdfPaperSizeDeviceUnits();
162 SetSizes(&settings_, kDefaultPdfDpi, physical_size.width(),
163 physical_size.height());
167 gfx::Size PrintingContextAndroid::GetPdfPaperSizeDeviceUnits() {
168 // NOTE: This implementation is the same as in PrintingContextNoSystemDialog.
171 UErrorCode error = U_ZERO_ERROR;
172 ulocdata_getPaperSize(
173 delegate_->GetAppLocale().c_str(), &height, &width, &error);
174 if (error > U_ZERO_ERROR) {
175 // If the call failed, assume a paper size of 8.5 x 11 inches.
176 LOG(WARNING) << "ulocdata_getPaperSize failed, using 8.5 x 11, error: "
178 width = static_cast<int>(
179 kLetterWidthInch * settings_.device_units_per_inch());
180 height = static_cast<int>(
181 kLetterHeightInch * settings_.device_units_per_inch());
183 // ulocdata_getPaperSize returns the width and height in mm.
184 // Convert this to pixels based on the dpi.
185 float multiplier = settings_.device_units_per_inch() / kMicronsPerMil;
187 height *= multiplier;
189 return gfx::Size(width, height);
192 PrintingContext::Result PrintingContextAndroid::UpdatePrinterSettings(
193 bool external_preview,
194 bool show_system_dialog,
196 DCHECK(!show_system_dialog);
197 DCHECK(!in_print_job_);
199 // Intentional No-op.
204 PrintingContext::Result PrintingContextAndroid::NewDocument(
205 const base::string16& document_name) {
206 DCHECK(!in_print_job_);
207 in_print_job_ = true;
212 PrintingContext::Result PrintingContextAndroid::NewPage() {
215 DCHECK(in_print_job_);
217 // Intentional No-op.
222 PrintingContext::Result PrintingContextAndroid::PageDone() {
225 DCHECK(in_print_job_);
227 // Intentional No-op.
232 PrintingContext::Result PrintingContextAndroid::DocumentDone() {
235 DCHECK(in_print_job_);
241 void PrintingContextAndroid::Cancel() {
242 abort_printing_ = true;
243 in_print_job_ = false;
246 void PrintingContextAndroid::ReleaseContext() {
247 // Intentional No-op.
250 printing::NativeDrawingContext PrintingContextAndroid::context() const {
251 // Intentional No-op.
255 } // namespace printing