1 // Copyright 2013 The Chromium Authors
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"
13 #include "base/android/jni_android.h"
14 #include "base/android/jni_array.h"
15 #include "base/android/jni_string.h"
16 #include "base/files/file.h"
17 #include "base/logging.h"
18 #include "base/strings/string_number_conversions.h"
19 #include "base/values.h"
20 #include "printing/metafile.h"
21 #include "printing/mojom/print.mojom.h"
22 #include "printing/print_job_constants.h"
23 #include "printing/printing_jni_headers/PrintingContext_jni.h"
24 #include "printing/units.h"
25 #include "third_party/icu/source/i18n/unicode/ulocdata.h"
26 #include "ui/android/window_android.h"
28 using base::android::JavaParamRef;
29 using base::android::JavaRef;
30 using base::android::ScopedJavaLocalRef;
36 // Sets the page sizes for a `PrintSettings` object. `width` and `height`
37 // arguments should be in device units.
38 void SetSizes(PrintSettings* settings, int dpi, int width, int height) {
39 gfx::Size physical_size_device_units(width, height);
40 // Assume full page is printable for now.
41 gfx::Rect printable_area_device_units(0, 0, width, height);
43 settings->set_dpi(dpi);
44 settings->SetPrinterPrintableArea(physical_size_device_units,
45 printable_area_device_units, false);
48 void GetPageRanges(JNIEnv* env,
49 const JavaRef<jintArray>& int_arr,
50 PageRanges* range_vector) {
51 std::vector<int> pages;
52 base::android::JavaIntArrayToIntVector(env, int_arr, &pages);
53 for (int page : pages) {
57 range_vector->push_back(range);
64 std::unique_ptr<PrintingContext> PrintingContext::CreateImpl(
66 bool skip_system_calls) {
67 DCHECK(!skip_system_calls);
68 return std::make_unique<PrintingContextAndroid>(delegate);
72 void PrintingContextAndroid::PdfWritingDone(int page_count) {
73 JNIEnv* env = base::android::AttachCurrentThread();
74 Java_PrintingContext_pdfWritingDone(env, page_count);
78 void PrintingContextAndroid::SetPendingPrint(
79 ui::WindowAndroid* window,
80 const ScopedJavaLocalRef<jobject>& printable,
81 int render_process_id,
82 int render_frame_id) {
83 JNIEnv* env = base::android::AttachCurrentThread();
84 Java_PrintingContext_setPendingPrint(env, window->GetJavaObject(), printable,
85 render_process_id, render_frame_id);
88 PrintingContextAndroid::PrintingContextAndroid(Delegate* delegate)
89 : PrintingContext(delegate) {
90 // The constructor is run in the IO thread.
93 PrintingContextAndroid::~PrintingContextAndroid() {}
95 void PrintingContextAndroid::AskUserForSettings(
99 PrintSettingsCallback callback) {
100 // This method is always run in the UI thread.
101 callback_ = std::move(callback);
103 JNIEnv* env = base::android::AttachCurrentThread();
104 if (j_printing_context_.is_null()) {
105 j_printing_context_.Reset(
106 Java_PrintingContext_create(env, reinterpret_cast<intptr_t>(this)));
110 Java_PrintingContext_showPrintDialog(env, j_printing_context_);
112 Java_PrintingContext_askUserForSettings(env, j_printing_context_,
117 void PrintingContextAndroid::AskUserForSettingsReply(
119 const JavaParamRef<jobject>& obj,
123 // TODO(cimamoglu): Differentiate between `kFailed` And `kCancel`.
124 std::move(callback_).Run(mojom::ResultCode::kFailed);
128 // We use device name variable to store the file descriptor. This is hacky
129 // but necessary. Since device name is not necessary for the upstream
130 // printing code for Android, this is harmless.
131 // TODO(thestig): See if the call to set_device_name() can be removed.
132 fd_ = Java_PrintingContext_getFileDescriptor(env, j_printing_context_);
133 DCHECK(is_file_descriptor_valid());
134 settings_->set_device_name(base::NumberToString16(fd_));
136 ScopedJavaLocalRef<jintArray> intArr =
137 Java_PrintingContext_getPages(env, j_printing_context_);
138 if (!intArr.is_null()) {
139 PageRanges range_vector;
140 GetPageRanges(env, intArr, &range_vector);
141 settings_->set_ranges(range_vector);
144 int dpi = Java_PrintingContext_getDpi(env, j_printing_context_);
145 int width = Java_PrintingContext_getWidth(env, j_printing_context_);
146 int height = Java_PrintingContext_getHeight(env, j_printing_context_);
147 width = ConvertUnit(width, kMilsPerInch, dpi);
148 height = ConvertUnit(height, kMilsPerInch, dpi);
149 SetSizes(settings_.get(), dpi, width, height);
151 std::move(callback_).Run(mojom::ResultCode::kSuccess);
154 void PrintingContextAndroid::ShowSystemDialogDone(
156 const JavaParamRef<jobject>& obj) {
158 // Settings are not updated, callback is called only to unblock javascript.
159 std::move(callback_).Run(mojom::ResultCode::kCanceled);
162 mojom::ResultCode PrintingContextAndroid::UseDefaultSettings() {
163 DCHECK(!in_print_job_);
166 settings_->set_dpi(kDefaultPdfDpi);
167 gfx::Size physical_size = GetPdfPaperSizeDeviceUnits();
168 SetSizes(settings_.get(), kDefaultPdfDpi, physical_size.width(),
169 physical_size.height());
170 return mojom::ResultCode::kSuccess;
173 gfx::Size PrintingContextAndroid::GetPdfPaperSizeDeviceUnits() {
174 // NOTE: This implementation is the same as in PrintingContextNoSystemDialog.
177 UErrorCode error = U_ZERO_ERROR;
178 ulocdata_getPaperSize(delegate_->GetAppLocale().c_str(), &height, &width,
180 if (error > U_ZERO_ERROR) {
181 // If the call failed, assume a paper size of 8.5 x 11 inches.
182 LOG(WARNING) << "ulocdata_getPaperSize failed, using 8.5 x 11, error: "
185 static_cast<int>(kLetterWidthInch * settings_->device_units_per_inch());
186 height = static_cast<int>(kLetterHeightInch *
187 settings_->device_units_per_inch());
189 // ulocdata_getPaperSize returns the width and height in mm.
190 // Convert this to pixels based on the dpi.
191 float multiplier = settings_->device_units_per_inch() / kMicronsPerMil;
193 height *= multiplier;
195 return gfx::Size(width, height);
198 mojom::ResultCode PrintingContextAndroid::UpdatePrinterSettings(
199 const PrinterSettings& printer_settings) {
200 DCHECK(!printer_settings.show_system_dialog);
201 DCHECK(!in_print_job_);
203 // Intentional No-op.
205 return mojom::ResultCode::kSuccess;
208 mojom::ResultCode PrintingContextAndroid::NewDocument(
209 const std::u16string& document_name) {
210 DCHECK(!in_print_job_);
211 in_print_job_ = true;
213 return mojom::ResultCode::kSuccess;
216 mojom::ResultCode PrintingContextAndroid::PrintDocument(
217 const MetafilePlayer& metafile,
218 const PrintSettings& settings,
219 uint32_t num_pages) {
221 return mojom::ResultCode::kCanceled;
222 DCHECK(in_print_job_);
223 DCHECK(is_file_descriptor_valid());
225 return metafile.SaveToFileDescriptor(fd_) ? mojom::ResultCode::kSuccess
226 : mojom::ResultCode::kFailed;
229 mojom::ResultCode PrintingContextAndroid::DocumentDone() {
231 return mojom::ResultCode::kCanceled;
232 DCHECK(in_print_job_);
235 return mojom::ResultCode::kSuccess;
238 void PrintingContextAndroid::Cancel() {
239 abort_printing_ = true;
240 in_print_job_ = false;
243 void PrintingContextAndroid::ReleaseContext() {
244 // Intentional No-op.
247 printing::NativeDrawingContext PrintingContextAndroid::context() const {
248 // Intentional No-op.
252 } // namespace printing