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;
2116ccdd01f9b7b69041decfbd484d6a399aec7904Makoto Onukiimport android.graphics.Bitmap.Config;
22b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslavimport android.graphics.BitmapFactory;
2316ccdd01f9b7b69041decfbd484d6a399aec7904Makoto Onukiimport android.graphics.Canvas;
2416ccdd01f9b7b69041decfbd484d6a399aec7904Makoto Onukiimport android.graphics.ColorMatrix;
2516ccdd01f9b7b69041decfbd484d6a399aec7904Makoto Onukiimport android.graphics.ColorMatrixColorFilter;
26b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslavimport android.graphics.Matrix;
2716ccdd01f9b7b69041decfbd484d6a399aec7904Makoto Onukiimport android.graphics.Paint;
28b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslavimport android.graphics.RectF;
29b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslavimport android.graphics.pdf.PdfDocument.Page;
30b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslavimport android.net.Uri;
31975c49f182d754dfe1a38ba0457d6e603b125570John Hofordimport android.os.AsyncTask;
32b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslavimport android.os.Bundle;
33b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslavimport android.os.CancellationSignal;
34b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslavimport android.os.ParcelFileDescriptor;
35b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslavimport android.print.PageRange;
36b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslavimport android.print.PrintAttributes;
37b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslavimport android.print.PrintDocumentAdapter;
38b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslavimport android.print.PrintDocumentInfo;
39b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslavimport android.print.PrintManager;
40215440785861d37af3c6056be63ec2dd8274c452Philip P. Moltmannimport android.print.PrintAttributes.MediaSize;
41b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslavimport android.print.pdf.PrintedPdfDocument;
42b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslavimport android.util.Log;
43b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav
44b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslavimport java.io.FileNotFoundException;
45b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslavimport java.io.FileOutputStream;
46b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslavimport java.io.IOException;
47b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslavimport java.io.InputStream;
48b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav
49b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav/**
50b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav * Kitkat specific PrintManager API implementation.
51b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav */
52975c49f182d754dfe1a38ba0457d6e603b125570John Hofordclass PrintHelperKitkat {
53b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav    private static final String LOG_TAG = "PrintHelperKitkat";
54b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav    // will be <= 300 dpi on A4 (8.3×11.7) paper (worst case of 150 dpi)
55b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav    private final static int MAX_PRINT_SIZE = 3500;
56b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav    final Context mContext;
57975c49f182d754dfe1a38ba0457d6e603b125570John Hoford    BitmapFactory.Options mDecodeOptions = null;
58975c49f182d754dfe1a38ba0457d6e603b125570John Hoford    private final Object mLock = new Object();
59b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav    /**
60b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav     * image will be scaled but leave white space
61b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav     */
62b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav    public static final int SCALE_MODE_FIT = 1;
63b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav    /**
64b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav     * image will fill the paper and be cropped (default)
65b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav     */
66b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav    public static final int SCALE_MODE_FILL = 2;
67b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav
6809ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov    /**
69975c49f182d754dfe1a38ba0457d6e603b125570John Hoford     * select landscape (default)
70975c49f182d754dfe1a38ba0457d6e603b125570John Hoford     */
71975c49f182d754dfe1a38ba0457d6e603b125570John Hoford    public static final int ORIENTATION_LANDSCAPE = 1;
72975c49f182d754dfe1a38ba0457d6e603b125570John Hoford
73975c49f182d754dfe1a38ba0457d6e603b125570John Hoford    /**
74975c49f182d754dfe1a38ba0457d6e603b125570John Hoford     * select portrait
75975c49f182d754dfe1a38ba0457d6e603b125570John Hoford     */
76975c49f182d754dfe1a38ba0457d6e603b125570John Hoford    public static final int ORIENTATION_PORTRAIT = 2;
77975c49f182d754dfe1a38ba0457d6e603b125570John Hoford
78975c49f182d754dfe1a38ba0457d6e603b125570John Hoford    /**
7909ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov     * this is a black and white image
8009ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov     */
8109ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov    public static final int COLOR_MODE_MONOCHROME = 1;
8209ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov    /**
8309ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov     * this is a color image (default)
8409ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov     */
8509ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov    public static final int COLOR_MODE_COLOR = 2;
8609ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov
87b4eb9c984f1c6ac8007c74fab239437cf9f6b474Svet Ganov    public interface OnPrintFinishCallback {
88b4eb9c984f1c6ac8007c74fab239437cf9f6b474Svet Ganov        public void onFinish();
89b4eb9c984f1c6ac8007c74fab239437cf9f6b474Svet Ganov    }
90b4eb9c984f1c6ac8007c74fab239437cf9f6b474Svet Ganov
91215440785861d37af3c6056be63ec2dd8274c452Philip P. Moltmann    /**
92215440785861d37af3c6056be63ec2dd8274c452Philip P. Moltmann     * Whether the PrintActivity respects the suggested orientation
93215440785861d37af3c6056be63ec2dd8274c452Philip P. Moltmann     */
94215440785861d37af3c6056be63ec2dd8274c452Philip P. Moltmann    protected boolean mPrintActivityRespectsOrientation;
95215440785861d37af3c6056be63ec2dd8274c452Philip P. Moltmann
9673cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann    /**
9773cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann     * Whether the print subsystem handles min margins correctly. If not the print helper needs to
9873cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann     * fake this.
9973cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann     */
10073cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann    protected boolean mIsMinMarginsHandlingCorrect;
10173cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann
102b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav    int mScaleMode = SCALE_MODE_FILL;
103b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav
10409ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov    int mColorMode = COLOR_MODE_COLOR;
10509ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov
106215440785861d37af3c6056be63ec2dd8274c452Philip P. Moltmann    int mOrientation;
107975c49f182d754dfe1a38ba0457d6e603b125570John Hoford
108b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav    PrintHelperKitkat(Context context) {
109215440785861d37af3c6056be63ec2dd8274c452Philip P. Moltmann        mPrintActivityRespectsOrientation = true;
11073cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann        mIsMinMarginsHandlingCorrect = true;
111215440785861d37af3c6056be63ec2dd8274c452Philip P. Moltmann
112b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav        mContext = context;
113b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav    }
114b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav
115b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav    /**
116b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav     * Selects whether the image will fill the paper and be cropped
117975c49f182d754dfe1a38ba0457d6e603b125570John Hoford     * <p/>
118b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav     * {@link #SCALE_MODE_FIT}
119b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav     * or whether the image will be scaled but leave white space
120b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav     * {@link #SCALE_MODE_FILL}.
121b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav     *
122b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav     * @param scaleMode {@link #SCALE_MODE_FIT} or
123b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav     *                  {@link #SCALE_MODE_FILL}
124b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav     */
125b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav    public void setScaleMode(int scaleMode) {
126b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav        mScaleMode = scaleMode;
127b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav    }
128b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav
129b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav    /**
130b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav     * Returns the scale mode with which the image will fill the paper.
131b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav     *
132b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav     * @return The scale Mode: {@link #SCALE_MODE_FIT} or
133b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav     * {@link #SCALE_MODE_FILL}
134b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav     */
135b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav    public int getScaleMode() {
136b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav        return mScaleMode;
137b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav    }
138b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav
139b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav    /**
14009ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov     * Sets whether the image will be printed in color (default)
14109ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov     * {@link #COLOR_MODE_COLOR} or in back and white
14209ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov     * {@link #COLOR_MODE_MONOCHROME}.
14309ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov     *
14409ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov     * @param colorMode The color mode which is one of
145975c49f182d754dfe1a38ba0457d6e603b125570John Hoford     *                  {@link #COLOR_MODE_COLOR} and {@link #COLOR_MODE_MONOCHROME}.
14609ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov     */
14709ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov    public void setColorMode(int colorMode) {
14809ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov        mColorMode = colorMode;
14909ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov    }
15009ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov
15109ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov    /**
152975c49f182d754dfe1a38ba0457d6e603b125570John Hoford     * Sets whether to select landscape (default), {@link #ORIENTATION_LANDSCAPE}
153975c49f182d754dfe1a38ba0457d6e603b125570John Hoford     * or portrait {@link #ORIENTATION_PORTRAIT}
154975c49f182d754dfe1a38ba0457d6e603b125570John Hoford     * @param orientation The page orientation which is one of
155975c49f182d754dfe1a38ba0457d6e603b125570John Hoford     *                    {@link #ORIENTATION_LANDSCAPE} or {@link #ORIENTATION_PORTRAIT}.
156975c49f182d754dfe1a38ba0457d6e603b125570John Hoford     */
157975c49f182d754dfe1a38ba0457d6e603b125570John Hoford    public void setOrientation(int orientation) {
158975c49f182d754dfe1a38ba0457d6e603b125570John Hoford        mOrientation = orientation;
159975c49f182d754dfe1a38ba0457d6e603b125570John Hoford    }
160975c49f182d754dfe1a38ba0457d6e603b125570John Hoford
161975c49f182d754dfe1a38ba0457d6e603b125570John Hoford    /**
162975c49f182d754dfe1a38ba0457d6e603b125570John Hoford     * Gets the page orientation with which the image will be printed.
163975c49f182d754dfe1a38ba0457d6e603b125570John Hoford     *
164975c49f182d754dfe1a38ba0457d6e603b125570John Hoford     * @return The preferred orientation which is one of
165975c49f182d754dfe1a38ba0457d6e603b125570John Hoford     * {@link #ORIENTATION_LANDSCAPE} or {@link #ORIENTATION_PORTRAIT}
166975c49f182d754dfe1a38ba0457d6e603b125570John Hoford     */
167975c49f182d754dfe1a38ba0457d6e603b125570John Hoford    public int getOrientation() {
168215440785861d37af3c6056be63ec2dd8274c452Philip P. Moltmann        /// Unset defaults to landscape but might turn image
169215440785861d37af3c6056be63ec2dd8274c452Philip P. Moltmann        if (mOrientation == 0) {
170215440785861d37af3c6056be63ec2dd8274c452Philip P. Moltmann            return ORIENTATION_LANDSCAPE;
171215440785861d37af3c6056be63ec2dd8274c452Philip P. Moltmann        }
172975c49f182d754dfe1a38ba0457d6e603b125570John Hoford        return mOrientation;
173975c49f182d754dfe1a38ba0457d6e603b125570John Hoford    }
174975c49f182d754dfe1a38ba0457d6e603b125570John Hoford
175975c49f182d754dfe1a38ba0457d6e603b125570John Hoford    /**
17609ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov     * Gets the color mode with which the image will be printed.
17709ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov     *
17809ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov     * @return The color mode which is one of {@link #COLOR_MODE_COLOR}
17909ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov     * and {@link #COLOR_MODE_MONOCHROME}.
18009ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov     */
18109ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov    public int getColorMode() {
18209ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov        return mColorMode;
18309ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov    }
18409ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov
18509ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov    /**
186215440785861d37af3c6056be63ec2dd8274c452Philip P. Moltmann     * Check if the supplied bitmap should best be printed on a portrait orientation paper.
187215440785861d37af3c6056be63ec2dd8274c452Philip P. Moltmann     *
188215440785861d37af3c6056be63ec2dd8274c452Philip P. Moltmann     * @param bitmap The bitmap to be printed.
189215440785861d37af3c6056be63ec2dd8274c452Philip P. Moltmann     * @return true iff the picture should best be printed on a portrait orientation paper.
190215440785861d37af3c6056be63ec2dd8274c452Philip P. Moltmann     */
191215440785861d37af3c6056be63ec2dd8274c452Philip P. Moltmann    private static boolean isPortrait(Bitmap bitmap) {
192215440785861d37af3c6056be63ec2dd8274c452Philip P. Moltmann        if (bitmap.getWidth() <= bitmap.getHeight()) {
193215440785861d37af3c6056be63ec2dd8274c452Philip P. Moltmann            return true;
194215440785861d37af3c6056be63ec2dd8274c452Philip P. Moltmann        } else {
195215440785861d37af3c6056be63ec2dd8274c452Philip P. Moltmann            return false;
196215440785861d37af3c6056be63ec2dd8274c452Philip P. Moltmann        }
197215440785861d37af3c6056be63ec2dd8274c452Philip P. Moltmann    }
198215440785861d37af3c6056be63ec2dd8274c452Philip P. Moltmann
199215440785861d37af3c6056be63ec2dd8274c452Philip P. Moltmann    /**
20073cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann     * Create a build with a copy from the other print attributes.
20173cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann     *
20273cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann     * @param other The other print attributes
20373cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann     *
20473cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann     * @return A builder that will build print attributes that match the other attributes
20573cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann     */
20673cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann    protected PrintAttributes.Builder copyAttributes(PrintAttributes other) {
20745f4520ad78647cee60e429d9c0ddd0005e07456Philip P. Moltmann        PrintAttributes.Builder b = (new PrintAttributes.Builder())
20873cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann                .setMediaSize(other.getMediaSize())
20973cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann                .setResolution(other.getResolution())
21073cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann                .setMinMargins(other.getMinMargins());
21145f4520ad78647cee60e429d9c0ddd0005e07456Philip P. Moltmann
21245f4520ad78647cee60e429d9c0ddd0005e07456Philip P. Moltmann        if (other.getColorMode() != 0) {
21345f4520ad78647cee60e429d9c0ddd0005e07456Philip P. Moltmann            b.setColorMode(other.getColorMode());
21445f4520ad78647cee60e429d9c0ddd0005e07456Philip P. Moltmann        }
21545f4520ad78647cee60e429d9c0ddd0005e07456Philip P. Moltmann
21645f4520ad78647cee60e429d9c0ddd0005e07456Philip P. Moltmann        return b;
21773cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann    }
21873cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann
21973cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann    /**
220b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav     * Prints a bitmap.
221b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav     *
222b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav     * @param jobName The print job name.
223b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav     * @param bitmap  The bitmap to print.
224b4eb9c984f1c6ac8007c74fab239437cf9f6b474Svet Ganov     * @param callback Optional callback to observe when printing is finished.
225b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav     */
226b4eb9c984f1c6ac8007c74fab239437cf9f6b474Svet Ganov    public void printBitmap(final String jobName, final Bitmap bitmap,
227b4eb9c984f1c6ac8007c74fab239437cf9f6b474Svet Ganov            final OnPrintFinishCallback callback) {
228b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav        if (bitmap == null) {
229b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav            return;
230b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav        }
231b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav        final int fittingMode = mScaleMode; // grab the fitting mode at time of call
232b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav        PrintManager printManager = (PrintManager) mContext.getSystemService(Context.PRINT_SERVICE);
233215440785861d37af3c6056be63ec2dd8274c452Philip P. Moltmann        PrintAttributes.MediaSize mediaSize;
234215440785861d37af3c6056be63ec2dd8274c452Philip P. Moltmann        if (isPortrait(bitmap)) {
235215440785861d37af3c6056be63ec2dd8274c452Philip P. Moltmann            mediaSize = PrintAttributes.MediaSize.UNKNOWN_PORTRAIT;
236215440785861d37af3c6056be63ec2dd8274c452Philip P. Moltmann        } else {
237b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav            mediaSize = PrintAttributes.MediaSize.UNKNOWN_LANDSCAPE;
238b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav        }
23909ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov        PrintAttributes attr = new PrintAttributes.Builder()
24009ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov                .setMediaSize(mediaSize)
24109ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov                .setColorMode(mColorMode)
24209ad64345349f27bdeb53c536f178e46bb7ce5acSvetoslav Ganov                .build();
243b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav
244b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav        printManager.print(jobName,
245b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav                new PrintDocumentAdapter() {
246b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav                    private PrintAttributes mAttributes;
247b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav
248b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav                    @Override
249b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav                    public void onLayout(PrintAttributes oldPrintAttributes,
250b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav                                         PrintAttributes newPrintAttributes,
251b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav                                         CancellationSignal cancellationSignal,
252b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav                                         LayoutResultCallback layoutResultCallback,
253b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav                                         Bundle bundle) {
254b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav
255b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav                        mAttributes = newPrintAttributes;
256b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav
257b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav                        PrintDocumentInfo info = new PrintDocumentInfo.Builder(jobName)
258b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav                                .setContentType(PrintDocumentInfo.CONTENT_TYPE_PHOTO)
259b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav                                .setPageCount(1)
260b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav                                .build();
261b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav                        boolean changed = !newPrintAttributes.equals(oldPrintAttributes);
262b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav                        layoutResultCallback.onLayoutFinished(info, changed);
263b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav                    }
264b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav
265b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav                    @Override
266b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav                    public void onWrite(PageRange[] pageRanges, ParcelFileDescriptor fileDescriptor,
267b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav                                        CancellationSignal cancellationSignal,
268b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav                                        WriteResultCallback writeResultCallback) {
26973cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann                        writeBitmap(mAttributes, fittingMode, bitmap, fileDescriptor,
27073cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann                                writeResultCallback);
271b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav                    }
272b4eb9c984f1c6ac8007c74fab239437cf9f6b474Svet Ganov
273b4eb9c984f1c6ac8007c74fab239437cf9f6b474Svet Ganov                    @Override
274b4eb9c984f1c6ac8007c74fab239437cf9f6b474Svet Ganov                    public void onFinish() {
275b4eb9c984f1c6ac8007c74fab239437cf9f6b474Svet Ganov                        if (callback != null) {
276b4eb9c984f1c6ac8007c74fab239437cf9f6b474Svet Ganov                            callback.onFinish();
277b4eb9c984f1c6ac8007c74fab239437cf9f6b474Svet Ganov                        }
278b4eb9c984f1c6ac8007c74fab239437cf9f6b474Svet Ganov                    }
279b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav                }, attr);
280b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav    }
281b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav
282b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav    /**
283975c49f182d754dfe1a38ba0457d6e603b125570John Hoford     * Calculates the transform the print an Image to fill the page
284975c49f182d754dfe1a38ba0457d6e603b125570John Hoford     *
285975c49f182d754dfe1a38ba0457d6e603b125570John Hoford     * @param imageWidth  with of bitmap
286975c49f182d754dfe1a38ba0457d6e603b125570John Hoford     * @param imageHeight height of bitmap
287975c49f182d754dfe1a38ba0457d6e603b125570John Hoford     * @param content     The output page dimensions
288975c49f182d754dfe1a38ba0457d6e603b125570John Hoford     * @param fittingMode The mode of fitting {@link #SCALE_MODE_FILL} vs {@link #SCALE_MODE_FIT}
289975c49f182d754dfe1a38ba0457d6e603b125570John Hoford     * @return Matrix to be used in canvas.drawBitmap(bitmap, matrix, null) call
290975c49f182d754dfe1a38ba0457d6e603b125570John Hoford     */
291975c49f182d754dfe1a38ba0457d6e603b125570John Hoford    private Matrix getMatrix(int imageWidth, int imageHeight, RectF content, int fittingMode) {
292975c49f182d754dfe1a38ba0457d6e603b125570John Hoford        Matrix matrix = new Matrix();
293975c49f182d754dfe1a38ba0457d6e603b125570John Hoford
294975c49f182d754dfe1a38ba0457d6e603b125570John Hoford        // Compute and apply scale to fill the page.
295975c49f182d754dfe1a38ba0457d6e603b125570John Hoford        float scale = content.width() / imageWidth;
296975c49f182d754dfe1a38ba0457d6e603b125570John Hoford        if (fittingMode == SCALE_MODE_FILL) {
297975c49f182d754dfe1a38ba0457d6e603b125570John Hoford            scale = Math.max(scale, content.height() / imageHeight);
298975c49f182d754dfe1a38ba0457d6e603b125570John Hoford        } else {
299975c49f182d754dfe1a38ba0457d6e603b125570John Hoford            scale = Math.min(scale, content.height() / imageHeight);
300975c49f182d754dfe1a38ba0457d6e603b125570John Hoford        }
301975c49f182d754dfe1a38ba0457d6e603b125570John Hoford        matrix.postScale(scale, scale);
302975c49f182d754dfe1a38ba0457d6e603b125570John Hoford
303975c49f182d754dfe1a38ba0457d6e603b125570John Hoford        // Center the content.
304975c49f182d754dfe1a38ba0457d6e603b125570John Hoford        final float translateX = (content.width()
305975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                - imageWidth * scale) / 2;
306975c49f182d754dfe1a38ba0457d6e603b125570John Hoford        final float translateY = (content.height()
307975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                - imageHeight * scale) / 2;
308975c49f182d754dfe1a38ba0457d6e603b125570John Hoford        matrix.postTranslate(translateX, translateY);
309975c49f182d754dfe1a38ba0457d6e603b125570John Hoford        return matrix;
310975c49f182d754dfe1a38ba0457d6e603b125570John Hoford    }
311975c49f182d754dfe1a38ba0457d6e603b125570John Hoford
312975c49f182d754dfe1a38ba0457d6e603b125570John Hoford    /**
31373cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann     * Write a bitmap for a PDF document.
31473cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann     *
31573cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann     * @param attributes          The print attributes
31673cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann     * @param fittingMode         How to fit the bitmap
31773cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann     * @param bitmap              The bitmap to write
31873cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann     * @param fileDescriptor      The file to write to
31973cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann     * @param writeResultCallback Callback to call once written
32073cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann     */
32173cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann    private void writeBitmap(PrintAttributes attributes, int fittingMode, Bitmap bitmap,
32273cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann            ParcelFileDescriptor fileDescriptor,
32373cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann            PrintDocumentAdapter.WriteResultCallback writeResultCallback) {
32473cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann        PrintAttributes pdfAttributes;
32573cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann        if (mIsMinMarginsHandlingCorrect) {
32673cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann            pdfAttributes = attributes;
32773cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann        } else {
32873cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann            // If the handling of any margin != 0 is broken, strip the margins and add them to the
32973cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann            // bitmap later
33073cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann            pdfAttributes = copyAttributes(attributes)
33173cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann                    .setMinMargins(new PrintAttributes.Margins(0,0,0,0)).build();
33273cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann        }
33373cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann
33473cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann        PrintedPdfDocument pdfDocument = new PrintedPdfDocument(mContext,
33573cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann                pdfAttributes);
33673cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann
33773cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann        Bitmap maybeGrayscale = convertBitmapForColorMode(bitmap,
33873cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann                pdfAttributes.getColorMode());
33973cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann        try {
34073cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann            Page page = pdfDocument.startPage(1);
34173cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann
34273cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann            RectF contentRect;
34373cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann            if (mIsMinMarginsHandlingCorrect) {
34473cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann                contentRect = new RectF(page.getInfo().getContentRect());
34573cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann            } else {
34673cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann                // Create dummy doc that has the margins to compute correctly sized content
34773cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann                // rectangle
34873cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann                PrintedPdfDocument dummyDocument = new PrintedPdfDocument(mContext,
34973cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann                        attributes);
35073cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann                Page dummyPage = dummyDocument.startPage(1);
35173cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann                contentRect = new RectF(dummyPage.getInfo().getContentRect());
35273cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann                dummyDocument.finishPage(dummyPage);
35373cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann                dummyDocument.close();
35473cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann            }
35573cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann
35673cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann            // Resize bitmap
35773cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann            Matrix matrix = getMatrix(
35873cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann                    maybeGrayscale.getWidth(), maybeGrayscale.getHeight(),
35973cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann                    contentRect, fittingMode);
36073cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann
36173cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann            if (mIsMinMarginsHandlingCorrect) {
36273cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann                // The pdfDocument takes care of the positioning and margins
36373cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann            } else {
36473cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann                // Move it to the correct position.
36573cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann                matrix.postTranslate(contentRect.left, contentRect.top);
36673cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann
36773cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann                // Cut off margins
36873cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann                page.getCanvas().clipRect(contentRect);
36973cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann            }
37073cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann
37173cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann            // Draw the bitmap.
37273cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann            page.getCanvas().drawBitmap(maybeGrayscale, matrix, null);
37373cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann
37473cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann            // Finish the page.
37573cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann            pdfDocument.finishPage(page);
37673cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann
37773cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann            try {
37873cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann                // Write the document.
37973cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann                pdfDocument.writeTo(new FileOutputStream(fileDescriptor.getFileDescriptor()));
38073cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann                // Done.
38173cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann                writeResultCallback.onWriteFinished(new PageRange[]{PageRange.ALL_PAGES});
38273cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann            } catch (IOException ioe) {
38373cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann                // Failed.
38473cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann                Log.e(LOG_TAG, "Error writing printed content", ioe);
38573cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann                writeResultCallback.onWriteFailed(null);
38673cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann            }
38773cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann        } finally {
38873cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann            pdfDocument.close();
38973cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann
39073cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann            if (fileDescriptor != null) {
39173cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann                try {
39273cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann                    fileDescriptor.close();
39373cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann                } catch (IOException ioe) {
39473cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann                    // ignore
39573cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann                }
39673cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann            }
39773cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann            // If we created a new instance for grayscaling, then recycle it here.
39873cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann            if (maybeGrayscale != bitmap) {
39973cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann                maybeGrayscale.recycle();
40073cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann            }
40173cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann        }
40273cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann    }
40373cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann
40473cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann    /**
405b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav     * Prints an image located at the Uri. Image types supported are those of
406b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav     * <code>BitmapFactory.decodeStream</code> (JPEG, GIF, PNG, BMP, WEBP)
407b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav     *
408b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav     * @param jobName   The print job name.
409b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav     * @param imageFile The <code>Uri</code> pointing to an image to print.
410b4eb9c984f1c6ac8007c74fab239437cf9f6b474Svet Ganov     * @param callback Optional callback to observe when printing is finished.
411b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav     * @throws FileNotFoundException if <code>Uri</code> is not pointing to a valid image.
412b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav     */
413b4eb9c984f1c6ac8007c74fab239437cf9f6b474Svet Ganov    public void printBitmap(final String jobName, final Uri imageFile,
414b4eb9c984f1c6ac8007c74fab239437cf9f6b474Svet Ganov            final OnPrintFinishCallback callback) throws FileNotFoundException {
415975c49f182d754dfe1a38ba0457d6e603b125570John Hoford        final int fittingMode = mScaleMode;
416975c49f182d754dfe1a38ba0457d6e603b125570John Hoford
417975c49f182d754dfe1a38ba0457d6e603b125570John Hoford        PrintDocumentAdapter printDocumentAdapter = new PrintDocumentAdapter() {
418975c49f182d754dfe1a38ba0457d6e603b125570John Hoford            private PrintAttributes mAttributes;
419854aed9e83ca17ad558f3aec7fff49ef2153ceafSvetoslav            AsyncTask<Uri, Boolean, Bitmap> mLoadBitmap;
420975c49f182d754dfe1a38ba0457d6e603b125570John Hoford            Bitmap mBitmap = null;
421975c49f182d754dfe1a38ba0457d6e603b125570John Hoford
422975c49f182d754dfe1a38ba0457d6e603b125570John Hoford            @Override
423975c49f182d754dfe1a38ba0457d6e603b125570John Hoford            public void onLayout(final PrintAttributes oldPrintAttributes,
424975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                                 final PrintAttributes newPrintAttributes,
425975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                                 final CancellationSignal cancellationSignal,
426975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                                 final LayoutResultCallback layoutResultCallback,
427975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                                 Bundle bundle) {
428854aed9e83ca17ad558f3aec7fff49ef2153ceafSvetoslav
429215440785861d37af3c6056be63ec2dd8274c452Philip P. Moltmann                synchronized (this) {
430215440785861d37af3c6056be63ec2dd8274c452Philip P. Moltmann                    mAttributes = newPrintAttributes;
431215440785861d37af3c6056be63ec2dd8274c452Philip P. Moltmann                }
432854aed9e83ca17ad558f3aec7fff49ef2153ceafSvetoslav
433975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                if (cancellationSignal.isCanceled()) {
434975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                    layoutResultCallback.onLayoutCancelled();
435975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                    return;
436975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                }
437975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                // we finished the load
438975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                if (mBitmap != null) {
439975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                    PrintDocumentInfo info = new PrintDocumentInfo.Builder(jobName)
440975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                            .setContentType(PrintDocumentInfo.CONTENT_TYPE_PHOTO)
441975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                            .setPageCount(1)
442975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                            .build();
443975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                    boolean changed = !newPrintAttributes.equals(oldPrintAttributes);
444975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                    layoutResultCallback.onLayoutFinished(info, changed);
445975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                    return;
446975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                }
447975c49f182d754dfe1a38ba0457d6e603b125570John Hoford
448854aed9e83ca17ad558f3aec7fff49ef2153ceafSvetoslav                mLoadBitmap = new AsyncTask<Uri, Boolean, Bitmap>() {
449975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                    @Override
450975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                    protected void onPreExecute() {
451975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                        // First register for cancellation requests.
452975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                        cancellationSignal.setOnCancelListener(
453975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                                new CancellationSignal.OnCancelListener() {
454975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                                    @Override
455975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                                    public void onCancel() { // on different thread
456975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                                        cancelLoad();
457975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                                        cancel(false);
458975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                                    }
459975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                                });
460975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                    }
461975c49f182d754dfe1a38ba0457d6e603b125570John Hoford
462975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                    @Override
463975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                    protected Bitmap doInBackground(Uri... uris) {
464975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                        try {
465975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                            return loadConstrainedBitmap(imageFile, MAX_PRINT_SIZE);
466975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                        } catch (FileNotFoundException e) {
467975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                          /* ignore */
468975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                        }
469975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                        return null;
470975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                    }
471975c49f182d754dfe1a38ba0457d6e603b125570John Hoford
472975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                    @Override
473975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                    protected void onPostExecute(Bitmap bitmap) {
474975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                        super.onPostExecute(bitmap);
475215440785861d37af3c6056be63ec2dd8274c452Philip P. Moltmann
476215440785861d37af3c6056be63ec2dd8274c452Philip P. Moltmann                        // If orientation was not set by the caller, try to fit the bitmap on
477215440785861d37af3c6056be63ec2dd8274c452Philip P. Moltmann                        // the current paper by potentially rotating the bitmap by 90 degrees.
478215440785861d37af3c6056be63ec2dd8274c452Philip P. Moltmann                        if (bitmap != null
479215440785861d37af3c6056be63ec2dd8274c452Philip P. Moltmann                                && (!mPrintActivityRespectsOrientation || mOrientation == 0)) {
480215440785861d37af3c6056be63ec2dd8274c452Philip P. Moltmann                            MediaSize mediaSize;
481215440785861d37af3c6056be63ec2dd8274c452Philip P. Moltmann
482215440785861d37af3c6056be63ec2dd8274c452Philip P. Moltmann                            synchronized (this) {
483215440785861d37af3c6056be63ec2dd8274c452Philip P. Moltmann                                mediaSize = mAttributes.getMediaSize();
484215440785861d37af3c6056be63ec2dd8274c452Philip P. Moltmann                            }
485215440785861d37af3c6056be63ec2dd8274c452Philip P. Moltmann
486215440785861d37af3c6056be63ec2dd8274c452Philip P. Moltmann                            if (mediaSize != null) {
487215440785861d37af3c6056be63ec2dd8274c452Philip P. Moltmann                                if (mediaSize.isPortrait() != isPortrait(bitmap)) {
488215440785861d37af3c6056be63ec2dd8274c452Philip P. Moltmann                                    Matrix rotation = new Matrix();
489215440785861d37af3c6056be63ec2dd8274c452Philip P. Moltmann
490215440785861d37af3c6056be63ec2dd8274c452Philip P. Moltmann                                    rotation.postRotate(90);
491215440785861d37af3c6056be63ec2dd8274c452Philip P. Moltmann                                    bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(),
492215440785861d37af3c6056be63ec2dd8274c452Philip P. Moltmann                                            bitmap.getHeight(), rotation, true);
493215440785861d37af3c6056be63ec2dd8274c452Philip P. Moltmann                                }
494215440785861d37af3c6056be63ec2dd8274c452Philip P. Moltmann                            }
495215440785861d37af3c6056be63ec2dd8274c452Philip P. Moltmann                        }
496215440785861d37af3c6056be63ec2dd8274c452Philip P. Moltmann
497975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                        mBitmap = bitmap;
498975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                        if (bitmap != null) {
499975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                            PrintDocumentInfo info = new PrintDocumentInfo.Builder(jobName)
500975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                                    .setContentType(PrintDocumentInfo.CONTENT_TYPE_PHOTO)
501975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                                    .setPageCount(1)
502975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                                    .build();
503215440785861d37af3c6056be63ec2dd8274c452Philip P. Moltmann
504975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                            boolean changed = !newPrintAttributes.equals(oldPrintAttributes);
505975c49f182d754dfe1a38ba0457d6e603b125570John Hoford
506975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                            layoutResultCallback.onLayoutFinished(info, changed);
507975c49f182d754dfe1a38ba0457d6e603b125570John Hoford
508975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                        } else {
509975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                            layoutResultCallback.onLayoutFailed(null);
510975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                        }
511854aed9e83ca17ad558f3aec7fff49ef2153ceafSvetoslav                        mLoadBitmap = null;
512975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                    }
513975c49f182d754dfe1a38ba0457d6e603b125570John Hoford
514975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                    @Override
515975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                    protected void onCancelled(Bitmap result) {
516975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                        // Task was cancelled, report that.
517975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                        layoutResultCallback.onLayoutCancelled();
518854aed9e83ca17ad558f3aec7fff49ef2153ceafSvetoslav                        mLoadBitmap = null;
519975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                    }
520854aed9e83ca17ad558f3aec7fff49ef2153ceafSvetoslav                }.execute();
521975c49f182d754dfe1a38ba0457d6e603b125570John Hoford            }
522975c49f182d754dfe1a38ba0457d6e603b125570John Hoford
523975c49f182d754dfe1a38ba0457d6e603b125570John Hoford            private void cancelLoad() {
524975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                synchronized (mLock) { // prevent race with set null below
525975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                    if (mDecodeOptions != null) {
526975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                        mDecodeOptions.requestCancelDecode();
527975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                        mDecodeOptions = null;
528975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                    }
529975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                }
530975c49f182d754dfe1a38ba0457d6e603b125570John Hoford            }
531975c49f182d754dfe1a38ba0457d6e603b125570John Hoford
532975c49f182d754dfe1a38ba0457d6e603b125570John Hoford            @Override
533975c49f182d754dfe1a38ba0457d6e603b125570John Hoford            public void onFinish() {
534975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                super.onFinish();
535975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                cancelLoad();
536854aed9e83ca17ad558f3aec7fff49ef2153ceafSvetoslav                if (mLoadBitmap != null) {
537854aed9e83ca17ad558f3aec7fff49ef2153ceafSvetoslav                    mLoadBitmap.cancel(true);
538854aed9e83ca17ad558f3aec7fff49ef2153ceafSvetoslav                }
539b4eb9c984f1c6ac8007c74fab239437cf9f6b474Svet Ganov                if (callback != null) {
540b4eb9c984f1c6ac8007c74fab239437cf9f6b474Svet Ganov                    callback.onFinish();
541b4eb9c984f1c6ac8007c74fab239437cf9f6b474Svet Ganov                }
54216ccdd01f9b7b69041decfbd484d6a399aec7904Makoto Onuki                if (mBitmap != null) {
54316ccdd01f9b7b69041decfbd484d6a399aec7904Makoto Onuki                    mBitmap.recycle();
54416ccdd01f9b7b69041decfbd484d6a399aec7904Makoto Onuki                    mBitmap = null;
54516ccdd01f9b7b69041decfbd484d6a399aec7904Makoto Onuki                }
546975c49f182d754dfe1a38ba0457d6e603b125570John Hoford            }
547975c49f182d754dfe1a38ba0457d6e603b125570John Hoford
548975c49f182d754dfe1a38ba0457d6e603b125570John Hoford            @Override
549975c49f182d754dfe1a38ba0457d6e603b125570John Hoford            public void onWrite(PageRange[] pageRanges, ParcelFileDescriptor fileDescriptor,
550975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                                CancellationSignal cancellationSignal,
551975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                                WriteResultCallback writeResultCallback) {
55273cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann                writeBitmap(mAttributes, fittingMode, mBitmap, fileDescriptor, writeResultCallback);
553975c49f182d754dfe1a38ba0457d6e603b125570John Hoford            }
554975c49f182d754dfe1a38ba0457d6e603b125570John Hoford        };
555975c49f182d754dfe1a38ba0457d6e603b125570John Hoford
556975c49f182d754dfe1a38ba0457d6e603b125570John Hoford        PrintManager printManager = (PrintManager) mContext.getSystemService(Context.PRINT_SERVICE);
557975c49f182d754dfe1a38ba0457d6e603b125570John Hoford        PrintAttributes.Builder builder = new PrintAttributes.Builder();
558975c49f182d754dfe1a38ba0457d6e603b125570John Hoford        builder.setColorMode(mColorMode);
559975c49f182d754dfe1a38ba0457d6e603b125570John Hoford
560215440785861d37af3c6056be63ec2dd8274c452Philip P. Moltmann        if (mOrientation == ORIENTATION_LANDSCAPE || mOrientation == 0) {
561975c49f182d754dfe1a38ba0457d6e603b125570John Hoford            builder.setMediaSize(PrintAttributes.MediaSize.UNKNOWN_LANDSCAPE);
562975c49f182d754dfe1a38ba0457d6e603b125570John Hoford        } else if (mOrientation == ORIENTATION_PORTRAIT) {
563975c49f182d754dfe1a38ba0457d6e603b125570John Hoford            builder.setMediaSize(PrintAttributes.MediaSize.UNKNOWN_PORTRAIT);
564975c49f182d754dfe1a38ba0457d6e603b125570John Hoford        }
565975c49f182d754dfe1a38ba0457d6e603b125570John Hoford        PrintAttributes attr = builder.build();
566975c49f182d754dfe1a38ba0457d6e603b125570John Hoford
567975c49f182d754dfe1a38ba0457d6e603b125570John Hoford        printManager.print(jobName, printDocumentAdapter, attr);
568b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav    }
569b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav
570b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav    /**
571b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav     * Loads a bitmap while limiting its size
572b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav     *
573b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav     * @param uri           location of a valid image
574b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav     * @param maxSideLength the maximum length of a size
575b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav     * @return the Bitmap
576b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav     * @throws FileNotFoundException if the Uri does not point to an image
577b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav     */
578b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav    private Bitmap loadConstrainedBitmap(Uri uri, int maxSideLength) throws FileNotFoundException {
579b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav        if (maxSideLength <= 0 || uri == null || mContext == null) {
580b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav            throw new IllegalArgumentException("bad argument to getScaledBitmap");
581b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav        }
582b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav        // Get width and height of stored bitmap
583b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav        BitmapFactory.Options opt = new BitmapFactory.Options();
584b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav        opt.inJustDecodeBounds = true;
585b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav        loadBitmap(uri, opt);
586b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav
587b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav        int w = opt.outWidth;
588b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav        int h = opt.outHeight;
589b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav
590b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav        // If bitmap cannot be decoded, return null
591b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav        if (w <= 0 || h <= 0) {
592b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav            return null;
593b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav        }
594b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav
595b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav        // Find best downsampling size
596b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav        int imageSide = Math.max(w, h);
597b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav
598b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav        int sampleSize = 1;
599b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav        while (imageSide > maxSideLength) {
600b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav            imageSide >>>= 1;
601b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav            sampleSize <<= 1;
602b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav        }
603b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav
604b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav        // Make sure sample size is reasonable
605b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav        if (sampleSize <= 0 || 0 >= (int) (Math.min(w, h) / sampleSize)) {
606b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav            return null;
607b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav        }
608975c49f182d754dfe1a38ba0457d6e603b125570John Hoford        BitmapFactory.Options decodeOptions = null;
609975c49f182d754dfe1a38ba0457d6e603b125570John Hoford        synchronized (mLock) { // prevent race with set null below
610975c49f182d754dfe1a38ba0457d6e603b125570John Hoford            mDecodeOptions = new BitmapFactory.Options();
611975c49f182d754dfe1a38ba0457d6e603b125570John Hoford            mDecodeOptions.inMutable = true;
612975c49f182d754dfe1a38ba0457d6e603b125570John Hoford            mDecodeOptions.inSampleSize = sampleSize;
613975c49f182d754dfe1a38ba0457d6e603b125570John Hoford            decodeOptions = mDecodeOptions;
614975c49f182d754dfe1a38ba0457d6e603b125570John Hoford        }
615975c49f182d754dfe1a38ba0457d6e603b125570John Hoford        try {
616975c49f182d754dfe1a38ba0457d6e603b125570John Hoford            return loadBitmap(uri, decodeOptions);
617975c49f182d754dfe1a38ba0457d6e603b125570John Hoford        } finally {
618975c49f182d754dfe1a38ba0457d6e603b125570John Hoford            synchronized (mLock) {
619975c49f182d754dfe1a38ba0457d6e603b125570John Hoford                mDecodeOptions = null;
620975c49f182d754dfe1a38ba0457d6e603b125570John Hoford            }
621975c49f182d754dfe1a38ba0457d6e603b125570John Hoford        }
622b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav    }
623b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav
624b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav    /**
625b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav     * Returns the bitmap from the given uri loaded using the given options.
626b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav     * Returns null on failure.
627b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav     */
628b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav    private Bitmap loadBitmap(Uri uri, BitmapFactory.Options o) throws FileNotFoundException {
629b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav        if (uri == null || mContext == null) {
630b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav            throw new IllegalArgumentException("bad argument to loadBitmap");
631b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav        }
632b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav        InputStream is = null;
633b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav        try {
634b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav            is = mContext.getContentResolver().openInputStream(uri);
635b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav            return BitmapFactory.decodeStream(is, null, o);
636b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav        } finally {
637545f1bf8b47c12d2453143706a2fd76d9eef2368Svetoslav Ganov            if (is != null) {
638545f1bf8b47c12d2453143706a2fd76d9eef2368Svetoslav Ganov                try {
639545f1bf8b47c12d2453143706a2fd76d9eef2368Svetoslav Ganov                    is.close();
640545f1bf8b47c12d2453143706a2fd76d9eef2368Svetoslav Ganov                } catch (IOException t) {
641545f1bf8b47c12d2453143706a2fd76d9eef2368Svetoslav Ganov                    Log.w(LOG_TAG, "close fail ", t);
642545f1bf8b47c12d2453143706a2fd76d9eef2368Svetoslav Ganov                }
643b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav            }
644b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav        }
645b363776d911abae9d067b9ef77fccc1c3c56e652Svetoslav    }
64616ccdd01f9b7b69041decfbd484d6a399aec7904Makoto Onuki
64716ccdd01f9b7b69041decfbd484d6a399aec7904Makoto Onuki    private Bitmap convertBitmapForColorMode(Bitmap original, int colorMode) {
64816ccdd01f9b7b69041decfbd484d6a399aec7904Makoto Onuki        if (colorMode != COLOR_MODE_MONOCHROME) {
64916ccdd01f9b7b69041decfbd484d6a399aec7904Makoto Onuki            return original;
65016ccdd01f9b7b69041decfbd484d6a399aec7904Makoto Onuki        }
65116ccdd01f9b7b69041decfbd484d6a399aec7904Makoto Onuki        // Create a grayscale bitmap
65216ccdd01f9b7b69041decfbd484d6a399aec7904Makoto Onuki        Bitmap grayscale = Bitmap.createBitmap(original.getWidth(), original.getHeight(),
65316ccdd01f9b7b69041decfbd484d6a399aec7904Makoto Onuki                Config.ARGB_8888);
65416ccdd01f9b7b69041decfbd484d6a399aec7904Makoto Onuki        Canvas c = new Canvas(grayscale);
65516ccdd01f9b7b69041decfbd484d6a399aec7904Makoto Onuki        Paint p = new Paint();
65616ccdd01f9b7b69041decfbd484d6a399aec7904Makoto Onuki        ColorMatrix cm = new ColorMatrix();
65716ccdd01f9b7b69041decfbd484d6a399aec7904Makoto Onuki        cm.setSaturation(0);
65816ccdd01f9b7b69041decfbd484d6a399aec7904Makoto Onuki        ColorMatrixColorFilter f = new ColorMatrixColorFilter(cm);
65916ccdd01f9b7b69041decfbd484d6a399aec7904Makoto Onuki        p.setColorFilter(f);
66016ccdd01f9b7b69041decfbd484d6a399aec7904Makoto Onuki        c.drawBitmap(original, 0, 0, p);
66116ccdd01f9b7b69041decfbd484d6a399aec7904Makoto Onuki        c.setBitmap(null);
66216ccdd01f9b7b69041decfbd484d6a399aec7904Makoto Onuki
66316ccdd01f9b7b69041decfbd484d6a399aec7904Makoto Onuki        return grayscale;
66416ccdd01f9b7b69041decfbd484d6a399aec7904Makoto Onuki    }
66573cad7b8c14ee0003a958e9a30be11e4ecaf304dPhilip P. Moltmann}
666