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
5package org.chromium.printing;
6
7import android.print.PrintDocumentAdapter;
8import android.util.SparseArray;
9
10import org.chromium.base.CalledByNative;
11import org.chromium.base.JNINamespace;
12import org.chromium.base.ThreadUtils;
13
14/**
15 * This class is responsible for communicating with its native counterpart through JNI to handle
16 * the generation of PDF.  On the Java side, it works with a {@link PrintingController}
17 * to talk to the framework.
18 */
19@JNINamespace("printing")
20public class PrintingContext implements PrintingContextInterface {
21
22    /**
23     * Mapping from a file descriptor (as originally provided from
24     * {@link PrintDocumentAdapter#onWrite}) to a PrintingContext.
25     *
26     * This is static because a static method of the native code (inside PrintingContextAndroid)
27     * needs to find Java PrintingContext class corresponding to a file descriptor.
28     **/
29    private static final SparseArray<PrintingContext> PRINTING_CONTEXT_MAP =
30            new SparseArray<PrintingContext>();
31
32    /** The controller this object interacts with, which in turn communicates with the framework. */
33    private final PrintingController mController;
34
35    /** The pointer to the native PrintingContextAndroid object. */
36    private final long mNativeObject;
37
38    private PrintingContext(long ptr) {
39        mController = PrintingControllerImpl.getInstance();
40        mNativeObject = ptr;
41    }
42
43    /**
44     * Updates PRINTING_CONTEXT_MAP to map from the file descriptor to this object.
45     * @param fileDescriptor The file descriptor passed down from
46     *                       {@link PrintDocumentAdapter#onWrite}.
47     * @param delete If true, delete the entry (if it exists). If false, add it to the map.
48     */
49    @Override
50    public void updatePrintingContextMap(int fileDescriptor, boolean delete) {
51        ThreadUtils.assertOnUiThread();
52        if (delete) {
53            PRINTING_CONTEXT_MAP.remove(fileDescriptor);
54        } else {
55            PRINTING_CONTEXT_MAP.put(fileDescriptor, this);
56        }
57    }
58
59    /**
60     * Notifies the native side that the user just chose a new set of printing settings.
61     * @param success True if the user has chosen printing settings necessary for the
62     *                generation of PDF, false if there has been a problem.
63     */
64    @Override
65    public void askUserForSettingsReply(boolean success) {
66        nativeAskUserForSettingsReply(mNativeObject, success);
67    }
68
69    @CalledByNative
70    public static PrintingContext create(int nativeObjectPointer) {
71        ThreadUtils.assertOnUiThread();
72        return new PrintingContext(nativeObjectPointer);
73    }
74
75    @CalledByNative
76    public int getFileDescriptor() {
77        ThreadUtils.assertOnUiThread();
78        return mController.getFileDescriptor();
79    }
80
81    @CalledByNative
82    public int getDpi() {
83        ThreadUtils.assertOnUiThread();
84        return mController.getDpi();
85    }
86
87    @CalledByNative
88    public int getWidth() {
89        ThreadUtils.assertOnUiThread();
90        return mController.getPageWidth();
91    }
92
93    @CalledByNative
94    public int getHeight() {
95        ThreadUtils.assertOnUiThread();
96        return mController.getPageHeight();
97    }
98
99    @CalledByNative
100    public static void pdfWritingDone(int fd, boolean success) {
101        ThreadUtils.assertOnUiThread();
102        // TODO(cimamoglu): Do something when fd == -1.
103        if (PRINTING_CONTEXT_MAP.get(fd) != null) {
104            ThreadUtils.assertOnUiThread();
105            PrintingContext printingContext = PRINTING_CONTEXT_MAP.get(fd);
106            printingContext.mController.pdfWritingDone(success);
107            PRINTING_CONTEXT_MAP.remove(fd);
108        }
109    }
110
111    @CalledByNative
112    public int[] getPages() {
113        ThreadUtils.assertOnUiThread();
114        return mController.getPageNumbers();
115    }
116
117    @CalledByNative
118    public void pageCountEstimationDone(final int maxPages) {
119        ThreadUtils.assertOnUiThread();
120        // If the printing dialog has already finished, tell Chromium that operation is cancelled.
121        if (mController.hasPrintingFinished()) {
122            // NOTE: We don't call nativeAskUserForSettingsReply (hence Chromium callback in
123            // AskUserForSettings callback) twice.  See {@link PrintingControllerImpl#onFinish}
124            // for more explanation.
125            nativeAskUserForSettingsReply(mNativeObject, false);
126        } else {
127            mController.setPrintingContext(this);
128            mController.pageCountEstimationDone(maxPages);
129        }
130    }
131
132    private native void nativeAskUserForSettingsReply(
133            long nativePrintingContextAndroid,
134            boolean success);
135}