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
81b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav    int mScaleMode = SCALE_MODE_FILL;
82b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav
8309ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov    int mColorMode = COLOR_MODE_COLOR;
8409ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov
85975c49f182d754dfe1a38ba0457d6e603b125570John Hoford    int mOrientation = ORIENTATION_LANDSCAPE;
86975c49f182d754dfe1a38ba0457d6e603b125570John Hoford
87b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav    PrintHelperKitkat(Context context) {
88b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav        mContext = context;
89b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav    }
90b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav
91b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav    /**
92b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav     * Selects whether the image will fill the paper and be cropped
93975c49f182d754dfe1a38ba0457d6e603b125570John Hoford     * <p/>
94b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav     * {@link #SCALE_MODE_FIT}
95b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav     * or whether the image will be scaled but leave white space
96b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav     * {@link #SCALE_MODE_FILL}.
97b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav     *
98b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav     * @param scaleMode {@link #SCALE_MODE_FIT} or
99b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav     *                  {@link #SCALE_MODE_FILL}
100b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav     */
101b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav    public void setScaleMode(int scaleMode) {
102b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav        mScaleMode = scaleMode;
103b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav    }
104b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav
105b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav    /**
106b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav     * Returns the scale mode with which the image will fill the paper.
107b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav     *
108b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav     * @return The scale Mode: {@link #SCALE_MODE_FIT} or
109b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav     * {@link #SCALE_MODE_FILL}
110b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav     */
111b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav    public int getScaleMode() {
112b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav        return mScaleMode;
113b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav    }
114b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav
115b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav    /**
11609ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov     * Sets whether the image will be printed in color (default)
11709ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov     * {@link #COLOR_MODE_COLOR} or in back and white
11809ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov     * {@link #COLOR_MODE_MONOCHROME}.
11909ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov     *
12009ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov     * @param colorMode The color mode which is one of
121975c49f182d754dfe1a38ba0457d6e603b125570John Hoford     *                  {@link #COLOR_MODE_COLOR} and {@link #COLOR_MODE_MONOCHROME}.
12209ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov     */
12309ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov    public void setColorMode(int colorMode) {
12409ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov        mColorMode = colorMode;
12509ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov    }
12609ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov
12709ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov    /**
128975c49f182d754dfe1a38ba0457d6e603b125570John Hoford     * Sets whether to select landscape (default), {@link #ORIENTATION_LANDSCAPE}
129975c49f182d754dfe1a38ba0457d6e603b125570John Hoford     * or portrait {@link #ORIENTATION_PORTRAIT}
130975c49f182d754dfe1a38ba0457d6e603b125570John Hoford     * @param orientation The page orientation which is one of
131975c49f182d754dfe1a38ba0457d6e603b125570John Hoford     *                    {@link #ORIENTATION_LANDSCAPE} or {@link #ORIENTATION_PORTRAIT}.
132975c49f182d754dfe1a38ba0457d6e603b125570John Hoford     */
133975c49f182d754dfe1a38ba0457d6e603b125570John Hoford    public void setOrientation(int orientation) {
134975c49f182d754dfe1a38ba0457d6e603b125570John Hoford        mOrientation = orientation;
135975c49f182d754dfe1a38ba0457d6e603b125570John Hoford    }
136975c49f182d754dfe1a38ba0457d6e603b125570John Hoford
137975c49f182d754dfe1a38ba0457d6e603b125570John Hoford    /**
138975c49f182d754dfe1a38ba0457d6e603b125570John Hoford     * Gets the page orientation with which the image will be printed.
139975c49f182d754dfe1a38ba0457d6e603b125570John Hoford     *
140975c49f182d754dfe1a38ba0457d6e603b125570John Hoford     * @return The preferred orientation which is one of
141975c49f182d754dfe1a38ba0457d6e603b125570John Hoford     * {@link #ORIENTATION_LANDSCAPE} or {@link #ORIENTATION_PORTRAIT}
142975c49f182d754dfe1a38ba0457d6e603b125570John Hoford     */
143975c49f182d754dfe1a38ba0457d6e603b125570John Hoford    public int getOrientation() {
144975c49f182d754dfe1a38ba0457d6e603b125570John Hoford        return mOrientation;
145975c49f182d754dfe1a38ba0457d6e603b125570John Hoford    }
146975c49f182d754dfe1a38ba0457d6e603b125570John Hoford
147975c49f182d754dfe1a38ba0457d6e603b125570John Hoford    /**
14809ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov     * Gets the color mode with which the image will be printed.
14909ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov     *
15009ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov     * @return The color mode which is one of {@link #COLOR_MODE_COLOR}
15109ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov     * and {@link #COLOR_MODE_MONOCHROME}.
15209ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov     */
15309ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov    public int getColorMode() {
15409ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov        return mColorMode;
15509ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov    }
15609ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov
15709ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov    /**
158b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav     * Prints a bitmap.
159b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav     *
160b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav     * @param jobName The print job name.
161b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav     * @param bitmap  The bitmap to print.
162b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav     */
163b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav    public void printBitmap(final String jobName, final Bitmap bitmap) {
164b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav        if (bitmap == null) {
165b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav            return;
166b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav        }
167b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav        final int fittingMode = mScaleMode; // grab the fitting mode at time of call
168b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav        PrintManager printManager = (PrintManager) mContext.getSystemService(Context.PRINT_SERVICE);
169b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav        PrintAttributes.MediaSize mediaSize = PrintAttributes.MediaSize.UNKNOWN_PORTRAIT;
170b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav        if (bitmap.getWidth() > bitmap.getHeight()) {
171b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav            mediaSize = PrintAttributes.MediaSize.UNKNOWN_LANDSCAPE;
172b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav        }
17309ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov        PrintAttributes attr = new PrintAttributes.Builder()
17409ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov                .setMediaSize(mediaSize)
17509ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov                .setColorMode(mColorMode)
17609ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov                .build();
177b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav
178b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav        printManager.print(jobName,
179b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav                new PrintDocumentAdapter() {
180b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav                    private PrintAttributes mAttributes;
181b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav
182b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav                    @Override
183b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav                    public void onLayout(PrintAttributes oldPrintAttributes,
184b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav                                         PrintAttributes newPrintAttributes,
185b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav                                         CancellationSignal cancellationSignal,
186b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav                                         LayoutResultCallback layoutResultCallback,
187b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav                                         Bundle bundle) {
188b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav
189b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav                        mAttributes = newPrintAttributes;
190b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav
191b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav                        PrintDocumentInfo info = new PrintDocumentInfo.Builder(jobName)
192b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav                                .setContentType(PrintDocumentInfo.CONTENT_TYPE_PHOTO)
193b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav                                .setPageCount(1)
194b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav                                .build();
195b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav                        boolean changed = !newPrintAttributes.equals(oldPrintAttributes);
196b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav                        layoutResultCallback.onLayoutFinished(info, changed);
197b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav                    }
198b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav
199b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav                    @Override
200b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav                    public void onWrite(PageRange[] pageRanges, ParcelFileDescriptor fileDescriptor,
201b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav                                        CancellationSignal cancellationSignal,
202b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav                                        WriteResultCallback writeResultCallback) {
203b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav                        PrintedPdfDocument pdfDocument = new PrintedPdfDocument(mContext,
204b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav                                mAttributes);
205b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav                        try {
206b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav                            Page page = pdfDocument.startPage(1);
207b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav
208b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav                            RectF content = new RectF(page.getInfo().getContentRect());
209b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav
210975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                            Matrix matrix = getMatrix(bitmap.getWidth(), bitmap.getHeight(),
211975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                                    content, fittingMode);
212b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav
213b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav                            // Draw the bitmap.
214b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav                            page.getCanvas().drawBitmap(bitmap, matrix, null);
215b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav
216b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav                            // Finish the page.
217b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav                            pdfDocument.finishPage(page);
218b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav
219b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav                            try {
220b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav                                // Write the document.
221b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav                                pdfDocument.writeTo(new FileOutputStream(
222b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav                                        fileDescriptor.getFileDescriptor()));
223b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav                                // Done.
224b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav                                writeResultCallback.onWriteFinished(
225b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav                                        new PageRange[]{PageRange.ALL_PAGES});
226b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav                            } catch (IOException ioe) {
227b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav                                // Failed.
228b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav                                Log.e(LOG_TAG, "Error writing printed content", ioe);
229b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav                                writeResultCallback.onWriteFailed(null);
230b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav                            }
231b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav                        } finally {
232b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav                            if (pdfDocument != null) {
233b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav                                pdfDocument.close();
234b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav                            }
235b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav                            if (fileDescriptor != null) {
236b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav                                try {
237b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav                                    fileDescriptor.close();
238b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav                                } catch (IOException ioe) {
239b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav                                    /* ignore */
240b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav                                }
241b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav                            }
242b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav                        }
243b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav                    }
244b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav                }, attr);
245b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav    }
246b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav
247b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav    /**
248975c49f182d754dfe1a38ba0457d6e603b125570John Hoford     * Calculates the transform the print an Image to fill the page
249975c49f182d754dfe1a38ba0457d6e603b125570John Hoford     *
250975c49f182d754dfe1a38ba0457d6e603b125570John Hoford     * @param imageWidth  with of bitmap
251975c49f182d754dfe1a38ba0457d6e603b125570John Hoford     * @param imageHeight height of bitmap
252975c49f182d754dfe1a38ba0457d6e603b125570John Hoford     * @param content     The output page dimensions
253975c49f182d754dfe1a38ba0457d6e603b125570John Hoford     * @param fittingMode The mode of fitting {@link #SCALE_MODE_FILL} vs {@link #SCALE_MODE_FIT}
254975c49f182d754dfe1a38ba0457d6e603b125570John Hoford     * @return Matrix to be used in canvas.drawBitmap(bitmap, matrix, null) call
255975c49f182d754dfe1a38ba0457d6e603b125570John Hoford     */
256975c49f182d754dfe1a38ba0457d6e603b125570John Hoford    private Matrix getMatrix(int imageWidth, int imageHeight, RectF content, int fittingMode) {
257975c49f182d754dfe1a38ba0457d6e603b125570John Hoford        Matrix matrix = new Matrix();
258975c49f182d754dfe1a38ba0457d6e603b125570John Hoford
259975c49f182d754dfe1a38ba0457d6e603b125570John Hoford        // Compute and apply scale to fill the page.
260975c49f182d754dfe1a38ba0457d6e603b125570John Hoford        float scale = content.width() / imageWidth;
261975c49f182d754dfe1a38ba0457d6e603b125570John Hoford        if (fittingMode == SCALE_MODE_FILL) {
262975c49f182d754dfe1a38ba0457d6e603b125570John Hoford            scale = Math.max(scale, content.height() / imageHeight);
263975c49f182d754dfe1a38ba0457d6e603b125570John Hoford        } else {
264975c49f182d754dfe1a38ba0457d6e603b125570John Hoford            scale = Math.min(scale, content.height() / imageHeight);
265975c49f182d754dfe1a38ba0457d6e603b125570John Hoford        }
266975c49f182d754dfe1a38ba0457d6e603b125570John Hoford        matrix.postScale(scale, scale);
267975c49f182d754dfe1a38ba0457d6e603b125570John Hoford
268975c49f182d754dfe1a38ba0457d6e603b125570John Hoford        // Center the content.
269975c49f182d754dfe1a38ba0457d6e603b125570John Hoford        final float translateX = (content.width()
270975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                - imageWidth * scale) / 2;
271975c49f182d754dfe1a38ba0457d6e603b125570John Hoford        final float translateY = (content.height()
272975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                - imageHeight * scale) / 2;
273975c49f182d754dfe1a38ba0457d6e603b125570John Hoford        matrix.postTranslate(translateX, translateY);
274975c49f182d754dfe1a38ba0457d6e603b125570John Hoford        return matrix;
275975c49f182d754dfe1a38ba0457d6e603b125570John Hoford    }
276975c49f182d754dfe1a38ba0457d6e603b125570John Hoford
277975c49f182d754dfe1a38ba0457d6e603b125570John Hoford    /**
278b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav     * Prints an image located at the Uri. Image types supported are those of
279b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav     * <code>BitmapFactory.decodeStream</code> (JPEG, GIF, PNG, BMP, WEBP)
280b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav     *
281b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav     * @param jobName   The print job name.
282b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav     * @param imageFile The <code>Uri</code> pointing to an image to print.
283b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav     * @throws FileNotFoundException if <code>Uri</code> is not pointing to a valid image.
284b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav     */
285975c49f182d754dfe1a38ba0457d6e603b125570John Hoford    public void printBitmap(final String jobName, final Uri imageFile)
286975c49f182d754dfe1a38ba0457d6e603b125570John Hoford            throws FileNotFoundException {
287975c49f182d754dfe1a38ba0457d6e603b125570John Hoford        final int fittingMode = mScaleMode;
288975c49f182d754dfe1a38ba0457d6e603b125570John Hoford
289975c49f182d754dfe1a38ba0457d6e603b125570John Hoford        PrintDocumentAdapter printDocumentAdapter = new PrintDocumentAdapter() {
290975c49f182d754dfe1a38ba0457d6e603b125570John Hoford            private PrintAttributes mAttributes;
291975c49f182d754dfe1a38ba0457d6e603b125570John Hoford            AsyncTask<Uri, Boolean, Bitmap> loadBitmap;
292975c49f182d754dfe1a38ba0457d6e603b125570John Hoford            Bitmap mBitmap = null;
293975c49f182d754dfe1a38ba0457d6e603b125570John Hoford
294975c49f182d754dfe1a38ba0457d6e603b125570John Hoford            @Override
295975c49f182d754dfe1a38ba0457d6e603b125570John Hoford            public void onLayout(final PrintAttributes oldPrintAttributes,
296975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                                 final PrintAttributes newPrintAttributes,
297975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                                 final CancellationSignal cancellationSignal,
298975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                                 final LayoutResultCallback layoutResultCallback,
299975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                                 Bundle bundle) {
300975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                if (cancellationSignal.isCanceled()) {
301975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                    layoutResultCallback.onLayoutCancelled();
302975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                    mAttributes = newPrintAttributes;
303975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                    return;
304975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                }
305975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                // we finished the load
306975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                if (mBitmap != null) {
307975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                    PrintDocumentInfo info = new PrintDocumentInfo.Builder(jobName)
308975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                            .setContentType(PrintDocumentInfo.CONTENT_TYPE_PHOTO)
309975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                            .setPageCount(1)
310975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                            .build();
311975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                    boolean changed = !newPrintAttributes.equals(oldPrintAttributes);
312975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                    layoutResultCallback.onLayoutFinished(info, changed);
313975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                    return;
314975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                }
315975c49f182d754dfe1a38ba0457d6e603b125570John Hoford
316975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                loadBitmap = new AsyncTask<Uri, Boolean, Bitmap>() {
317975c49f182d754dfe1a38ba0457d6e603b125570John Hoford
318975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                    @Override
319975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                    protected void onPreExecute() {
320975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                        // First register for cancellation requests.
321975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                        cancellationSignal.setOnCancelListener(
322975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                                new CancellationSignal.OnCancelListener() {
323975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                                    @Override
324975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                                    public void onCancel() { // on different thread
325975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                                        cancelLoad();
326975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                                        cancel(false);
327975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                                    }
328975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                                });
329975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                    }
330975c49f182d754dfe1a38ba0457d6e603b125570John Hoford
331975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                    @Override
332975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                    protected Bitmap doInBackground(Uri... uris) {
333975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                        try {
334975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                            return loadConstrainedBitmap(imageFile, MAX_PRINT_SIZE);
335975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                        } catch (FileNotFoundException e) {
336975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                          /* ignore */
337975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                        }
338975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                        return null;
339975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                    }
340975c49f182d754dfe1a38ba0457d6e603b125570John Hoford
341975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                    @Override
342975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                    protected void onPostExecute(Bitmap bitmap) {
343975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                        super.onPostExecute(bitmap);
344975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                        mBitmap = bitmap;
345975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                        if (bitmap != null) {
346975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                            PrintDocumentInfo info = new PrintDocumentInfo.Builder(jobName)
347975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                                    .setContentType(PrintDocumentInfo.CONTENT_TYPE_PHOTO)
348975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                                    .setPageCount(1)
349975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                                    .build();
350975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                            boolean changed = !newPrintAttributes.equals(oldPrintAttributes);
351975c49f182d754dfe1a38ba0457d6e603b125570John Hoford
352975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                            layoutResultCallback.onLayoutFinished(info, changed);
353975c49f182d754dfe1a38ba0457d6e603b125570John Hoford
354975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                        } else {
355975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                            layoutResultCallback.onLayoutFailed(null);
356975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                        }
357975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                    }
358975c49f182d754dfe1a38ba0457d6e603b125570John Hoford
359975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                    @Override
360975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                    protected void onCancelled(Bitmap result) {
361975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                        // Task was cancelled, report that.
362975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                        layoutResultCallback.onLayoutCancelled();
363975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                    }
364975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                };
365975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                loadBitmap.execute();
366975c49f182d754dfe1a38ba0457d6e603b125570John Hoford
367975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                mAttributes = newPrintAttributes;
368975c49f182d754dfe1a38ba0457d6e603b125570John Hoford            }
369975c49f182d754dfe1a38ba0457d6e603b125570John Hoford
370975c49f182d754dfe1a38ba0457d6e603b125570John Hoford            private void cancelLoad() {
371975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                synchronized (mLock) { // prevent race with set null below
372975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                    if (mDecodeOptions != null) {
373975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                        mDecodeOptions.requestCancelDecode();
374975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                        mDecodeOptions = null;
375975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                    }
376975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                }
377975c49f182d754dfe1a38ba0457d6e603b125570John Hoford            }
378975c49f182d754dfe1a38ba0457d6e603b125570John Hoford
379975c49f182d754dfe1a38ba0457d6e603b125570John Hoford            @Override
380975c49f182d754dfe1a38ba0457d6e603b125570John Hoford            public void onFinish() {
381975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                super.onFinish();
382975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                cancelLoad();
383975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                loadBitmap.cancel(true);
384975c49f182d754dfe1a38ba0457d6e603b125570John Hoford            }
385975c49f182d754dfe1a38ba0457d6e603b125570John Hoford
386975c49f182d754dfe1a38ba0457d6e603b125570John Hoford            @Override
387975c49f182d754dfe1a38ba0457d6e603b125570John Hoford            public void onWrite(PageRange[] pageRanges, ParcelFileDescriptor fileDescriptor,
388975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                                CancellationSignal cancellationSignal,
389975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                                WriteResultCallback writeResultCallback) {
390975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                PrintedPdfDocument pdfDocument = new PrintedPdfDocument(mContext,
391975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                        mAttributes);
392975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                try {
393975c49f182d754dfe1a38ba0457d6e603b125570John Hoford
394975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                    Page page = pdfDocument.startPage(1);
395975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                    RectF content = new RectF(page.getInfo().getContentRect());
396975c49f182d754dfe1a38ba0457d6e603b125570John Hoford
397975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                    // Compute and apply scale to fill the page.
398975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                    Matrix matrix = getMatrix(mBitmap.getWidth(), mBitmap.getHeight(),
399975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                            content, fittingMode);
400975c49f182d754dfe1a38ba0457d6e603b125570John Hoford
401975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                    // Draw the bitmap.
402975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                    page.getCanvas().drawBitmap(mBitmap, matrix, null);
403975c49f182d754dfe1a38ba0457d6e603b125570John Hoford
404975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                    // Finish the page.
405975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                    pdfDocument.finishPage(page);
406975c49f182d754dfe1a38ba0457d6e603b125570John Hoford
407975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                    try {
408975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                        // Write the document.
409975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                        pdfDocument.writeTo(new FileOutputStream(
410975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                                fileDescriptor.getFileDescriptor()));
411975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                        // Done.
412975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                        writeResultCallback.onWriteFinished(
413975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                                new PageRange[]{PageRange.ALL_PAGES});
414975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                    } catch (IOException ioe) {
415975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                        // Failed.
416975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                        Log.e(LOG_TAG, "Error writing printed content", ioe);
417975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                        writeResultCallback.onWriteFailed(null);
418975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                    }
419975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                } finally {
420975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                    if (pdfDocument != null) {
421975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                        pdfDocument.close();
422975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                    }
423975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                    if (fileDescriptor != null) {
424975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                        try {
425975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                            fileDescriptor.close();
426975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                        } catch (IOException ioe) {
427975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                            /* ignore */
428975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                        }
429975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                    }
430975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                }
431975c49f182d754dfe1a38ba0457d6e603b125570John Hoford            }
432975c49f182d754dfe1a38ba0457d6e603b125570John Hoford        };
433975c49f182d754dfe1a38ba0457d6e603b125570John Hoford
434975c49f182d754dfe1a38ba0457d6e603b125570John Hoford        PrintManager printManager = (PrintManager) mContext.getSystemService(Context.PRINT_SERVICE);
435975c49f182d754dfe1a38ba0457d6e603b125570John Hoford        PrintAttributes.Builder builder = new PrintAttributes.Builder();
436975c49f182d754dfe1a38ba0457d6e603b125570John Hoford        builder.setColorMode(mColorMode);
437975c49f182d754dfe1a38ba0457d6e603b125570John Hoford
438975c49f182d754dfe1a38ba0457d6e603b125570John Hoford        if (mOrientation == ORIENTATION_LANDSCAPE) {
439975c49f182d754dfe1a38ba0457d6e603b125570John Hoford            builder.setMediaSize(PrintAttributes.MediaSize.UNKNOWN_LANDSCAPE);
440975c49f182d754dfe1a38ba0457d6e603b125570John Hoford        } else if (mOrientation == ORIENTATION_PORTRAIT) {
441975c49f182d754dfe1a38ba0457d6e603b125570John Hoford            builder.setMediaSize(PrintAttributes.MediaSize.UNKNOWN_PORTRAIT);
442975c49f182d754dfe1a38ba0457d6e603b125570John Hoford        }
443975c49f182d754dfe1a38ba0457d6e603b125570John Hoford        PrintAttributes attr = builder.build();
444975c49f182d754dfe1a38ba0457d6e603b125570John Hoford
445975c49f182d754dfe1a38ba0457d6e603b125570John Hoford        printManager.print(jobName, printDocumentAdapter, attr);
446b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav    }
447b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav
448b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav    /**
449b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav     * Loads a bitmap while limiting its size
450b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav     *
451b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav     * @param uri           location of a valid image
452b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav     * @param maxSideLength the maximum length of a size
453b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav     * @return the Bitmap
454b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav     * @throws FileNotFoundException if the Uri does not point to an image
455b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav     */
456b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav    private Bitmap loadConstrainedBitmap(Uri uri, int maxSideLength) throws FileNotFoundException {
457b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav        if (maxSideLength <= 0 || uri == null || mContext == null) {
458b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav            throw new IllegalArgumentException("bad argument to getScaledBitmap");
459b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav        }
460b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav        // Get width and height of stored bitmap
461b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav        BitmapFactory.Options opt = new BitmapFactory.Options();
462b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav        opt.inJustDecodeBounds = true;
463b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav        loadBitmap(uri, opt);
464b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav
465b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav        int w = opt.outWidth;
466b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav        int h = opt.outHeight;
467b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav
468b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav        // If bitmap cannot be decoded, return null
469b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav        if (w <= 0 || h <= 0) {
470b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav            return null;
471b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav        }
472b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav
473b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav        // Find best downsampling size
474b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav        int imageSide = Math.max(w, h);
475b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav
476b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav        int sampleSize = 1;
477b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav        while (imageSide > maxSideLength) {
478b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav            imageSide >>>= 1;
479b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav            sampleSize <<= 1;
480b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav        }
481b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav
482b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav        // Make sure sample size is reasonable
483b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav        if (sampleSize <= 0 || 0 >= (int) (Math.min(w, h) / sampleSize)) {
484b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav            return null;
485b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav        }
486975c49f182d754dfe1a38ba0457d6e603b125570John Hoford        BitmapFactory.Options decodeOptions = null;
487975c49f182d754dfe1a38ba0457d6e603b125570John Hoford        synchronized (mLock) { // prevent race with set null below
488975c49f182d754dfe1a38ba0457d6e603b125570John Hoford            mDecodeOptions = new BitmapFactory.Options();
489975c49f182d754dfe1a38ba0457d6e603b125570John Hoford            mDecodeOptions.inMutable = true;
490975c49f182d754dfe1a38ba0457d6e603b125570John Hoford            mDecodeOptions.inSampleSize = sampleSize;
491975c49f182d754dfe1a38ba0457d6e603b125570John Hoford            decodeOptions = mDecodeOptions;
492975c49f182d754dfe1a38ba0457d6e603b125570John Hoford        }
493975c49f182d754dfe1a38ba0457d6e603b125570John Hoford        try {
494975c49f182d754dfe1a38ba0457d6e603b125570John Hoford            return loadBitmap(uri, decodeOptions);
495975c49f182d754dfe1a38ba0457d6e603b125570John Hoford        } finally {
496975c49f182d754dfe1a38ba0457d6e603b125570John Hoford            synchronized (mLock) {
497975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                mDecodeOptions = null;
498975c49f182d754dfe1a38ba0457d6e603b125570John Hoford            }
499975c49f182d754dfe1a38ba0457d6e603b125570John Hoford        }
500b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav    }
501b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav
502b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav    /**
503b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav     * Returns the bitmap from the given uri loaded using the given options.
504b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav     * Returns null on failure.
505b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav     */
506b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav    private Bitmap loadBitmap(Uri uri, BitmapFactory.Options o) throws FileNotFoundException {
507b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav        if (uri == null || mContext == null) {
508b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav            throw new IllegalArgumentException("bad argument to loadBitmap");
509b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav        }
510b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav        InputStream is = null;
511b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav        try {
512b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav            is = mContext.getContentResolver().openInputStream(uri);
513b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav            return BitmapFactory.decodeStream(is, null, o);
514b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav        } finally {
515545f1bf8b47c12d2453143706a2fd76d9eef2368Svetoslav Ganov            if (is != null) {
516545f1bf8b47c12d2453143706a2fd76d9eef2368Svetoslav Ganov                try {
517545f1bf8b47c12d2453143706a2fd76d9eef2368Svetoslav Ganov                    is.close();
518545f1bf8b47c12d2453143706a2fd76d9eef2368Svetoslav Ganov                } catch (IOException t) {
519545f1bf8b47c12d2453143706a2fd76d9eef2368Svetoslav Ganov                    Log.w(LOG_TAG, "close fail ", t);
520545f1bf8b47c12d2453143706a2fd76d9eef2368Svetoslav Ganov                }
521b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav            }
522b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav        }
523b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav    }
524b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav}