1b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav/*
2b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav * Copyright (C) 2013 The Android Open Source Project
3b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav *
4b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav * Licensed under the Apache License, Version 2.0 (the "License");
5b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav * you may not use this file except in compliance with the License.
6b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav * You may obtain a copy of the License at
7b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav *
8b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav *      http://www.apache.org/licenses/LICENSE-2.0
9b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav *
10b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav * Unless required by applicable law or agreed to in writing, software
11b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav * distributed under the License is distributed on an "AS IS" BASIS,
12b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav * See the License for the specific language governing permissions and
14b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav * limitations under the License.
15b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav */
16b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav
17b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslavpackage android.support.v4.print;
18b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav
19b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslavimport android.content.Context;
20b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslavimport android.graphics.Bitmap;
21b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslavimport android.graphics.BitmapFactory;
22b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslavimport android.graphics.Matrix;
23b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslavimport android.graphics.RectF;
24b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslavimport android.graphics.pdf.PdfDocument.Page;
25b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslavimport android.net.Uri;
26975c49f182d754dfe1a38ba0457d6e603b125570John Hofordimport android.os.AsyncTask;
27b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslavimport android.os.Bundle;
28b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslavimport android.os.CancellationSignal;
29b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslavimport android.os.ParcelFileDescriptor;
30b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslavimport android.print.PageRange;
31b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslavimport android.print.PrintAttributes;
32b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslavimport android.print.PrintDocumentAdapter;
33b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslavimport android.print.PrintDocumentInfo;
34b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslavimport android.print.PrintManager;
35b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslavimport android.print.pdf.PrintedPdfDocument;
36b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslavimport android.util.Log;
37b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav
38b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslavimport java.io.FileNotFoundException;
39b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslavimport java.io.FileOutputStream;
40b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslavimport java.io.IOException;
41b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslavimport java.io.InputStream;
42b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav
43b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav/**
44b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav * Kitkat specific PrintManager API implementation.
45b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav */
46975c49f182d754dfe1a38ba0457d6e603b125570John Hofordclass PrintHelperKitkat {
47b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav    private static final String LOG_TAG = "PrintHelperKitkat";
48b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav    // will be <= 300 dpi on A4 (8.3×11.7) paper (worst case of 150 dpi)
49b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav    private final static int MAX_PRINT_SIZE = 3500;
50b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav    final Context mContext;
51975c49f182d754dfe1a38ba0457d6e603b125570John Hoford    BitmapFactory.Options mDecodeOptions = null;
52975c49f182d754dfe1a38ba0457d6e603b125570John Hoford    private final Object mLock = new Object();
53b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav    /**
54b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav     * image will be scaled but leave white space
55b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav     */
56b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav    public static final int SCALE_MODE_FIT = 1;
57b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav    /**
58b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav     * image will fill the paper and be cropped (default)
59b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav     */
60b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav    public static final int SCALE_MODE_FILL = 2;
61b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav
6209ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov    /**
63975c49f182d754dfe1a38ba0457d6e603b125570John Hoford     * select landscape (default)
64975c49f182d754dfe1a38ba0457d6e603b125570John Hoford     */
65975c49f182d754dfe1a38ba0457d6e603b125570John Hoford    public static final int ORIENTATION_LANDSCAPE = 1;
66975c49f182d754dfe1a38ba0457d6e603b125570John Hoford
67975c49f182d754dfe1a38ba0457d6e603b125570John Hoford    /**
68975c49f182d754dfe1a38ba0457d6e603b125570John Hoford     * select portrait
69975c49f182d754dfe1a38ba0457d6e603b125570John Hoford     */
70975c49f182d754dfe1a38ba0457d6e603b125570John Hoford    public static final int ORIENTATION_PORTRAIT = 2;
71975c49f182d754dfe1a38ba0457d6e603b125570John Hoford
72975c49f182d754dfe1a38ba0457d6e603b125570John Hoford    /**
7309ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov     * this is a black and white image
7409ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov     */
7509ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov    public static final int COLOR_MODE_MONOCHROME = 1;
7609ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov    /**
7709ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov     * this is a color image (default)
7809ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov     */
7909ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov    public static final int COLOR_MODE_COLOR = 2;
8009ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov
81b4eb9c984f1c6ac8007c74fab239437cf9f6b474Svet Ganov    public interface OnPrintFinishCallback {
82b4eb9c984f1c6ac8007c74fab239437cf9f6b474Svet Ganov        public void onFinish();
83b4eb9c984f1c6ac8007c74fab239437cf9f6b474Svet Ganov    }
84b4eb9c984f1c6ac8007c74fab239437cf9f6b474Svet Ganov
85b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav    int mScaleMode = SCALE_MODE_FILL;
86b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav
8709ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov    int mColorMode = COLOR_MODE_COLOR;
8809ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov
89975c49f182d754dfe1a38ba0457d6e603b125570John Hoford    int mOrientation = ORIENTATION_LANDSCAPE;
90975c49f182d754dfe1a38ba0457d6e603b125570John Hoford
91b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav    PrintHelperKitkat(Context context) {
92b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav        mContext = context;
93b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav    }
94b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav
95b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav    /**
96b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav     * Selects whether the image will fill the paper and be cropped
97975c49f182d754dfe1a38ba0457d6e603b125570John Hoford     * <p/>
98b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav     * {@link #SCALE_MODE_FIT}
99b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav     * or whether the image will be scaled but leave white space
100b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav     * {@link #SCALE_MODE_FILL}.
101b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav     *
102b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav     * @param scaleMode {@link #SCALE_MODE_FIT} or
103b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav     *                  {@link #SCALE_MODE_FILL}
104b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav     */
105b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav    public void setScaleMode(int scaleMode) {
106b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav        mScaleMode = scaleMode;
107b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav    }
108b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav
109b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav    /**
110b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav     * Returns the scale mode with which the image will fill the paper.
111b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav     *
112b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav     * @return The scale Mode: {@link #SCALE_MODE_FIT} or
113b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav     * {@link #SCALE_MODE_FILL}
114b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav     */
115b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav    public int getScaleMode() {
116b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav        return mScaleMode;
117b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav    }
118b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav
119b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav    /**
12009ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov     * Sets whether the image will be printed in color (default)
12109ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov     * {@link #COLOR_MODE_COLOR} or in back and white
12209ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov     * {@link #COLOR_MODE_MONOCHROME}.
12309ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov     *
12409ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov     * @param colorMode The color mode which is one of
125975c49f182d754dfe1a38ba0457d6e603b125570John Hoford     *                  {@link #COLOR_MODE_COLOR} and {@link #COLOR_MODE_MONOCHROME}.
12609ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov     */
12709ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov    public void setColorMode(int colorMode) {
12809ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov        mColorMode = colorMode;
12909ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov    }
13009ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov
13109ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov    /**
132975c49f182d754dfe1a38ba0457d6e603b125570John Hoford     * Sets whether to select landscape (default), {@link #ORIENTATION_LANDSCAPE}
133975c49f182d754dfe1a38ba0457d6e603b125570John Hoford     * or portrait {@link #ORIENTATION_PORTRAIT}
134975c49f182d754dfe1a38ba0457d6e603b125570John Hoford     * @param orientation The page orientation which is one of
135975c49f182d754dfe1a38ba0457d6e603b125570John Hoford     *                    {@link #ORIENTATION_LANDSCAPE} or {@link #ORIENTATION_PORTRAIT}.
136975c49f182d754dfe1a38ba0457d6e603b125570John Hoford     */
137975c49f182d754dfe1a38ba0457d6e603b125570John Hoford    public void setOrientation(int orientation) {
138975c49f182d754dfe1a38ba0457d6e603b125570John Hoford        mOrientation = orientation;
139975c49f182d754dfe1a38ba0457d6e603b125570John Hoford    }
140975c49f182d754dfe1a38ba0457d6e603b125570John Hoford
141975c49f182d754dfe1a38ba0457d6e603b125570John Hoford    /**
142975c49f182d754dfe1a38ba0457d6e603b125570John Hoford     * Gets the page orientation with which the image will be printed.
143975c49f182d754dfe1a38ba0457d6e603b125570John Hoford     *
144975c49f182d754dfe1a38ba0457d6e603b125570John Hoford     * @return The preferred orientation which is one of
145975c49f182d754dfe1a38ba0457d6e603b125570John Hoford     * {@link #ORIENTATION_LANDSCAPE} or {@link #ORIENTATION_PORTRAIT}
146975c49f182d754dfe1a38ba0457d6e603b125570John Hoford     */
147975c49f182d754dfe1a38ba0457d6e603b125570John Hoford    public int getOrientation() {
148975c49f182d754dfe1a38ba0457d6e603b125570John Hoford        return mOrientation;
149975c49f182d754dfe1a38ba0457d6e603b125570John Hoford    }
150975c49f182d754dfe1a38ba0457d6e603b125570John Hoford
151975c49f182d754dfe1a38ba0457d6e603b125570John Hoford    /**
15209ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov     * Gets the color mode with which the image will be printed.
15309ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov     *
15409ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov     * @return The color mode which is one of {@link #COLOR_MODE_COLOR}
15509ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov     * and {@link #COLOR_MODE_MONOCHROME}.
15609ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov     */
15709ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov    public int getColorMode() {
15809ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov        return mColorMode;
15909ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov    }
16009ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov
16109ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov    /**
162b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav     * Prints a bitmap.
163b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav     *
164b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav     * @param jobName The print job name.
165b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav     * @param bitmap  The bitmap to print.
166b4eb9c984f1c6ac8007c74fab239437cf9f6b474Svet Ganov     * @param callback Optional callback to observe when printing is finished.
167b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav     */
168b4eb9c984f1c6ac8007c74fab239437cf9f6b474Svet Ganov    public void printBitmap(final String jobName, final Bitmap bitmap,
169b4eb9c984f1c6ac8007c74fab239437cf9f6b474Svet Ganov            final OnPrintFinishCallback callback) {
170b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav        if (bitmap == null) {
171b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav            return;
172b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav        }
173b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav        final int fittingMode = mScaleMode; // grab the fitting mode at time of call
174b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav        PrintManager printManager = (PrintManager) mContext.getSystemService(Context.PRINT_SERVICE);
175b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav        PrintAttributes.MediaSize mediaSize = PrintAttributes.MediaSize.UNKNOWN_PORTRAIT;
176b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav        if (bitmap.getWidth() > bitmap.getHeight()) {
177b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav            mediaSize = PrintAttributes.MediaSize.UNKNOWN_LANDSCAPE;
178b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav        }
17909ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov        PrintAttributes attr = new PrintAttributes.Builder()
18009ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov                .setMediaSize(mediaSize)
18109ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov                .setColorMode(mColorMode)
18209ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov                .build();
183b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav
184b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav        printManager.print(jobName,
185b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav                new PrintDocumentAdapter() {
186b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav                    private PrintAttributes mAttributes;
187b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav
188b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav                    @Override
189b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav                    public void onLayout(PrintAttributes oldPrintAttributes,
190b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav                                         PrintAttributes newPrintAttributes,
191b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav                                         CancellationSignal cancellationSignal,
192b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav                                         LayoutResultCallback layoutResultCallback,
193b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav                                         Bundle bundle) {
194b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav
195b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav                        mAttributes = newPrintAttributes;
196b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav
197b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav                        PrintDocumentInfo info = new PrintDocumentInfo.Builder(jobName)
198b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav                                .setContentType(PrintDocumentInfo.CONTENT_TYPE_PHOTO)
199b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav                                .setPageCount(1)
200b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav                                .build();
201b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav                        boolean changed = !newPrintAttributes.equals(oldPrintAttributes);
202b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav                        layoutResultCallback.onLayoutFinished(info, changed);
203b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav                    }
204b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav
205b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav                    @Override
206b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav                    public void onWrite(PageRange[] pageRanges, ParcelFileDescriptor fileDescriptor,
207b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav                                        CancellationSignal cancellationSignal,
208b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav                                        WriteResultCallback writeResultCallback) {
209b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav                        PrintedPdfDocument pdfDocument = new PrintedPdfDocument(mContext,
210b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav                                mAttributes);
211b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav                        try {
212b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav                            Page page = pdfDocument.startPage(1);
213b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav
214b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav                            RectF content = new RectF(page.getInfo().getContentRect());
215b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav
216975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                            Matrix matrix = getMatrix(bitmap.getWidth(), bitmap.getHeight(),
217975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                                    content, fittingMode);
218b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav
219b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav                            // Draw the bitmap.
220b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav                            page.getCanvas().drawBitmap(bitmap, matrix, null);
221b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav
222b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav                            // Finish the page.
223b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav                            pdfDocument.finishPage(page);
224b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav
225b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav                            try {
226b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav                                // Write the document.
227b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav                                pdfDocument.writeTo(new FileOutputStream(
228b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav                                        fileDescriptor.getFileDescriptor()));
229b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav                                // Done.
230b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav                                writeResultCallback.onWriteFinished(
231b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav                                        new PageRange[]{PageRange.ALL_PAGES});
232b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav                            } catch (IOException ioe) {
233b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav                                // Failed.
234b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav                                Log.e(LOG_TAG, "Error writing printed content", ioe);
235b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav                                writeResultCallback.onWriteFailed(null);
236b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav                            }
237b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav                        } finally {
238b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav                            if (pdfDocument != null) {
239b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav                                pdfDocument.close();
240b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav                            }
241b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav                            if (fileDescriptor != null) {
242b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav                                try {
243b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav                                    fileDescriptor.close();
244b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav                                } catch (IOException ioe) {
245b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav                                    /* ignore */
246b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav                                }
247b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav                            }
248b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav                        }
249b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav                    }
250b4eb9c984f1c6ac8007c74fab239437cf9f6b474Svet Ganov
251b4eb9c984f1c6ac8007c74fab239437cf9f6b474Svet Ganov                    @Override
252b4eb9c984f1c6ac8007c74fab239437cf9f6b474Svet Ganov                    public void onFinish() {
253b4eb9c984f1c6ac8007c74fab239437cf9f6b474Svet Ganov                        if (callback != null) {
254b4eb9c984f1c6ac8007c74fab239437cf9f6b474Svet Ganov                            callback.onFinish();
255b4eb9c984f1c6ac8007c74fab239437cf9f6b474Svet Ganov                        }
256b4eb9c984f1c6ac8007c74fab239437cf9f6b474Svet Ganov                    }
257b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav                }, attr);
258b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav    }
259b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav
260b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav    /**
261975c49f182d754dfe1a38ba0457d6e603b125570John Hoford     * Calculates the transform the print an Image to fill the page
262975c49f182d754dfe1a38ba0457d6e603b125570John Hoford     *
263975c49f182d754dfe1a38ba0457d6e603b125570John Hoford     * @param imageWidth  with of bitmap
264975c49f182d754dfe1a38ba0457d6e603b125570John Hoford     * @param imageHeight height of bitmap
265975c49f182d754dfe1a38ba0457d6e603b125570John Hoford     * @param content     The output page dimensions
266975c49f182d754dfe1a38ba0457d6e603b125570John Hoford     * @param fittingMode The mode of fitting {@link #SCALE_MODE_FILL} vs {@link #SCALE_MODE_FIT}
267975c49f182d754dfe1a38ba0457d6e603b125570John Hoford     * @return Matrix to be used in canvas.drawBitmap(bitmap, matrix, null) call
268975c49f182d754dfe1a38ba0457d6e603b125570John Hoford     */
269975c49f182d754dfe1a38ba0457d6e603b125570John Hoford    private Matrix getMatrix(int imageWidth, int imageHeight, RectF content, int fittingMode) {
270975c49f182d754dfe1a38ba0457d6e603b125570John Hoford        Matrix matrix = new Matrix();
271975c49f182d754dfe1a38ba0457d6e603b125570John Hoford
272975c49f182d754dfe1a38ba0457d6e603b125570John Hoford        // Compute and apply scale to fill the page.
273975c49f182d754dfe1a38ba0457d6e603b125570John Hoford        float scale = content.width() / imageWidth;
274975c49f182d754dfe1a38ba0457d6e603b125570John Hoford        if (fittingMode == SCALE_MODE_FILL) {
275975c49f182d754dfe1a38ba0457d6e603b125570John Hoford            scale = Math.max(scale, content.height() / imageHeight);
276975c49f182d754dfe1a38ba0457d6e603b125570John Hoford        } else {
277975c49f182d754dfe1a38ba0457d6e603b125570John Hoford            scale = Math.min(scale, content.height() / imageHeight);
278975c49f182d754dfe1a38ba0457d6e603b125570John Hoford        }
279975c49f182d754dfe1a38ba0457d6e603b125570John Hoford        matrix.postScale(scale, scale);
280975c49f182d754dfe1a38ba0457d6e603b125570John Hoford
281975c49f182d754dfe1a38ba0457d6e603b125570John Hoford        // Center the content.
282975c49f182d754dfe1a38ba0457d6e603b125570John Hoford        final float translateX = (content.width()
283975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                - imageWidth * scale) / 2;
284975c49f182d754dfe1a38ba0457d6e603b125570John Hoford        final float translateY = (content.height()
285975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                - imageHeight * scale) / 2;
286975c49f182d754dfe1a38ba0457d6e603b125570John Hoford        matrix.postTranslate(translateX, translateY);
287975c49f182d754dfe1a38ba0457d6e603b125570John Hoford        return matrix;
288975c49f182d754dfe1a38ba0457d6e603b125570John Hoford    }
289975c49f182d754dfe1a38ba0457d6e603b125570John Hoford
290975c49f182d754dfe1a38ba0457d6e603b125570John Hoford    /**
291b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav     * Prints an image located at the Uri. Image types supported are those of
292b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav     * <code>BitmapFactory.decodeStream</code> (JPEG, GIF, PNG, BMP, WEBP)
293b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav     *
294b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav     * @param jobName   The print job name.
295b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav     * @param imageFile The <code>Uri</code> pointing to an image to print.
296b4eb9c984f1c6ac8007c74fab239437cf9f6b474Svet Ganov     * @param callback Optional callback to observe when printing is finished.
297b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav     * @throws FileNotFoundException if <code>Uri</code> is not pointing to a valid image.
298b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav     */
299b4eb9c984f1c6ac8007c74fab239437cf9f6b474Svet Ganov    public void printBitmap(final String jobName, final Uri imageFile,
300b4eb9c984f1c6ac8007c74fab239437cf9f6b474Svet Ganov            final OnPrintFinishCallback callback) throws FileNotFoundException {
301975c49f182d754dfe1a38ba0457d6e603b125570John Hoford        final int fittingMode = mScaleMode;
302975c49f182d754dfe1a38ba0457d6e603b125570John Hoford
303975c49f182d754dfe1a38ba0457d6e603b125570John Hoford        PrintDocumentAdapter printDocumentAdapter = new PrintDocumentAdapter() {
304975c49f182d754dfe1a38ba0457d6e603b125570John Hoford            private PrintAttributes mAttributes;
305854aed9e83ca17ad558f3aec7fff49ef2153ceafSvetoslav            AsyncTask<Uri, Boolean, Bitmap> mLoadBitmap;
306975c49f182d754dfe1a38ba0457d6e603b125570John Hoford            Bitmap mBitmap = null;
307975c49f182d754dfe1a38ba0457d6e603b125570John Hoford
308975c49f182d754dfe1a38ba0457d6e603b125570John Hoford            @Override
309975c49f182d754dfe1a38ba0457d6e603b125570John Hoford            public void onLayout(final PrintAttributes oldPrintAttributes,
310975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                                 final PrintAttributes newPrintAttributes,
311975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                                 final CancellationSignal cancellationSignal,
312975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                                 final LayoutResultCallback layoutResultCallback,
313975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                                 Bundle bundle) {
314854aed9e83ca17ad558f3aec7fff49ef2153ceafSvetoslav
315854aed9e83ca17ad558f3aec7fff49ef2153ceafSvetoslav                mAttributes = newPrintAttributes;
316854aed9e83ca17ad558f3aec7fff49ef2153ceafSvetoslav
317975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                if (cancellationSignal.isCanceled()) {
318975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                    layoutResultCallback.onLayoutCancelled();
319975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                    return;
320975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                }
321975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                // we finished the load
322975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                if (mBitmap != null) {
323975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                    PrintDocumentInfo info = new PrintDocumentInfo.Builder(jobName)
324975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                            .setContentType(PrintDocumentInfo.CONTENT_TYPE_PHOTO)
325975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                            .setPageCount(1)
326975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                            .build();
327975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                    boolean changed = !newPrintAttributes.equals(oldPrintAttributes);
328975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                    layoutResultCallback.onLayoutFinished(info, changed);
329975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                    return;
330975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                }
331975c49f182d754dfe1a38ba0457d6e603b125570John Hoford
332854aed9e83ca17ad558f3aec7fff49ef2153ceafSvetoslav                mLoadBitmap = new AsyncTask<Uri, Boolean, Bitmap>() {
333975c49f182d754dfe1a38ba0457d6e603b125570John Hoford
334975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                    @Override
335975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                    protected void onPreExecute() {
336975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                        // First register for cancellation requests.
337975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                        cancellationSignal.setOnCancelListener(
338975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                                new CancellationSignal.OnCancelListener() {
339975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                                    @Override
340975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                                    public void onCancel() { // on different thread
341975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                                        cancelLoad();
342975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                                        cancel(false);
343975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                                    }
344975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                                });
345975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                    }
346975c49f182d754dfe1a38ba0457d6e603b125570John Hoford
347975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                    @Override
348975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                    protected Bitmap doInBackground(Uri... uris) {
349975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                        try {
350975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                            return loadConstrainedBitmap(imageFile, MAX_PRINT_SIZE);
351975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                        } catch (FileNotFoundException e) {
352975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                          /* ignore */
353975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                        }
354975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                        return null;
355975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                    }
356975c49f182d754dfe1a38ba0457d6e603b125570John Hoford
357975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                    @Override
358975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                    protected void onPostExecute(Bitmap bitmap) {
359975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                        super.onPostExecute(bitmap);
360975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                        mBitmap = bitmap;
361975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                        if (bitmap != null) {
362975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                            PrintDocumentInfo info = new PrintDocumentInfo.Builder(jobName)
363975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                                    .setContentType(PrintDocumentInfo.CONTENT_TYPE_PHOTO)
364975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                                    .setPageCount(1)
365975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                                    .build();
366975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                            boolean changed = !newPrintAttributes.equals(oldPrintAttributes);
367975c49f182d754dfe1a38ba0457d6e603b125570John Hoford
368975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                            layoutResultCallback.onLayoutFinished(info, changed);
369975c49f182d754dfe1a38ba0457d6e603b125570John Hoford
370975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                        } else {
371975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                            layoutResultCallback.onLayoutFailed(null);
372975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                        }
373854aed9e83ca17ad558f3aec7fff49ef2153ceafSvetoslav                        mLoadBitmap = null;
374975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                    }
375975c49f182d754dfe1a38ba0457d6e603b125570John Hoford
376975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                    @Override
377975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                    protected void onCancelled(Bitmap result) {
378975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                        // Task was cancelled, report that.
379975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                        layoutResultCallback.onLayoutCancelled();
380854aed9e83ca17ad558f3aec7fff49ef2153ceafSvetoslav                        mLoadBitmap = null;
381975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                    }
382854aed9e83ca17ad558f3aec7fff49ef2153ceafSvetoslav                }.execute();
383975c49f182d754dfe1a38ba0457d6e603b125570John Hoford            }
384975c49f182d754dfe1a38ba0457d6e603b125570John Hoford
385975c49f182d754dfe1a38ba0457d6e603b125570John Hoford            private void cancelLoad() {
386975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                synchronized (mLock) { // prevent race with set null below
387975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                    if (mDecodeOptions != null) {
388975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                        mDecodeOptions.requestCancelDecode();
389975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                        mDecodeOptions = null;
390975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                    }
391975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                }
392975c49f182d754dfe1a38ba0457d6e603b125570John Hoford            }
393975c49f182d754dfe1a38ba0457d6e603b125570John Hoford
394975c49f182d754dfe1a38ba0457d6e603b125570John Hoford            @Override
395975c49f182d754dfe1a38ba0457d6e603b125570John Hoford            public void onFinish() {
396975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                super.onFinish();
397975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                cancelLoad();
398854aed9e83ca17ad558f3aec7fff49ef2153ceafSvetoslav                if (mLoadBitmap != null) {
399854aed9e83ca17ad558f3aec7fff49ef2153ceafSvetoslav                    mLoadBitmap.cancel(true);
400854aed9e83ca17ad558f3aec7fff49ef2153ceafSvetoslav                }
401b4eb9c984f1c6ac8007c74fab239437cf9f6b474Svet Ganov                if (callback != null) {
402b4eb9c984f1c6ac8007c74fab239437cf9f6b474Svet Ganov                    callback.onFinish();
403b4eb9c984f1c6ac8007c74fab239437cf9f6b474Svet Ganov                }
404975c49f182d754dfe1a38ba0457d6e603b125570John Hoford            }
405975c49f182d754dfe1a38ba0457d6e603b125570John Hoford
406975c49f182d754dfe1a38ba0457d6e603b125570John Hoford            @Override
407975c49f182d754dfe1a38ba0457d6e603b125570John Hoford            public void onWrite(PageRange[] pageRanges, ParcelFileDescriptor fileDescriptor,
408975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                                CancellationSignal cancellationSignal,
409975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                                WriteResultCallback writeResultCallback) {
410975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                PrintedPdfDocument pdfDocument = new PrintedPdfDocument(mContext,
411975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                        mAttributes);
412975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                try {
413975c49f182d754dfe1a38ba0457d6e603b125570John Hoford
414975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                    Page page = pdfDocument.startPage(1);
415975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                    RectF content = new RectF(page.getInfo().getContentRect());
416975c49f182d754dfe1a38ba0457d6e603b125570John Hoford
417975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                    // Compute and apply scale to fill the page.
418975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                    Matrix matrix = getMatrix(mBitmap.getWidth(), mBitmap.getHeight(),
419975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                            content, fittingMode);
420975c49f182d754dfe1a38ba0457d6e603b125570John Hoford
421975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                    // Draw the bitmap.
422975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                    page.getCanvas().drawBitmap(mBitmap, matrix, null);
423975c49f182d754dfe1a38ba0457d6e603b125570John Hoford
424975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                    // Finish the page.
425975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                    pdfDocument.finishPage(page);
426975c49f182d754dfe1a38ba0457d6e603b125570John Hoford
427975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                    try {
428975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                        // Write the document.
429975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                        pdfDocument.writeTo(new FileOutputStream(
430975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                                fileDescriptor.getFileDescriptor()));
431975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                        // Done.
432975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                        writeResultCallback.onWriteFinished(
433975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                                new PageRange[]{PageRange.ALL_PAGES});
434975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                    } catch (IOException ioe) {
435975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                        // Failed.
436975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                        Log.e(LOG_TAG, "Error writing printed content", ioe);
437975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                        writeResultCallback.onWriteFailed(null);
438975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                    }
439975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                } finally {
440975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                    if (pdfDocument != null) {
441975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                        pdfDocument.close();
442975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                    }
443975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                    if (fileDescriptor != null) {
444975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                        try {
445975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                            fileDescriptor.close();
446975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                        } catch (IOException ioe) {
447975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                            /* ignore */
448975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                        }
449975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                    }
450975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                }
451975c49f182d754dfe1a38ba0457d6e603b125570John Hoford            }
452975c49f182d754dfe1a38ba0457d6e603b125570John Hoford        };
453975c49f182d754dfe1a38ba0457d6e603b125570John Hoford
454975c49f182d754dfe1a38ba0457d6e603b125570John Hoford        PrintManager printManager = (PrintManager) mContext.getSystemService(Context.PRINT_SERVICE);
455975c49f182d754dfe1a38ba0457d6e603b125570John Hoford        PrintAttributes.Builder builder = new PrintAttributes.Builder();
456975c49f182d754dfe1a38ba0457d6e603b125570John Hoford        builder.setColorMode(mColorMode);
457975c49f182d754dfe1a38ba0457d6e603b125570John Hoford
458975c49f182d754dfe1a38ba0457d6e603b125570John Hoford        if (mOrientation == ORIENTATION_LANDSCAPE) {
459975c49f182d754dfe1a38ba0457d6e603b125570John Hoford            builder.setMediaSize(PrintAttributes.MediaSize.UNKNOWN_LANDSCAPE);
460975c49f182d754dfe1a38ba0457d6e603b125570John Hoford        } else if (mOrientation == ORIENTATION_PORTRAIT) {
461975c49f182d754dfe1a38ba0457d6e603b125570John Hoford            builder.setMediaSize(PrintAttributes.MediaSize.UNKNOWN_PORTRAIT);
462975c49f182d754dfe1a38ba0457d6e603b125570John Hoford        }
463975c49f182d754dfe1a38ba0457d6e603b125570John Hoford        PrintAttributes attr = builder.build();
464975c49f182d754dfe1a38ba0457d6e603b125570John Hoford
465975c49f182d754dfe1a38ba0457d6e603b125570John Hoford        printManager.print(jobName, printDocumentAdapter, attr);
466b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav    }
467b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav
468b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav    /**
469b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav     * Loads a bitmap while limiting its size
470b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav     *
471b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav     * @param uri           location of a valid image
472b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav     * @param maxSideLength the maximum length of a size
473b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav     * @return the Bitmap
474b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav     * @throws FileNotFoundException if the Uri does not point to an image
475b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav     */
476b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav    private Bitmap loadConstrainedBitmap(Uri uri, int maxSideLength) throws FileNotFoundException {
477b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav        if (maxSideLength <= 0 || uri == null || mContext == null) {
478b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav            throw new IllegalArgumentException("bad argument to getScaledBitmap");
479b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav        }
480b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav        // Get width and height of stored bitmap
481b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav        BitmapFactory.Options opt = new BitmapFactory.Options();
482b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav        opt.inJustDecodeBounds = true;
483b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav        loadBitmap(uri, opt);
484b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav
485b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav        int w = opt.outWidth;
486b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav        int h = opt.outHeight;
487b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav
488b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav        // If bitmap cannot be decoded, return null
489b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav        if (w <= 0 || h <= 0) {
490b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav            return null;
491b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav        }
492b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav
493b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav        // Find best downsampling size
494b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav        int imageSide = Math.max(w, h);
495b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav
496b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav        int sampleSize = 1;
497b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav        while (imageSide > maxSideLength) {
498b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav            imageSide >>>= 1;
499b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav            sampleSize <<= 1;
500b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav        }
501b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav
502b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav        // Make sure sample size is reasonable
503b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav        if (sampleSize <= 0 || 0 >= (int) (Math.min(w, h) / sampleSize)) {
504b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav            return null;
505b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav        }
506975c49f182d754dfe1a38ba0457d6e603b125570John Hoford        BitmapFactory.Options decodeOptions = null;
507975c49f182d754dfe1a38ba0457d6e603b125570John Hoford        synchronized (mLock) { // prevent race with set null below
508975c49f182d754dfe1a38ba0457d6e603b125570John Hoford            mDecodeOptions = new BitmapFactory.Options();
509975c49f182d754dfe1a38ba0457d6e603b125570John Hoford            mDecodeOptions.inMutable = true;
510975c49f182d754dfe1a38ba0457d6e603b125570John Hoford            mDecodeOptions.inSampleSize = sampleSize;
511975c49f182d754dfe1a38ba0457d6e603b125570John Hoford            decodeOptions = mDecodeOptions;
512975c49f182d754dfe1a38ba0457d6e603b125570John Hoford        }
513975c49f182d754dfe1a38ba0457d6e603b125570John Hoford        try {
514975c49f182d754dfe1a38ba0457d6e603b125570John Hoford            return loadBitmap(uri, decodeOptions);
515975c49f182d754dfe1a38ba0457d6e603b125570John Hoford        } finally {
516975c49f182d754dfe1a38ba0457d6e603b125570John Hoford            synchronized (mLock) {
517975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                mDecodeOptions = null;
518975c49f182d754dfe1a38ba0457d6e603b125570John Hoford            }
519975c49f182d754dfe1a38ba0457d6e603b125570John Hoford        }
520b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav    }
521b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav
522b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav    /**
523b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav     * Returns the bitmap from the given uri loaded using the given options.
524b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav     * Returns null on failure.
525b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav     */
526b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav    private Bitmap loadBitmap(Uri uri, BitmapFactory.Options o) throws FileNotFoundException {
527b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav        if (uri == null || mContext == null) {
528b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav            throw new IllegalArgumentException("bad argument to loadBitmap");
529b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav        }
530b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav        InputStream is = null;
531b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav        try {
532b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav            is = mContext.getContentResolver().openInputStream(uri);
533b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav            return BitmapFactory.decodeStream(is, null, o);
534b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav        } finally {
535545f1bf8b47c12d2453143706a2fd76d9eef2368Svetoslav Ganov            if (is != null) {
536545f1bf8b47c12d2453143706a2fd76d9eef2368Svetoslav Ganov                try {
537545f1bf8b47c12d2453143706a2fd76d9eef2368Svetoslav Ganov                    is.close();
538545f1bf8b47c12d2453143706a2fd76d9eef2368Svetoslav Ganov                } catch (IOException t) {
539545f1bf8b47c12d2453143706a2fd76d9eef2368Svetoslav Ganov                    Log.w(LOG_TAG, "close fail ", t);
540545f1bf8b47c12d2453143706a2fd76d9eef2368Svetoslav Ganov                }
541b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav            }
542b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav        }
543b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav    }
544b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav}