1b9f7aac3488873677377b36c57338d758098f78eDan Sandler/*
2b9f7aac3488873677377b36c57338d758098f78eDan Sandler * Copyright (C) 2015 The Android Open Source Project
3b9f7aac3488873677377b36c57338d758098f78eDan Sandler *
4b9f7aac3488873677377b36c57338d758098f78eDan Sandler * Licensed under the Apache License, Version 2.0 (the "License");
5b9f7aac3488873677377b36c57338d758098f78eDan Sandler * you may not use this file except in compliance with the License.
6b9f7aac3488873677377b36c57338d758098f78eDan Sandler * You may obtain a copy of the License at
7b9f7aac3488873677377b36c57338d758098f78eDan Sandler *
8b9f7aac3488873677377b36c57338d758098f78eDan Sandler *      http://www.apache.org/licenses/LICENSE-2.0
9b9f7aac3488873677377b36c57338d758098f78eDan Sandler *
10b9f7aac3488873677377b36c57338d758098f78eDan Sandler * Unless required by applicable law or agreed to in writing, software
11b9f7aac3488873677377b36c57338d758098f78eDan Sandler * distributed under the License is distributed on an "AS IS" BASIS,
12b9f7aac3488873677377b36c57338d758098f78eDan Sandler * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13b9f7aac3488873677377b36c57338d758098f78eDan Sandler * See the License for the specific language governing permissions and
14b9f7aac3488873677377b36c57338d758098f78eDan Sandler * limitations under the License.
15b9f7aac3488873677377b36c57338d758098f78eDan Sandler */
16b9f7aac3488873677377b36c57338d758098f78eDan Sandler
17b9f7aac3488873677377b36c57338d758098f78eDan Sandlerpackage android.graphics.drawable;
18b9f7aac3488873677377b36c57338d758098f78eDan Sandler
1924f11b1871f9def5d802d107897658c4b2b66ab5Dan Sandlerimport android.annotation.ColorInt;
20b9f7aac3488873677377b36c57338d758098f78eDan Sandlerimport android.annotation.DrawableRes;
2124f11b1871f9def5d802d107897658c4b2b66ab5Dan Sandlerimport android.content.res.ColorStateList;
22b9f7aac3488873677377b36c57338d758098f78eDan Sandlerimport android.content.ContentResolver;
23cad84a2070b68093ab31b05389685fdbcd0d9f85Santos Cordonimport android.content.Context;
24c7fd3462a2699f73d5f2ba6d863d8be4ddd570a9Julia Reynoldsimport android.content.pm.ApplicationInfo;
25b9f7aac3488873677377b36c57338d758098f78eDan Sandlerimport android.content.pm.PackageManager;
26b9f7aac3488873677377b36c57338d758098f78eDan Sandlerimport android.content.res.Resources;
27b9f7aac3488873677377b36c57338d758098f78eDan Sandlerimport android.graphics.Bitmap;
28b9f7aac3488873677377b36c57338d758098f78eDan Sandlerimport android.graphics.BitmapFactory;
2924f11b1871f9def5d802d107897658c4b2b66ab5Dan Sandlerimport android.graphics.PorterDuff;
30b9f7aac3488873677377b36c57338d758098f78eDan Sandlerimport android.net.Uri;
31b9f7aac3488873677377b36c57338d758098f78eDan Sandlerimport android.os.AsyncTask;
32b9f7aac3488873677377b36c57338d758098f78eDan Sandlerimport android.os.Handler;
33b9f7aac3488873677377b36c57338d758098f78eDan Sandlerimport android.os.Message;
34b9f7aac3488873677377b36c57338d758098f78eDan Sandlerimport android.os.Parcel;
35b9f7aac3488873677377b36c57338d758098f78eDan Sandlerimport android.os.Parcelable;
364e78706f439d318ae7a78927d98f734351a89f64Dan Sandlerimport android.text.TextUtils;
37b9f7aac3488873677377b36c57338d758098f78eDan Sandlerimport android.util.Log;
38b9f7aac3488873677377b36c57338d758098f78eDan Sandler
39cad84a2070b68093ab31b05389685fdbcd0d9f85Santos Cordonimport java.io.DataInputStream;
40cad84a2070b68093ab31b05389685fdbcd0d9f85Santos Cordonimport java.io.DataOutputStream;
41b9f7aac3488873677377b36c57338d758098f78eDan Sandlerimport java.io.File;
42b9f7aac3488873677377b36c57338d758098f78eDan Sandlerimport java.io.FileInputStream;
43b9f7aac3488873677377b36c57338d758098f78eDan Sandlerimport java.io.FileNotFoundException;
44cad84a2070b68093ab31b05389685fdbcd0d9f85Santos Cordonimport java.io.IOException;
45b9f7aac3488873677377b36c57338d758098f78eDan Sandlerimport java.io.InputStream;
46cad84a2070b68093ab31b05389685fdbcd0d9f85Santos Cordonimport java.io.OutputStream;
47b9f7aac3488873677377b36c57338d758098f78eDan Sandler
48b9f7aac3488873677377b36c57338d758098f78eDan Sandler/**
49b9f7aac3488873677377b36c57338d758098f78eDan Sandler * An umbrella container for several serializable graphics representations, including Bitmaps,
50b9f7aac3488873677377b36c57338d758098f78eDan Sandler * compressed bitmap images (e.g. JPG or PNG), and drawable resources (including vectors).
51b9f7aac3488873677377b36c57338d758098f78eDan Sandler *
52b9f7aac3488873677377b36c57338d758098f78eDan Sandler * <a href="https://developer.android.com/training/displaying-bitmaps/index.html">Much ink</a>
53b9f7aac3488873677377b36c57338d758098f78eDan Sandler * has been spilled on the best way to load images, and many clients may have different needs when
54b9f7aac3488873677377b36c57338d758098f78eDan Sandler * it comes to threading and fetching. This class is therefore focused on encapsulation rather than
55b9f7aac3488873677377b36c57338d758098f78eDan Sandler * behavior.
56b9f7aac3488873677377b36c57338d758098f78eDan Sandler */
57b9f7aac3488873677377b36c57338d758098f78eDan Sandler
58b9f7aac3488873677377b36c57338d758098f78eDan Sandlerpublic final class Icon implements Parcelable {
59b9f7aac3488873677377b36c57338d758098f78eDan Sandler    private static final String TAG = "Icon";
60b9f7aac3488873677377b36c57338d758098f78eDan Sandler
61d63f9321e62064660d426efd5abbd885c4a24652Dan Sandler    /** @hide */
62d63f9321e62064660d426efd5abbd885c4a24652Dan Sandler    public static final int TYPE_BITMAP   = 1;
63d63f9321e62064660d426efd5abbd885c4a24652Dan Sandler    /** @hide */
64d63f9321e62064660d426efd5abbd885c4a24652Dan Sandler    public static final int TYPE_RESOURCE = 2;
65d63f9321e62064660d426efd5abbd885c4a24652Dan Sandler    /** @hide */
66d63f9321e62064660d426efd5abbd885c4a24652Dan Sandler    public static final int TYPE_DATA     = 3;
67d63f9321e62064660d426efd5abbd885c4a24652Dan Sandler    /** @hide */
68d63f9321e62064660d426efd5abbd885c4a24652Dan Sandler    public static final int TYPE_URI      = 4;
69b9f7aac3488873677377b36c57338d758098f78eDan Sandler
70cad84a2070b68093ab31b05389685fdbcd0d9f85Santos Cordon    private static final int VERSION_STREAM_SERIALIZER = 1;
71cad84a2070b68093ab31b05389685fdbcd0d9f85Santos Cordon
72b9f7aac3488873677377b36c57338d758098f78eDan Sandler    private final int mType;
73b9f7aac3488873677377b36c57338d758098f78eDan Sandler
7424f11b1871f9def5d802d107897658c4b2b66ab5Dan Sandler    private ColorStateList mTintList;
7524f11b1871f9def5d802d107897658c4b2b66ab5Dan Sandler    static final PorterDuff.Mode DEFAULT_TINT_MODE = Drawable.DEFAULT_TINT_MODE; // SRC_IN
7624f11b1871f9def5d802d107897658c4b2b66ab5Dan Sandler    private PorterDuff.Mode mTintMode = DEFAULT_TINT_MODE;
7724f11b1871f9def5d802d107897658c4b2b66ab5Dan Sandler
78b9f7aac3488873677377b36c57338d758098f78eDan Sandler    // To avoid adding unnecessary overhead, we have a few basic objects that get repurposed
79b9f7aac3488873677377b36c57338d758098f78eDan Sandler    // based on the value of mType.
80b9f7aac3488873677377b36c57338d758098f78eDan Sandler
81b9f7aac3488873677377b36c57338d758098f78eDan Sandler    // TYPE_BITMAP: Bitmap
82b9f7aac3488873677377b36c57338d758098f78eDan Sandler    // TYPE_RESOURCE: Resources
83b9f7aac3488873677377b36c57338d758098f78eDan Sandler    // TYPE_DATA: DataBytes
84b9f7aac3488873677377b36c57338d758098f78eDan Sandler    private Object          mObj1;
85b9f7aac3488873677377b36c57338d758098f78eDan Sandler
86b9f7aac3488873677377b36c57338d758098f78eDan Sandler    // TYPE_RESOURCE: package name
87b9f7aac3488873677377b36c57338d758098f78eDan Sandler    // TYPE_URI: uri string
88b9f7aac3488873677377b36c57338d758098f78eDan Sandler    private String          mString1;
89b9f7aac3488873677377b36c57338d758098f78eDan Sandler
90b9f7aac3488873677377b36c57338d758098f78eDan Sandler    // TYPE_RESOURCE: resId
91b9f7aac3488873677377b36c57338d758098f78eDan Sandler    // TYPE_DATA: data length
92b9f7aac3488873677377b36c57338d758098f78eDan Sandler    private int             mInt1;
93b9f7aac3488873677377b36c57338d758098f78eDan Sandler
94b9f7aac3488873677377b36c57338d758098f78eDan Sandler    // TYPE_DATA: data offset
95b9f7aac3488873677377b36c57338d758098f78eDan Sandler    private int             mInt2;
96b9f7aac3488873677377b36c57338d758098f78eDan Sandler
97d63f9321e62064660d426efd5abbd885c4a24652Dan Sandler    /**
98d63f9321e62064660d426efd5abbd885c4a24652Dan Sandler     * @return The type of image data held in this Icon. One of
99d63f9321e62064660d426efd5abbd885c4a24652Dan Sandler     * {@link #TYPE_BITMAP},
100d63f9321e62064660d426efd5abbd885c4a24652Dan Sandler     * {@link #TYPE_RESOURCE},
101d63f9321e62064660d426efd5abbd885c4a24652Dan Sandler     * {@link #TYPE_DATA}, or
102d63f9321e62064660d426efd5abbd885c4a24652Dan Sandler     * {@link #TYPE_URI}.
103d63f9321e62064660d426efd5abbd885c4a24652Dan Sandler     * @hide
104d63f9321e62064660d426efd5abbd885c4a24652Dan Sandler     */
105d63f9321e62064660d426efd5abbd885c4a24652Dan Sandler    public int getType() {
106d63f9321e62064660d426efd5abbd885c4a24652Dan Sandler        return mType;
107d63f9321e62064660d426efd5abbd885c4a24652Dan Sandler    }
108d63f9321e62064660d426efd5abbd885c4a24652Dan Sandler
109d63f9321e62064660d426efd5abbd885c4a24652Dan Sandler    /**
110d63f9321e62064660d426efd5abbd885c4a24652Dan Sandler     * @return The {@link android.graphics.Bitmap} held by this {@link #TYPE_BITMAP} Icon.
111d63f9321e62064660d426efd5abbd885c4a24652Dan Sandler     * @hide
112d63f9321e62064660d426efd5abbd885c4a24652Dan Sandler     */
113d63f9321e62064660d426efd5abbd885c4a24652Dan Sandler    public Bitmap getBitmap() {
114b9f7aac3488873677377b36c57338d758098f78eDan Sandler        if (mType != TYPE_BITMAP) {
115b9f7aac3488873677377b36c57338d758098f78eDan Sandler            throw new IllegalStateException("called getBitmap() on " + this);
116b9f7aac3488873677377b36c57338d758098f78eDan Sandler        }
117b9f7aac3488873677377b36c57338d758098f78eDan Sandler        return (Bitmap) mObj1;
118b9f7aac3488873677377b36c57338d758098f78eDan Sandler    }
119b9f7aac3488873677377b36c57338d758098f78eDan Sandler
120a0d58ae574a3a69145512e0cd92e7842f0fbf83dJorim Jaggi    private void setBitmap(Bitmap b) {
121a0d58ae574a3a69145512e0cd92e7842f0fbf83dJorim Jaggi        mObj1 = b;
122a0d58ae574a3a69145512e0cd92e7842f0fbf83dJorim Jaggi    }
123a0d58ae574a3a69145512e0cd92e7842f0fbf83dJorim Jaggi
124d63f9321e62064660d426efd5abbd885c4a24652Dan Sandler    /**
125d63f9321e62064660d426efd5abbd885c4a24652Dan Sandler     * @return The length of the compressed bitmap byte array held by this {@link #TYPE_DATA} Icon.
126d63f9321e62064660d426efd5abbd885c4a24652Dan Sandler     * @hide
127d63f9321e62064660d426efd5abbd885c4a24652Dan Sandler     */
128d63f9321e62064660d426efd5abbd885c4a24652Dan Sandler    public int getDataLength() {
129b9f7aac3488873677377b36c57338d758098f78eDan Sandler        if (mType != TYPE_DATA) {
130b9f7aac3488873677377b36c57338d758098f78eDan Sandler            throw new IllegalStateException("called getDataLength() on " + this);
131b9f7aac3488873677377b36c57338d758098f78eDan Sandler        }
132b9f7aac3488873677377b36c57338d758098f78eDan Sandler        synchronized (this) {
133b9f7aac3488873677377b36c57338d758098f78eDan Sandler            return mInt1;
134b9f7aac3488873677377b36c57338d758098f78eDan Sandler        }
135b9f7aac3488873677377b36c57338d758098f78eDan Sandler    }
136b9f7aac3488873677377b36c57338d758098f78eDan Sandler
137d63f9321e62064660d426efd5abbd885c4a24652Dan Sandler    /**
138d63f9321e62064660d426efd5abbd885c4a24652Dan Sandler     * @return The offset into the byte array held by this {@link #TYPE_DATA} Icon at which
139d63f9321e62064660d426efd5abbd885c4a24652Dan Sandler     * valid compressed bitmap data is found.
140d63f9321e62064660d426efd5abbd885c4a24652Dan Sandler     * @hide
141d63f9321e62064660d426efd5abbd885c4a24652Dan Sandler     */
142d63f9321e62064660d426efd5abbd885c4a24652Dan Sandler    public int getDataOffset() {
143b9f7aac3488873677377b36c57338d758098f78eDan Sandler        if (mType != TYPE_DATA) {
144b9f7aac3488873677377b36c57338d758098f78eDan Sandler            throw new IllegalStateException("called getDataOffset() on " + this);
145b9f7aac3488873677377b36c57338d758098f78eDan Sandler        }
146b9f7aac3488873677377b36c57338d758098f78eDan Sandler        synchronized (this) {
147b9f7aac3488873677377b36c57338d758098f78eDan Sandler            return mInt2;
148b9f7aac3488873677377b36c57338d758098f78eDan Sandler        }
149b9f7aac3488873677377b36c57338d758098f78eDan Sandler    }
150b9f7aac3488873677377b36c57338d758098f78eDan Sandler
151d63f9321e62064660d426efd5abbd885c4a24652Dan Sandler    /**
152d63f9321e62064660d426efd5abbd885c4a24652Dan Sandler     * @return The byte array held by this {@link #TYPE_DATA} Icon ctonaining compressed
153d63f9321e62064660d426efd5abbd885c4a24652Dan Sandler     * bitmap data.
154d63f9321e62064660d426efd5abbd885c4a24652Dan Sandler     * @hide
155d63f9321e62064660d426efd5abbd885c4a24652Dan Sandler     */
156d63f9321e62064660d426efd5abbd885c4a24652Dan Sandler    public byte[] getDataBytes() {
157b9f7aac3488873677377b36c57338d758098f78eDan Sandler        if (mType != TYPE_DATA) {
158b9f7aac3488873677377b36c57338d758098f78eDan Sandler            throw new IllegalStateException("called getDataBytes() on " + this);
159b9f7aac3488873677377b36c57338d758098f78eDan Sandler        }
160b9f7aac3488873677377b36c57338d758098f78eDan Sandler        synchronized (this) {
161b9f7aac3488873677377b36c57338d758098f78eDan Sandler            return (byte[]) mObj1;
162b9f7aac3488873677377b36c57338d758098f78eDan Sandler        }
163b9f7aac3488873677377b36c57338d758098f78eDan Sandler    }
164b9f7aac3488873677377b36c57338d758098f78eDan Sandler
165d63f9321e62064660d426efd5abbd885c4a24652Dan Sandler    /**
166d63f9321e62064660d426efd5abbd885c4a24652Dan Sandler     * @return The {@link android.content.res.Resources} for this {@link #TYPE_RESOURCE} Icon.
167d63f9321e62064660d426efd5abbd885c4a24652Dan Sandler     * @hide
168d63f9321e62064660d426efd5abbd885c4a24652Dan Sandler     */
169d63f9321e62064660d426efd5abbd885c4a24652Dan Sandler    public Resources getResources() {
170b9f7aac3488873677377b36c57338d758098f78eDan Sandler        if (mType != TYPE_RESOURCE) {
171b9f7aac3488873677377b36c57338d758098f78eDan Sandler            throw new IllegalStateException("called getResources() on " + this);
172b9f7aac3488873677377b36c57338d758098f78eDan Sandler        }
173b9f7aac3488873677377b36c57338d758098f78eDan Sandler        return (Resources) mObj1;
174b9f7aac3488873677377b36c57338d758098f78eDan Sandler    }
175b9f7aac3488873677377b36c57338d758098f78eDan Sandler
176d63f9321e62064660d426efd5abbd885c4a24652Dan Sandler    /**
177d63f9321e62064660d426efd5abbd885c4a24652Dan Sandler     * @return The package containing resources for this {@link #TYPE_RESOURCE} Icon.
178d63f9321e62064660d426efd5abbd885c4a24652Dan Sandler     * @hide
179d63f9321e62064660d426efd5abbd885c4a24652Dan Sandler     */
180d63f9321e62064660d426efd5abbd885c4a24652Dan Sandler    public String getResPackage() {
181b9f7aac3488873677377b36c57338d758098f78eDan Sandler        if (mType != TYPE_RESOURCE) {
182b9f7aac3488873677377b36c57338d758098f78eDan Sandler            throw new IllegalStateException("called getResPackage() on " + this);
183b9f7aac3488873677377b36c57338d758098f78eDan Sandler        }
184b9f7aac3488873677377b36c57338d758098f78eDan Sandler        return mString1;
185b9f7aac3488873677377b36c57338d758098f78eDan Sandler    }
186b9f7aac3488873677377b36c57338d758098f78eDan Sandler
187d63f9321e62064660d426efd5abbd885c4a24652Dan Sandler    /**
188d63f9321e62064660d426efd5abbd885c4a24652Dan Sandler     * @return The resource ID for this {@link #TYPE_RESOURCE} Icon.
189d63f9321e62064660d426efd5abbd885c4a24652Dan Sandler     * @hide
190d63f9321e62064660d426efd5abbd885c4a24652Dan Sandler     */
191d63f9321e62064660d426efd5abbd885c4a24652Dan Sandler    public int getResId() {
192b9f7aac3488873677377b36c57338d758098f78eDan Sandler        if (mType != TYPE_RESOURCE) {
193b9f7aac3488873677377b36c57338d758098f78eDan Sandler            throw new IllegalStateException("called getResId() on " + this);
194b9f7aac3488873677377b36c57338d758098f78eDan Sandler        }
195b9f7aac3488873677377b36c57338d758098f78eDan Sandler        return mInt1;
196b9f7aac3488873677377b36c57338d758098f78eDan Sandler    }
197b9f7aac3488873677377b36c57338d758098f78eDan Sandler
198d63f9321e62064660d426efd5abbd885c4a24652Dan Sandler    /**
199d63f9321e62064660d426efd5abbd885c4a24652Dan Sandler     * @return The URI (as a String) for this {@link #TYPE_URI} Icon.
200d63f9321e62064660d426efd5abbd885c4a24652Dan Sandler     * @hide
201d63f9321e62064660d426efd5abbd885c4a24652Dan Sandler     */
202d63f9321e62064660d426efd5abbd885c4a24652Dan Sandler    public String getUriString() {
203b9f7aac3488873677377b36c57338d758098f78eDan Sandler        if (mType != TYPE_URI) {
204b9f7aac3488873677377b36c57338d758098f78eDan Sandler            throw new IllegalStateException("called getUriString() on " + this);
205b9f7aac3488873677377b36c57338d758098f78eDan Sandler        }
206b9f7aac3488873677377b36c57338d758098f78eDan Sandler        return mString1;
207b9f7aac3488873677377b36c57338d758098f78eDan Sandler    }
208b9f7aac3488873677377b36c57338d758098f78eDan Sandler
209d63f9321e62064660d426efd5abbd885c4a24652Dan Sandler    /**
210d63f9321e62064660d426efd5abbd885c4a24652Dan Sandler     * @return The {@link android.net.Uri} for this {@link #TYPE_URI} Icon.
211d63f9321e62064660d426efd5abbd885c4a24652Dan Sandler     * @hide
212d63f9321e62064660d426efd5abbd885c4a24652Dan Sandler     */
213d63f9321e62064660d426efd5abbd885c4a24652Dan Sandler    public Uri getUri() {
214b9f7aac3488873677377b36c57338d758098f78eDan Sandler        return Uri.parse(getUriString());
215b9f7aac3488873677377b36c57338d758098f78eDan Sandler    }
216b9f7aac3488873677377b36c57338d758098f78eDan Sandler
217b9f7aac3488873677377b36c57338d758098f78eDan Sandler    private static final String typeToString(int x) {
218b9f7aac3488873677377b36c57338d758098f78eDan Sandler        switch (x) {
219b9f7aac3488873677377b36c57338d758098f78eDan Sandler            case TYPE_BITMAP: return "BITMAP";
220b9f7aac3488873677377b36c57338d758098f78eDan Sandler            case TYPE_DATA: return "DATA";
221b9f7aac3488873677377b36c57338d758098f78eDan Sandler            case TYPE_RESOURCE: return "RESOURCE";
222b9f7aac3488873677377b36c57338d758098f78eDan Sandler            case TYPE_URI: return "URI";
223b9f7aac3488873677377b36c57338d758098f78eDan Sandler            default: return "UNKNOWN";
224b9f7aac3488873677377b36c57338d758098f78eDan Sandler        }
225b9f7aac3488873677377b36c57338d758098f78eDan Sandler    }
226b9f7aac3488873677377b36c57338d758098f78eDan Sandler
227b9f7aac3488873677377b36c57338d758098f78eDan Sandler    /**
228b9f7aac3488873677377b36c57338d758098f78eDan Sandler     * Invokes {@link #loadDrawable(Context)} on the given {@link android.os.Handler Handler}
229b9f7aac3488873677377b36c57338d758098f78eDan Sandler     * and then sends <code>andThen</code> to the same Handler when finished.
230b9f7aac3488873677377b36c57338d758098f78eDan Sandler     *
231b9f7aac3488873677377b36c57338d758098f78eDan Sandler     * @param context {@link android.content.Context Context} in which to load the drawable; see
232b9f7aac3488873677377b36c57338d758098f78eDan Sandler     *                {@link #loadDrawable(Context)}
233b9f7aac3488873677377b36c57338d758098f78eDan Sandler     * @param andThen {@link android.os.Message} to send to its target once the drawable
234b9f7aac3488873677377b36c57338d758098f78eDan Sandler     *                is available. The {@link android.os.Message#obj obj}
235b9f7aac3488873677377b36c57338d758098f78eDan Sandler     *                property is populated with the Drawable.
236b9f7aac3488873677377b36c57338d758098f78eDan Sandler     */
237b9f7aac3488873677377b36c57338d758098f78eDan Sandler    public void loadDrawableAsync(Context context, Message andThen) {
238b9f7aac3488873677377b36c57338d758098f78eDan Sandler        if (andThen.getTarget() == null) {
239b9f7aac3488873677377b36c57338d758098f78eDan Sandler            throw new IllegalArgumentException("callback message must have a target handler");
240b9f7aac3488873677377b36c57338d758098f78eDan Sandler        }
241b9f7aac3488873677377b36c57338d758098f78eDan Sandler        new LoadDrawableTask(context, andThen).runAsync();
242b9f7aac3488873677377b36c57338d758098f78eDan Sandler    }
243b9f7aac3488873677377b36c57338d758098f78eDan Sandler
244b9f7aac3488873677377b36c57338d758098f78eDan Sandler    /**
245b9f7aac3488873677377b36c57338d758098f78eDan Sandler     * Invokes {@link #loadDrawable(Context)} on a background thread
246b9f7aac3488873677377b36c57338d758098f78eDan Sandler     * and then runs <code>andThen</code> on the UI thread when finished.
247b9f7aac3488873677377b36c57338d758098f78eDan Sandler     *
248877d696c382ecb8a97972450c8819536641a963cDan Sandler     * @param context {@link Context Context} in which to load the drawable; see
249b9f7aac3488873677377b36c57338d758098f78eDan Sandler     *                {@link #loadDrawable(Context)}
250b9f7aac3488873677377b36c57338d758098f78eDan Sandler     * @param listener a callback to run on the provided
251877d696c382ecb8a97972450c8819536641a963cDan Sandler     * @param handler {@link Handler} on which to run <code>andThen</code>.
252b9f7aac3488873677377b36c57338d758098f78eDan Sandler     */
253877d696c382ecb8a97972450c8819536641a963cDan Sandler    public void loadDrawableAsync(Context context, final OnDrawableLoadedListener listener,
254877d696c382ecb8a97972450c8819536641a963cDan Sandler            Handler handler) {
255b9f7aac3488873677377b36c57338d758098f78eDan Sandler        new LoadDrawableTask(context, handler, listener).runAsync();
256b9f7aac3488873677377b36c57338d758098f78eDan Sandler    }
257b9f7aac3488873677377b36c57338d758098f78eDan Sandler
258b9f7aac3488873677377b36c57338d758098f78eDan Sandler    /**
259b9f7aac3488873677377b36c57338d758098f78eDan Sandler     * Returns a Drawable that can be used to draw the image inside this Icon, constructing it
260b9f7aac3488873677377b36c57338d758098f78eDan Sandler     * if necessary. Depending on the type of image, this may not be something you want to do on
261b9f7aac3488873677377b36c57338d758098f78eDan Sandler     * the UI thread, so consider using
262b9f7aac3488873677377b36c57338d758098f78eDan Sandler     * {@link #loadDrawableAsync(Context, Message) loadDrawableAsync} instead.
263b9f7aac3488873677377b36c57338d758098f78eDan Sandler     *
264b9f7aac3488873677377b36c57338d758098f78eDan Sandler     * @param context {@link android.content.Context Context} in which to load the drawable; used
265b9f7aac3488873677377b36c57338d758098f78eDan Sandler     *                to access {@link android.content.res.Resources Resources}, for example.
266b9f7aac3488873677377b36c57338d758098f78eDan Sandler     * @return A fresh instance of a drawable for this image, yours to keep.
267b9f7aac3488873677377b36c57338d758098f78eDan Sandler     */
268b9f7aac3488873677377b36c57338d758098f78eDan Sandler    public Drawable loadDrawable(Context context) {
26924f11b1871f9def5d802d107897658c4b2b66ab5Dan Sandler        final Drawable result = loadDrawableInner(context);
27024f11b1871f9def5d802d107897658c4b2b66ab5Dan Sandler        if (result != null && (mTintList != null || mTintMode != DEFAULT_TINT_MODE)) {
27124f11b1871f9def5d802d107897658c4b2b66ab5Dan Sandler            result.mutate();
27224f11b1871f9def5d802d107897658c4b2b66ab5Dan Sandler            result.setTintList(mTintList);
27324f11b1871f9def5d802d107897658c4b2b66ab5Dan Sandler            result.setTintMode(mTintMode);
27424f11b1871f9def5d802d107897658c4b2b66ab5Dan Sandler        }
27524f11b1871f9def5d802d107897658c4b2b66ab5Dan Sandler        return result;
27624f11b1871f9def5d802d107897658c4b2b66ab5Dan Sandler    }
27724f11b1871f9def5d802d107897658c4b2b66ab5Dan Sandler
27824f11b1871f9def5d802d107897658c4b2b66ab5Dan Sandler    /**
27924f11b1871f9def5d802d107897658c4b2b66ab5Dan Sandler     * Do the heavy lifting of loading the drawable, but stop short of applying any tint.
28024f11b1871f9def5d802d107897658c4b2b66ab5Dan Sandler     */
28124f11b1871f9def5d802d107897658c4b2b66ab5Dan Sandler    private Drawable loadDrawableInner(Context context) {
282b9f7aac3488873677377b36c57338d758098f78eDan Sandler        switch (mType) {
283b9f7aac3488873677377b36c57338d758098f78eDan Sandler            case TYPE_BITMAP:
284b9f7aac3488873677377b36c57338d758098f78eDan Sandler                return new BitmapDrawable(context.getResources(), getBitmap());
285b9f7aac3488873677377b36c57338d758098f78eDan Sandler            case TYPE_RESOURCE:
286b9f7aac3488873677377b36c57338d758098f78eDan Sandler                if (getResources() == null) {
2874e78706f439d318ae7a78927d98f734351a89f64Dan Sandler                    // figure out where to load resources from
2884e78706f439d318ae7a78927d98f734351a89f64Dan Sandler                    String resPackage = getResPackage();
2894e78706f439d318ae7a78927d98f734351a89f64Dan Sandler                    if (TextUtils.isEmpty(resPackage)) {
2904e78706f439d318ae7a78927d98f734351a89f64Dan Sandler                        // if none is specified, try the given context
2914e78706f439d318ae7a78927d98f734351a89f64Dan Sandler                        resPackage = context.getPackageName();
2924e78706f439d318ae7a78927d98f734351a89f64Dan Sandler                    }
2934e78706f439d318ae7a78927d98f734351a89f64Dan Sandler                    if ("android".equals(resPackage)) {
294b9f7aac3488873677377b36c57338d758098f78eDan Sandler                        mObj1 = Resources.getSystem();
295b9f7aac3488873677377b36c57338d758098f78eDan Sandler                    } else {
296b9f7aac3488873677377b36c57338d758098f78eDan Sandler                        final PackageManager pm = context.getPackageManager();
297b9f7aac3488873677377b36c57338d758098f78eDan Sandler                        try {
298c7fd3462a2699f73d5f2ba6d863d8be4ddd570a9Julia Reynolds                            ApplicationInfo ai = pm.getApplicationInfo(
299c7fd3462a2699f73d5f2ba6d863d8be4ddd570a9Julia Reynolds                                    resPackage, PackageManager.GET_UNINSTALLED_PACKAGES);
300c7fd3462a2699f73d5f2ba6d863d8be4ddd570a9Julia Reynolds                            if (ai != null) {
301c7fd3462a2699f73d5f2ba6d863d8be4ddd570a9Julia Reynolds                                mObj1 = pm.getResourcesForApplication(ai);
302c7fd3462a2699f73d5f2ba6d863d8be4ddd570a9Julia Reynolds                            } else {
303c7fd3462a2699f73d5f2ba6d863d8be4ddd570a9Julia Reynolds                                break;
304c7fd3462a2699f73d5f2ba6d863d8be4ddd570a9Julia Reynolds                            }
305b9f7aac3488873677377b36c57338d758098f78eDan Sandler                        } catch (PackageManager.NameNotFoundException e) {
3064e78706f439d318ae7a78927d98f734351a89f64Dan Sandler                            Log.e(TAG, String.format("Unable to find pkg=%s for icon %s",
3074e78706f439d318ae7a78927d98f734351a89f64Dan Sandler                                    resPackage, this), e);
308b9f7aac3488873677377b36c57338d758098f78eDan Sandler                            break;
309b9f7aac3488873677377b36c57338d758098f78eDan Sandler                        }
310b9f7aac3488873677377b36c57338d758098f78eDan Sandler                    }
311b9f7aac3488873677377b36c57338d758098f78eDan Sandler                }
312877d696c382ecb8a97972450c8819536641a963cDan Sandler                try {
313877d696c382ecb8a97972450c8819536641a963cDan Sandler                    return getResources().getDrawable(getResId(), context.getTheme());
314877d696c382ecb8a97972450c8819536641a963cDan Sandler                } catch (RuntimeException e) {
315877d696c382ecb8a97972450c8819536641a963cDan Sandler                    Log.e(TAG, String.format("Unable to load resource 0x%08x from pkg=%s",
316877d696c382ecb8a97972450c8819536641a963cDan Sandler                                    getResId(),
317877d696c382ecb8a97972450c8819536641a963cDan Sandler                                    getResPackage()),
318877d696c382ecb8a97972450c8819536641a963cDan Sandler                            e);
319877d696c382ecb8a97972450c8819536641a963cDan Sandler                }
320220239e37110bf7d97aa92270be5a12ab0cf5e24Yorke Lee                break;
321b9f7aac3488873677377b36c57338d758098f78eDan Sandler            case TYPE_DATA:
322b9f7aac3488873677377b36c57338d758098f78eDan Sandler                return new BitmapDrawable(context.getResources(),
323b9f7aac3488873677377b36c57338d758098f78eDan Sandler                    BitmapFactory.decodeByteArray(getDataBytes(), getDataOffset(), getDataLength())
324b9f7aac3488873677377b36c57338d758098f78eDan Sandler                );
325b9f7aac3488873677377b36c57338d758098f78eDan Sandler            case TYPE_URI:
326b9f7aac3488873677377b36c57338d758098f78eDan Sandler                final Uri uri = getUri();
327b9f7aac3488873677377b36c57338d758098f78eDan Sandler                final String scheme = uri.getScheme();
328b9f7aac3488873677377b36c57338d758098f78eDan Sandler                InputStream is = null;
329b9f7aac3488873677377b36c57338d758098f78eDan Sandler                if (ContentResolver.SCHEME_CONTENT.equals(scheme)
330b9f7aac3488873677377b36c57338d758098f78eDan Sandler                        || ContentResolver.SCHEME_FILE.equals(scheme)) {
331b9f7aac3488873677377b36c57338d758098f78eDan Sandler                    try {
332b9f7aac3488873677377b36c57338d758098f78eDan Sandler                        is = context.getContentResolver().openInputStream(uri);
333b9f7aac3488873677377b36c57338d758098f78eDan Sandler                    } catch (Exception e) {
334b9f7aac3488873677377b36c57338d758098f78eDan Sandler                        Log.w(TAG, "Unable to load image from URI: " + uri, e);
335b9f7aac3488873677377b36c57338d758098f78eDan Sandler                    }
336b9f7aac3488873677377b36c57338d758098f78eDan Sandler                } else {
337b9f7aac3488873677377b36c57338d758098f78eDan Sandler                    try {
338b9f7aac3488873677377b36c57338d758098f78eDan Sandler                        is = new FileInputStream(new File(mString1));
339b9f7aac3488873677377b36c57338d758098f78eDan Sandler                    } catch (FileNotFoundException e) {
340b9f7aac3488873677377b36c57338d758098f78eDan Sandler                        Log.w(TAG, "Unable to load image from path: " + uri, e);
341b9f7aac3488873677377b36c57338d758098f78eDan Sandler                    }
342b9f7aac3488873677377b36c57338d758098f78eDan Sandler                }
343b9f7aac3488873677377b36c57338d758098f78eDan Sandler                if (is != null) {
344b9f7aac3488873677377b36c57338d758098f78eDan Sandler                    return new BitmapDrawable(context.getResources(),
345b9f7aac3488873677377b36c57338d758098f78eDan Sandler                            BitmapFactory.decodeStream(is));
346b9f7aac3488873677377b36c57338d758098f78eDan Sandler                }
347b9f7aac3488873677377b36c57338d758098f78eDan Sandler                break;
348b9f7aac3488873677377b36c57338d758098f78eDan Sandler        }
349b9f7aac3488873677377b36c57338d758098f78eDan Sandler        return null;
350b9f7aac3488873677377b36c57338d758098f78eDan Sandler    }
351b9f7aac3488873677377b36c57338d758098f78eDan Sandler
352877d696c382ecb8a97972450c8819536641a963cDan Sandler    /**
353877d696c382ecb8a97972450c8819536641a963cDan Sandler     * Load the requested resources under the given userId, if the system allows it,
354877d696c382ecb8a97972450c8819536641a963cDan Sandler     * before actually loading the drawable.
355877d696c382ecb8a97972450c8819536641a963cDan Sandler     *
356877d696c382ecb8a97972450c8819536641a963cDan Sandler     * @hide
357877d696c382ecb8a97972450c8819536641a963cDan Sandler     */
358877d696c382ecb8a97972450c8819536641a963cDan Sandler    public Drawable loadDrawableAsUser(Context context, int userId) {
359877d696c382ecb8a97972450c8819536641a963cDan Sandler        if (mType == TYPE_RESOURCE) {
3604e78706f439d318ae7a78927d98f734351a89f64Dan Sandler            String resPackage = getResPackage();
3614e78706f439d318ae7a78927d98f734351a89f64Dan Sandler            if (TextUtils.isEmpty(resPackage)) {
3624e78706f439d318ae7a78927d98f734351a89f64Dan Sandler                resPackage = context.getPackageName();
3634e78706f439d318ae7a78927d98f734351a89f64Dan Sandler            }
3644e78706f439d318ae7a78927d98f734351a89f64Dan Sandler            if (getResources() == null && !(getResPackage().equals("android"))) {
365877d696c382ecb8a97972450c8819536641a963cDan Sandler                final PackageManager pm = context.getPackageManager();
366877d696c382ecb8a97972450c8819536641a963cDan Sandler                try {
3674e78706f439d318ae7a78927d98f734351a89f64Dan Sandler                    // assign getResources() as the correct user
3684e78706f439d318ae7a78927d98f734351a89f64Dan Sandler                    mObj1 = pm.getResourcesForApplicationAsUser(resPackage, userId);
369877d696c382ecb8a97972450c8819536641a963cDan Sandler                } catch (PackageManager.NameNotFoundException e) {
370877d696c382ecb8a97972450c8819536641a963cDan Sandler                    Log.e(TAG, String.format("Unable to find pkg=%s user=%d",
371877d696c382ecb8a97972450c8819536641a963cDan Sandler                                    getResPackage(),
372877d696c382ecb8a97972450c8819536641a963cDan Sandler                                    userId),
373877d696c382ecb8a97972450c8819536641a963cDan Sandler                            e);
374877d696c382ecb8a97972450c8819536641a963cDan Sandler                }
375877d696c382ecb8a97972450c8819536641a963cDan Sandler            }
376877d696c382ecb8a97972450c8819536641a963cDan Sandler        }
377877d696c382ecb8a97972450c8819536641a963cDan Sandler        return loadDrawable(context);
378877d696c382ecb8a97972450c8819536641a963cDan Sandler    }
379877d696c382ecb8a97972450c8819536641a963cDan Sandler
380cad84a2070b68093ab31b05389685fdbcd0d9f85Santos Cordon    /**
381a0d58ae574a3a69145512e0cd92e7842f0fbf83dJorim Jaggi     * Puts the memory used by this instance into Ashmem memory, if possible.
382a0d58ae574a3a69145512e0cd92e7842f0fbf83dJorim Jaggi     * @hide
383a0d58ae574a3a69145512e0cd92e7842f0fbf83dJorim Jaggi     */
384a0d58ae574a3a69145512e0cd92e7842f0fbf83dJorim Jaggi    public void convertToAshmem() {
385a0d58ae574a3a69145512e0cd92e7842f0fbf83dJorim Jaggi        if (mType == TYPE_BITMAP && getBitmap().isMutable()) {
386a0d58ae574a3a69145512e0cd92e7842f0fbf83dJorim Jaggi            setBitmap(getBitmap().createAshmemBitmap());
387a0d58ae574a3a69145512e0cd92e7842f0fbf83dJorim Jaggi        }
388a0d58ae574a3a69145512e0cd92e7842f0fbf83dJorim Jaggi    }
389a0d58ae574a3a69145512e0cd92e7842f0fbf83dJorim Jaggi
390a0d58ae574a3a69145512e0cd92e7842f0fbf83dJorim Jaggi    /**
391cad84a2070b68093ab31b05389685fdbcd0d9f85Santos Cordon     * Writes a serialized version of an Icon to the specified stream.
392cad84a2070b68093ab31b05389685fdbcd0d9f85Santos Cordon     *
393cad84a2070b68093ab31b05389685fdbcd0d9f85Santos Cordon     * @param stream The stream on which to serialize the Icon.
394cad84a2070b68093ab31b05389685fdbcd0d9f85Santos Cordon     * @hide
395cad84a2070b68093ab31b05389685fdbcd0d9f85Santos Cordon     */
396cad84a2070b68093ab31b05389685fdbcd0d9f85Santos Cordon    public void writeToStream(OutputStream stream) throws IOException {
397cad84a2070b68093ab31b05389685fdbcd0d9f85Santos Cordon        DataOutputStream dataStream = new DataOutputStream(stream);
398cad84a2070b68093ab31b05389685fdbcd0d9f85Santos Cordon
399cad84a2070b68093ab31b05389685fdbcd0d9f85Santos Cordon        dataStream.writeInt(VERSION_STREAM_SERIALIZER);
400cad84a2070b68093ab31b05389685fdbcd0d9f85Santos Cordon        dataStream.writeByte(mType);
401cad84a2070b68093ab31b05389685fdbcd0d9f85Santos Cordon
402cad84a2070b68093ab31b05389685fdbcd0d9f85Santos Cordon        switch (mType) {
403cad84a2070b68093ab31b05389685fdbcd0d9f85Santos Cordon            case TYPE_BITMAP:
404cad84a2070b68093ab31b05389685fdbcd0d9f85Santos Cordon                getBitmap().compress(Bitmap.CompressFormat.PNG, 100, dataStream);
405cad84a2070b68093ab31b05389685fdbcd0d9f85Santos Cordon                break;
406cad84a2070b68093ab31b05389685fdbcd0d9f85Santos Cordon            case TYPE_DATA:
407cad84a2070b68093ab31b05389685fdbcd0d9f85Santos Cordon                dataStream.writeInt(getDataLength());
408cad84a2070b68093ab31b05389685fdbcd0d9f85Santos Cordon                dataStream.write(getDataBytes(), getDataOffset(), getDataLength());
409cad84a2070b68093ab31b05389685fdbcd0d9f85Santos Cordon                break;
410cad84a2070b68093ab31b05389685fdbcd0d9f85Santos Cordon            case TYPE_RESOURCE:
411cad84a2070b68093ab31b05389685fdbcd0d9f85Santos Cordon                dataStream.writeUTF(getResPackage());
412cad84a2070b68093ab31b05389685fdbcd0d9f85Santos Cordon                dataStream.writeInt(getResId());
413cad84a2070b68093ab31b05389685fdbcd0d9f85Santos Cordon                break;
414cad84a2070b68093ab31b05389685fdbcd0d9f85Santos Cordon            case TYPE_URI:
415cad84a2070b68093ab31b05389685fdbcd0d9f85Santos Cordon                dataStream.writeUTF(getUriString());
416cad84a2070b68093ab31b05389685fdbcd0d9f85Santos Cordon                break;
417cad84a2070b68093ab31b05389685fdbcd0d9f85Santos Cordon        }
418cad84a2070b68093ab31b05389685fdbcd0d9f85Santos Cordon    }
419cad84a2070b68093ab31b05389685fdbcd0d9f85Santos Cordon
420b9f7aac3488873677377b36c57338d758098f78eDan Sandler    private Icon(int mType) {
421b9f7aac3488873677377b36c57338d758098f78eDan Sandler        this.mType = mType;
422b9f7aac3488873677377b36c57338d758098f78eDan Sandler    }
423b9f7aac3488873677377b36c57338d758098f78eDan Sandler
424b9f7aac3488873677377b36c57338d758098f78eDan Sandler    /**
425cad84a2070b68093ab31b05389685fdbcd0d9f85Santos Cordon     * Create an Icon from the specified stream.
426cad84a2070b68093ab31b05389685fdbcd0d9f85Santos Cordon     *
427cad84a2070b68093ab31b05389685fdbcd0d9f85Santos Cordon     * @param stream The input stream from which to reconstruct the Icon.
428cad84a2070b68093ab31b05389685fdbcd0d9f85Santos Cordon     * @hide
429cad84a2070b68093ab31b05389685fdbcd0d9f85Santos Cordon     */
430cad84a2070b68093ab31b05389685fdbcd0d9f85Santos Cordon    public static Icon createFromStream(InputStream stream) throws IOException {
431cad84a2070b68093ab31b05389685fdbcd0d9f85Santos Cordon        DataInputStream inputStream = new DataInputStream(stream);
432cad84a2070b68093ab31b05389685fdbcd0d9f85Santos Cordon
433cad84a2070b68093ab31b05389685fdbcd0d9f85Santos Cordon        final int version = inputStream.readInt();
434cad84a2070b68093ab31b05389685fdbcd0d9f85Santos Cordon        if (version >= VERSION_STREAM_SERIALIZER) {
435cad84a2070b68093ab31b05389685fdbcd0d9f85Santos Cordon            final int type = inputStream.readByte();
436cad84a2070b68093ab31b05389685fdbcd0d9f85Santos Cordon            switch (type) {
437cad84a2070b68093ab31b05389685fdbcd0d9f85Santos Cordon                case TYPE_BITMAP:
438cad84a2070b68093ab31b05389685fdbcd0d9f85Santos Cordon                    return createWithBitmap(BitmapFactory.decodeStream(inputStream));
439cad84a2070b68093ab31b05389685fdbcd0d9f85Santos Cordon                case TYPE_DATA:
440cad84a2070b68093ab31b05389685fdbcd0d9f85Santos Cordon                    final int length = inputStream.readInt();
441cad84a2070b68093ab31b05389685fdbcd0d9f85Santos Cordon                    final byte[] data = new byte[length];
442cad84a2070b68093ab31b05389685fdbcd0d9f85Santos Cordon                    inputStream.read(data, 0 /* offset */, length);
443cad84a2070b68093ab31b05389685fdbcd0d9f85Santos Cordon                    return createWithData(data, 0 /* offset */, length);
444cad84a2070b68093ab31b05389685fdbcd0d9f85Santos Cordon                case TYPE_RESOURCE:
445cad84a2070b68093ab31b05389685fdbcd0d9f85Santos Cordon                    final String packageName = inputStream.readUTF();
446cad84a2070b68093ab31b05389685fdbcd0d9f85Santos Cordon                    final int resId = inputStream.readInt();
447cad84a2070b68093ab31b05389685fdbcd0d9f85Santos Cordon                    return createWithResource(packageName, resId);
448cad84a2070b68093ab31b05389685fdbcd0d9f85Santos Cordon                case TYPE_URI:
449cad84a2070b68093ab31b05389685fdbcd0d9f85Santos Cordon                    final String uriOrPath = inputStream.readUTF();
450cad84a2070b68093ab31b05389685fdbcd0d9f85Santos Cordon                    return createWithContentUri(uriOrPath);
451cad84a2070b68093ab31b05389685fdbcd0d9f85Santos Cordon            }
452cad84a2070b68093ab31b05389685fdbcd0d9f85Santos Cordon        }
453cad84a2070b68093ab31b05389685fdbcd0d9f85Santos Cordon        return null;
454cad84a2070b68093ab31b05389685fdbcd0d9f85Santos Cordon    }
455cad84a2070b68093ab31b05389685fdbcd0d9f85Santos Cordon
456cad84a2070b68093ab31b05389685fdbcd0d9f85Santos Cordon    /**
457877d696c382ecb8a97972450c8819536641a963cDan Sandler     * Create an Icon pointing to a drawable resource.
45802cd9f91a6bd6d06d6d1237f8b978a0ab0b8ea32Dan Sandler     * @param context The context for the application whose resources should be used to resolve the
45902cd9f91a6bd6d06d6d1237f8b978a0ab0b8ea32Dan Sandler     *                given resource ID.
460877d696c382ecb8a97972450c8819536641a963cDan Sandler     * @param resId ID of the drawable resource
461b9f7aac3488873677377b36c57338d758098f78eDan Sandler     */
46202cd9f91a6bd6d06d6d1237f8b978a0ab0b8ea32Dan Sandler    public static Icon createWithResource(Context context, @DrawableRes int resId) {
4634e78706f439d318ae7a78927d98f734351a89f64Dan Sandler        if (context == null) {
4644e78706f439d318ae7a78927d98f734351a89f64Dan Sandler            throw new IllegalArgumentException("Context must not be null.");
4654e78706f439d318ae7a78927d98f734351a89f64Dan Sandler        }
46602cd9f91a6bd6d06d6d1237f8b978a0ab0b8ea32Dan Sandler        final Icon rep = new Icon(TYPE_RESOURCE);
46702cd9f91a6bd6d06d6d1237f8b978a0ab0b8ea32Dan Sandler        rep.mInt1 = resId;
46802cd9f91a6bd6d06d6d1237f8b978a0ab0b8ea32Dan Sandler        rep.mString1 = context.getPackageName();
46902cd9f91a6bd6d06d6d1237f8b978a0ab0b8ea32Dan Sandler        return rep;
47002cd9f91a6bd6d06d6d1237f8b978a0ab0b8ea32Dan Sandler    }
47102cd9f91a6bd6d06d6d1237f8b978a0ab0b8ea32Dan Sandler
47202cd9f91a6bd6d06d6d1237f8b978a0ab0b8ea32Dan Sandler    /**
47302cd9f91a6bd6d06d6d1237f8b978a0ab0b8ea32Dan Sandler     * Version of createWithResource that takes Resources. Do not use.
47402cd9f91a6bd6d06d6d1237f8b978a0ab0b8ea32Dan Sandler     * @hide
47502cd9f91a6bd6d06d6d1237f8b978a0ab0b8ea32Dan Sandler     */
476877d696c382ecb8a97972450c8819536641a963cDan Sandler    public static Icon createWithResource(Resources res, @DrawableRes int resId) {
477cad84a2070b68093ab31b05389685fdbcd0d9f85Santos Cordon        if (res == null) {
478cad84a2070b68093ab31b05389685fdbcd0d9f85Santos Cordon            throw new IllegalArgumentException("Resource must not be null.");
479cad84a2070b68093ab31b05389685fdbcd0d9f85Santos Cordon        }
480b9f7aac3488873677377b36c57338d758098f78eDan Sandler        final Icon rep = new Icon(TYPE_RESOURCE);
481877d696c382ecb8a97972450c8819536641a963cDan Sandler        rep.mInt1 = resId;
482877d696c382ecb8a97972450c8819536641a963cDan Sandler        rep.mString1 = res.getResourcePackageName(resId);
483877d696c382ecb8a97972450c8819536641a963cDan Sandler        return rep;
484877d696c382ecb8a97972450c8819536641a963cDan Sandler    }
485877d696c382ecb8a97972450c8819536641a963cDan Sandler
486877d696c382ecb8a97972450c8819536641a963cDan Sandler    /**
487877d696c382ecb8a97972450c8819536641a963cDan Sandler     * Create an Icon pointing to a drawable resource.
488877d696c382ecb8a97972450c8819536641a963cDan Sandler     * @param resPackage Name of the package containing the resource in question
489877d696c382ecb8a97972450c8819536641a963cDan Sandler     * @param resId ID of the drawable resource
490877d696c382ecb8a97972450c8819536641a963cDan Sandler     */
491877d696c382ecb8a97972450c8819536641a963cDan Sandler    public static Icon createWithResource(String resPackage, @DrawableRes int resId) {
492cad84a2070b68093ab31b05389685fdbcd0d9f85Santos Cordon        if (resPackage == null) {
493cad84a2070b68093ab31b05389685fdbcd0d9f85Santos Cordon            throw new IllegalArgumentException("Resource package name must not be null.");
494cad84a2070b68093ab31b05389685fdbcd0d9f85Santos Cordon        }
495877d696c382ecb8a97972450c8819536641a963cDan Sandler        final Icon rep = new Icon(TYPE_RESOURCE);
496877d696c382ecb8a97972450c8819536641a963cDan Sandler        rep.mInt1 = resId;
497877d696c382ecb8a97972450c8819536641a963cDan Sandler        rep.mString1 = resPackage;
498b9f7aac3488873677377b36c57338d758098f78eDan Sandler        return rep;
499b9f7aac3488873677377b36c57338d758098f78eDan Sandler    }
500b9f7aac3488873677377b36c57338d758098f78eDan Sandler
501b9f7aac3488873677377b36c57338d758098f78eDan Sandler    /**
502877d696c382ecb8a97972450c8819536641a963cDan Sandler     * Create an Icon pointing to a bitmap in memory.
503b9f7aac3488873677377b36c57338d758098f78eDan Sandler     * @param bits A valid {@link android.graphics.Bitmap} object
504b9f7aac3488873677377b36c57338d758098f78eDan Sandler     */
505b9f7aac3488873677377b36c57338d758098f78eDan Sandler    public static Icon createWithBitmap(Bitmap bits) {
506cad84a2070b68093ab31b05389685fdbcd0d9f85Santos Cordon        if (bits == null) {
507cad84a2070b68093ab31b05389685fdbcd0d9f85Santos Cordon            throw new IllegalArgumentException("Bitmap must not be null.");
508cad84a2070b68093ab31b05389685fdbcd0d9f85Santos Cordon        }
509b9f7aac3488873677377b36c57338d758098f78eDan Sandler        final Icon rep = new Icon(TYPE_BITMAP);
510a0d58ae574a3a69145512e0cd92e7842f0fbf83dJorim Jaggi        rep.setBitmap(bits);
511b9f7aac3488873677377b36c57338d758098f78eDan Sandler        return rep;
512b9f7aac3488873677377b36c57338d758098f78eDan Sandler    }
513b9f7aac3488873677377b36c57338d758098f78eDan Sandler
514b9f7aac3488873677377b36c57338d758098f78eDan Sandler    /**
515877d696c382ecb8a97972450c8819536641a963cDan Sandler     * Create an Icon pointing to a compressed bitmap stored in a byte array.
516b9f7aac3488873677377b36c57338d758098f78eDan Sandler     * @param data Byte array storing compressed bitmap data of a type that
517b9f7aac3488873677377b36c57338d758098f78eDan Sandler     *             {@link android.graphics.BitmapFactory}
518b9f7aac3488873677377b36c57338d758098f78eDan Sandler     *             can decode (see {@link android.graphics.Bitmap.CompressFormat}).
519b9f7aac3488873677377b36c57338d758098f78eDan Sandler     * @param offset Offset into <code>data</code> at which the bitmap data starts
520b9f7aac3488873677377b36c57338d758098f78eDan Sandler     * @param length Length of the bitmap data
521b9f7aac3488873677377b36c57338d758098f78eDan Sandler     */
522b9f7aac3488873677377b36c57338d758098f78eDan Sandler    public static Icon createWithData(byte[] data, int offset, int length) {
523cad84a2070b68093ab31b05389685fdbcd0d9f85Santos Cordon        if (data == null) {
524cad84a2070b68093ab31b05389685fdbcd0d9f85Santos Cordon            throw new IllegalArgumentException("Data must not be null.");
525cad84a2070b68093ab31b05389685fdbcd0d9f85Santos Cordon        }
526b9f7aac3488873677377b36c57338d758098f78eDan Sandler        final Icon rep = new Icon(TYPE_DATA);
527b9f7aac3488873677377b36c57338d758098f78eDan Sandler        rep.mObj1 = data;
528b9f7aac3488873677377b36c57338d758098f78eDan Sandler        rep.mInt1 = length;
529b9f7aac3488873677377b36c57338d758098f78eDan Sandler        rep.mInt2 = offset;
530b9f7aac3488873677377b36c57338d758098f78eDan Sandler        return rep;
531b9f7aac3488873677377b36c57338d758098f78eDan Sandler    }
532b9f7aac3488873677377b36c57338d758098f78eDan Sandler
533b9f7aac3488873677377b36c57338d758098f78eDan Sandler    /**
534877d696c382ecb8a97972450c8819536641a963cDan Sandler     * Create an Icon pointing to an image file specified by URI.
535b9f7aac3488873677377b36c57338d758098f78eDan Sandler     *
536b9f7aac3488873677377b36c57338d758098f78eDan Sandler     * @param uri A uri referring to local content:// or file:// image data.
537b9f7aac3488873677377b36c57338d758098f78eDan Sandler     */
538b9f7aac3488873677377b36c57338d758098f78eDan Sandler    public static Icon createWithContentUri(String uri) {
539cad84a2070b68093ab31b05389685fdbcd0d9f85Santos Cordon        if (uri == null) {
540cad84a2070b68093ab31b05389685fdbcd0d9f85Santos Cordon            throw new IllegalArgumentException("Uri must not be null.");
541cad84a2070b68093ab31b05389685fdbcd0d9f85Santos Cordon        }
542b9f7aac3488873677377b36c57338d758098f78eDan Sandler        final Icon rep = new Icon(TYPE_URI);
543b9f7aac3488873677377b36c57338d758098f78eDan Sandler        rep.mString1 = uri;
544b9f7aac3488873677377b36c57338d758098f78eDan Sandler        return rep;
545b9f7aac3488873677377b36c57338d758098f78eDan Sandler    }
546b9f7aac3488873677377b36c57338d758098f78eDan Sandler
547b9f7aac3488873677377b36c57338d758098f78eDan Sandler    /**
548877d696c382ecb8a97972450c8819536641a963cDan Sandler     * Create an Icon pointing to an image file specified by URI.
549b9f7aac3488873677377b36c57338d758098f78eDan Sandler     *
550b9f7aac3488873677377b36c57338d758098f78eDan Sandler     * @param uri A uri referring to local content:// or file:// image data.
551b9f7aac3488873677377b36c57338d758098f78eDan Sandler     */
552b9f7aac3488873677377b36c57338d758098f78eDan Sandler    public static Icon createWithContentUri(Uri uri) {
553cad84a2070b68093ab31b05389685fdbcd0d9f85Santos Cordon        if (uri == null) {
554cad84a2070b68093ab31b05389685fdbcd0d9f85Santos Cordon            throw new IllegalArgumentException("Uri must not be null.");
555cad84a2070b68093ab31b05389685fdbcd0d9f85Santos Cordon        }
556b9f7aac3488873677377b36c57338d758098f78eDan Sandler        final Icon rep = new Icon(TYPE_URI);
557b9f7aac3488873677377b36c57338d758098f78eDan Sandler        rep.mString1 = uri.toString();
558b9f7aac3488873677377b36c57338d758098f78eDan Sandler        return rep;
559b9f7aac3488873677377b36c57338d758098f78eDan Sandler    }
560b9f7aac3488873677377b36c57338d758098f78eDan Sandler
561b9f7aac3488873677377b36c57338d758098f78eDan Sandler    /**
56224f11b1871f9def5d802d107897658c4b2b66ab5Dan Sandler     * Store a color to use whenever this Icon is drawn.
56324f11b1871f9def5d802d107897658c4b2b66ab5Dan Sandler     *
56424f11b1871f9def5d802d107897658c4b2b66ab5Dan Sandler     * @param tint a color, as in {@link Drawable#setTint(int)}
56524f11b1871f9def5d802d107897658c4b2b66ab5Dan Sandler     * @return this same object, for use in chained construction
56624f11b1871f9def5d802d107897658c4b2b66ab5Dan Sandler     */
56724f11b1871f9def5d802d107897658c4b2b66ab5Dan Sandler    public Icon setTint(@ColorInt int tint) {
56824f11b1871f9def5d802d107897658c4b2b66ab5Dan Sandler        return setTintList(ColorStateList.valueOf(tint));
56924f11b1871f9def5d802d107897658c4b2b66ab5Dan Sandler    }
57024f11b1871f9def5d802d107897658c4b2b66ab5Dan Sandler
57124f11b1871f9def5d802d107897658c4b2b66ab5Dan Sandler    /**
57224f11b1871f9def5d802d107897658c4b2b66ab5Dan Sandler     * Store a color to use whenever this Icon is drawn.
57324f11b1871f9def5d802d107897658c4b2b66ab5Dan Sandler     *
57424f11b1871f9def5d802d107897658c4b2b66ab5Dan Sandler     * @param tintList as in {@link Drawable#setTintList(ColorStateList)}, null to remove tint
57524f11b1871f9def5d802d107897658c4b2b66ab5Dan Sandler     * @return this same object, for use in chained construction
57624f11b1871f9def5d802d107897658c4b2b66ab5Dan Sandler     */
57724f11b1871f9def5d802d107897658c4b2b66ab5Dan Sandler    public Icon setTintList(ColorStateList tintList) {
57824f11b1871f9def5d802d107897658c4b2b66ab5Dan Sandler        mTintList = tintList;
57924f11b1871f9def5d802d107897658c4b2b66ab5Dan Sandler        return this;
58024f11b1871f9def5d802d107897658c4b2b66ab5Dan Sandler    }
58124f11b1871f9def5d802d107897658c4b2b66ab5Dan Sandler
58224f11b1871f9def5d802d107897658c4b2b66ab5Dan Sandler    /**
58324f11b1871f9def5d802d107897658c4b2b66ab5Dan Sandler     * Store a blending mode to use whenever this Icon is drawn.
58424f11b1871f9def5d802d107897658c4b2b66ab5Dan Sandler     *
58524f11b1871f9def5d802d107897658c4b2b66ab5Dan Sandler     * @param mode a blending mode, as in {@link Drawable#setTintMode(PorterDuff.Mode)}, may be null
58624f11b1871f9def5d802d107897658c4b2b66ab5Dan Sandler     * @return this same object, for use in chained construction
58724f11b1871f9def5d802d107897658c4b2b66ab5Dan Sandler     */
58824f11b1871f9def5d802d107897658c4b2b66ab5Dan Sandler    public Icon setTintMode(PorterDuff.Mode mode) {
58924f11b1871f9def5d802d107897658c4b2b66ab5Dan Sandler        mTintMode = mode;
59024f11b1871f9def5d802d107897658c4b2b66ab5Dan Sandler        return this;
59124f11b1871f9def5d802d107897658c4b2b66ab5Dan Sandler    }
59224f11b1871f9def5d802d107897658c4b2b66ab5Dan Sandler
59324f11b1871f9def5d802d107897658c4b2b66ab5Dan Sandler    /**
594877d696c382ecb8a97972450c8819536641a963cDan Sandler     * Create an Icon pointing to an image file specified by path.
595b9f7aac3488873677377b36c57338d758098f78eDan Sandler     *
596b9f7aac3488873677377b36c57338d758098f78eDan Sandler     * @param path A path to a file that contains compressed bitmap data of
597b9f7aac3488873677377b36c57338d758098f78eDan Sandler     *           a type that {@link android.graphics.BitmapFactory} can decode.
598b9f7aac3488873677377b36c57338d758098f78eDan Sandler     */
599b9f7aac3488873677377b36c57338d758098f78eDan Sandler    public static Icon createWithFilePath(String path) {
600cad84a2070b68093ab31b05389685fdbcd0d9f85Santos Cordon        if (path == null) {
601cad84a2070b68093ab31b05389685fdbcd0d9f85Santos Cordon            throw new IllegalArgumentException("Path must not be null.");
602cad84a2070b68093ab31b05389685fdbcd0d9f85Santos Cordon        }
603b9f7aac3488873677377b36c57338d758098f78eDan Sandler        final Icon rep = new Icon(TYPE_URI);
604b9f7aac3488873677377b36c57338d758098f78eDan Sandler        rep.mString1 = path;
605b9f7aac3488873677377b36c57338d758098f78eDan Sandler        return rep;
606b9f7aac3488873677377b36c57338d758098f78eDan Sandler    }
607b9f7aac3488873677377b36c57338d758098f78eDan Sandler
608b9f7aac3488873677377b36c57338d758098f78eDan Sandler    @Override
609b9f7aac3488873677377b36c57338d758098f78eDan Sandler    public String toString() {
610b9f7aac3488873677377b36c57338d758098f78eDan Sandler        final StringBuilder sb = new StringBuilder("Icon(typ=").append(typeToString(mType));
611b9f7aac3488873677377b36c57338d758098f78eDan Sandler        switch (mType) {
612b9f7aac3488873677377b36c57338d758098f78eDan Sandler            case TYPE_BITMAP:
613b9f7aac3488873677377b36c57338d758098f78eDan Sandler                sb.append(" size=")
614b9f7aac3488873677377b36c57338d758098f78eDan Sandler                        .append(getBitmap().getWidth())
615b9f7aac3488873677377b36c57338d758098f78eDan Sandler                        .append("x")
616b9f7aac3488873677377b36c57338d758098f78eDan Sandler                        .append(getBitmap().getHeight());
617b9f7aac3488873677377b36c57338d758098f78eDan Sandler                break;
618b9f7aac3488873677377b36c57338d758098f78eDan Sandler            case TYPE_RESOURCE:
619b9f7aac3488873677377b36c57338d758098f78eDan Sandler                sb.append(" pkg=")
620b9f7aac3488873677377b36c57338d758098f78eDan Sandler                        .append(getResPackage())
621b9f7aac3488873677377b36c57338d758098f78eDan Sandler                        .append(" id=")
622d63f9321e62064660d426efd5abbd885c4a24652Dan Sandler                        .append(String.format("0x%08x", getResId()));
623b9f7aac3488873677377b36c57338d758098f78eDan Sandler                break;
624b9f7aac3488873677377b36c57338d758098f78eDan Sandler            case TYPE_DATA:
625b9f7aac3488873677377b36c57338d758098f78eDan Sandler                sb.append(" len=").append(getDataLength());
626b9f7aac3488873677377b36c57338d758098f78eDan Sandler                if (getDataOffset() != 0) {
627b9f7aac3488873677377b36c57338d758098f78eDan Sandler                    sb.append(" off=").append(getDataOffset());
628b9f7aac3488873677377b36c57338d758098f78eDan Sandler                }
629b9f7aac3488873677377b36c57338d758098f78eDan Sandler                break;
630b9f7aac3488873677377b36c57338d758098f78eDan Sandler            case TYPE_URI:
631b9f7aac3488873677377b36c57338d758098f78eDan Sandler                sb.append(" uri=").append(getUriString());
632b9f7aac3488873677377b36c57338d758098f78eDan Sandler                break;
633b9f7aac3488873677377b36c57338d758098f78eDan Sandler        }
63424f11b1871f9def5d802d107897658c4b2b66ab5Dan Sandler        if (mTintList != null) {
63524f11b1871f9def5d802d107897658c4b2b66ab5Dan Sandler            sb.append(" tint=");
63624f11b1871f9def5d802d107897658c4b2b66ab5Dan Sandler            String sep = "";
63724f11b1871f9def5d802d107897658c4b2b66ab5Dan Sandler            for (int c : mTintList.getColors()) {
63824f11b1871f9def5d802d107897658c4b2b66ab5Dan Sandler                sb.append(String.format("%s0x%08x", sep, c));
63924f11b1871f9def5d802d107897658c4b2b66ab5Dan Sandler                sep = "|";
64024f11b1871f9def5d802d107897658c4b2b66ab5Dan Sandler            }
64124f11b1871f9def5d802d107897658c4b2b66ab5Dan Sandler        }
64224f11b1871f9def5d802d107897658c4b2b66ab5Dan Sandler        if (mTintMode != DEFAULT_TINT_MODE) sb.append(" mode=").append(mTintMode);
643b9f7aac3488873677377b36c57338d758098f78eDan Sandler        sb.append(")");
644b9f7aac3488873677377b36c57338d758098f78eDan Sandler        return sb.toString();
645b9f7aac3488873677377b36c57338d758098f78eDan Sandler    }
646b9f7aac3488873677377b36c57338d758098f78eDan Sandler
647b9f7aac3488873677377b36c57338d758098f78eDan Sandler    /**
648b9f7aac3488873677377b36c57338d758098f78eDan Sandler     * Parcelable interface
649b9f7aac3488873677377b36c57338d758098f78eDan Sandler     */
650b9f7aac3488873677377b36c57338d758098f78eDan Sandler    public int describeContents() {
651b9f7aac3488873677377b36c57338d758098f78eDan Sandler        return (mType == TYPE_BITMAP || mType == TYPE_DATA)
652b9f7aac3488873677377b36c57338d758098f78eDan Sandler                ? Parcelable.CONTENTS_FILE_DESCRIPTOR : 0;
653b9f7aac3488873677377b36c57338d758098f78eDan Sandler    }
654b9f7aac3488873677377b36c57338d758098f78eDan Sandler
655b9f7aac3488873677377b36c57338d758098f78eDan Sandler    // ===== Parcelable interface ======
656b9f7aac3488873677377b36c57338d758098f78eDan Sandler
657b9f7aac3488873677377b36c57338d758098f78eDan Sandler    private Icon(Parcel in) {
658b9f7aac3488873677377b36c57338d758098f78eDan Sandler        this(in.readInt());
659b9f7aac3488873677377b36c57338d758098f78eDan Sandler        switch (mType) {
660b9f7aac3488873677377b36c57338d758098f78eDan Sandler            case TYPE_BITMAP:
661b9f7aac3488873677377b36c57338d758098f78eDan Sandler                final Bitmap bits = Bitmap.CREATOR.createFromParcel(in);
662b9f7aac3488873677377b36c57338d758098f78eDan Sandler                mObj1 = bits;
663b9f7aac3488873677377b36c57338d758098f78eDan Sandler                break;
664b9f7aac3488873677377b36c57338d758098f78eDan Sandler            case TYPE_RESOURCE:
665b9f7aac3488873677377b36c57338d758098f78eDan Sandler                final String pkg = in.readString();
666b9f7aac3488873677377b36c57338d758098f78eDan Sandler                final int resId = in.readInt();
667b9f7aac3488873677377b36c57338d758098f78eDan Sandler                mString1 = pkg;
668b9f7aac3488873677377b36c57338d758098f78eDan Sandler                mInt1 = resId;
669b9f7aac3488873677377b36c57338d758098f78eDan Sandler                break;
670b9f7aac3488873677377b36c57338d758098f78eDan Sandler            case TYPE_DATA:
671b9f7aac3488873677377b36c57338d758098f78eDan Sandler                final int len = in.readInt();
672b9f7aac3488873677377b36c57338d758098f78eDan Sandler                final byte[] a = in.readBlob();
673b9f7aac3488873677377b36c57338d758098f78eDan Sandler                if (len != a.length) {
674b9f7aac3488873677377b36c57338d758098f78eDan Sandler                    throw new RuntimeException("internal unparceling error: blob length ("
675b9f7aac3488873677377b36c57338d758098f78eDan Sandler                            + a.length + ") != expected length (" + len + ")");
676b9f7aac3488873677377b36c57338d758098f78eDan Sandler                }
677b9f7aac3488873677377b36c57338d758098f78eDan Sandler                mInt1 = len;
678b9f7aac3488873677377b36c57338d758098f78eDan Sandler                mObj1 = a;
679b9f7aac3488873677377b36c57338d758098f78eDan Sandler                break;
680b9f7aac3488873677377b36c57338d758098f78eDan Sandler            case TYPE_URI:
681b9f7aac3488873677377b36c57338d758098f78eDan Sandler                final String uri = in.readString();
682b9f7aac3488873677377b36c57338d758098f78eDan Sandler                mString1 = uri;
683b9f7aac3488873677377b36c57338d758098f78eDan Sandler                break;
684b9f7aac3488873677377b36c57338d758098f78eDan Sandler            default:
685b9f7aac3488873677377b36c57338d758098f78eDan Sandler                throw new RuntimeException("invalid "
686b9f7aac3488873677377b36c57338d758098f78eDan Sandler                        + this.getClass().getSimpleName() + " type in parcel: " + mType);
687b9f7aac3488873677377b36c57338d758098f78eDan Sandler        }
68824f11b1871f9def5d802d107897658c4b2b66ab5Dan Sandler        if (in.readInt() == 1) {
68924f11b1871f9def5d802d107897658c4b2b66ab5Dan Sandler            mTintList = ColorStateList.CREATOR.createFromParcel(in);
69024f11b1871f9def5d802d107897658c4b2b66ab5Dan Sandler        }
69124f11b1871f9def5d802d107897658c4b2b66ab5Dan Sandler        mTintMode = PorterDuff.intToMode(in.readInt());
692b9f7aac3488873677377b36c57338d758098f78eDan Sandler    }
693b9f7aac3488873677377b36c57338d758098f78eDan Sandler
694b9f7aac3488873677377b36c57338d758098f78eDan Sandler    @Override
695b9f7aac3488873677377b36c57338d758098f78eDan Sandler    public void writeToParcel(Parcel dest, int flags) {
69624f11b1871f9def5d802d107897658c4b2b66ab5Dan Sandler        dest.writeInt(mType);
697b9f7aac3488873677377b36c57338d758098f78eDan Sandler        switch (mType) {
698b9f7aac3488873677377b36c57338d758098f78eDan Sandler            case TYPE_BITMAP:
699b9f7aac3488873677377b36c57338d758098f78eDan Sandler                final Bitmap bits = getBitmap();
700b9f7aac3488873677377b36c57338d758098f78eDan Sandler                getBitmap().writeToParcel(dest, flags);
701b9f7aac3488873677377b36c57338d758098f78eDan Sandler                break;
702b9f7aac3488873677377b36c57338d758098f78eDan Sandler            case TYPE_RESOURCE:
703b9f7aac3488873677377b36c57338d758098f78eDan Sandler                dest.writeString(getResPackage());
704b9f7aac3488873677377b36c57338d758098f78eDan Sandler                dest.writeInt(getResId());
705b9f7aac3488873677377b36c57338d758098f78eDan Sandler                break;
706b9f7aac3488873677377b36c57338d758098f78eDan Sandler            case TYPE_DATA:
707b9f7aac3488873677377b36c57338d758098f78eDan Sandler                dest.writeInt(getDataLength());
708b9f7aac3488873677377b36c57338d758098f78eDan Sandler                dest.writeBlob(getDataBytes(), getDataOffset(), getDataLength());
709b9f7aac3488873677377b36c57338d758098f78eDan Sandler                break;
710b9f7aac3488873677377b36c57338d758098f78eDan Sandler            case TYPE_URI:
711b9f7aac3488873677377b36c57338d758098f78eDan Sandler                dest.writeString(getUriString());
712b9f7aac3488873677377b36c57338d758098f78eDan Sandler                break;
713b9f7aac3488873677377b36c57338d758098f78eDan Sandler        }
71424f11b1871f9def5d802d107897658c4b2b66ab5Dan Sandler        if (mTintList == null) {
71524f11b1871f9def5d802d107897658c4b2b66ab5Dan Sandler            dest.writeInt(0);
71624f11b1871f9def5d802d107897658c4b2b66ab5Dan Sandler        } else {
71724f11b1871f9def5d802d107897658c4b2b66ab5Dan Sandler            dest.writeInt(1);
71824f11b1871f9def5d802d107897658c4b2b66ab5Dan Sandler            mTintList.writeToParcel(dest, flags);
71924f11b1871f9def5d802d107897658c4b2b66ab5Dan Sandler        }
72024f11b1871f9def5d802d107897658c4b2b66ab5Dan Sandler        dest.writeInt(PorterDuff.modeToInt(mTintMode));
721b9f7aac3488873677377b36c57338d758098f78eDan Sandler    }
722b9f7aac3488873677377b36c57338d758098f78eDan Sandler
723b9f7aac3488873677377b36c57338d758098f78eDan Sandler    public static final Parcelable.Creator<Icon> CREATOR
724b9f7aac3488873677377b36c57338d758098f78eDan Sandler            = new Parcelable.Creator<Icon>() {
725b9f7aac3488873677377b36c57338d758098f78eDan Sandler        public Icon createFromParcel(Parcel in) {
726b9f7aac3488873677377b36c57338d758098f78eDan Sandler            return new Icon(in);
727b9f7aac3488873677377b36c57338d758098f78eDan Sandler        }
728b9f7aac3488873677377b36c57338d758098f78eDan Sandler
729b9f7aac3488873677377b36c57338d758098f78eDan Sandler        public Icon[] newArray(int size) {
730b9f7aac3488873677377b36c57338d758098f78eDan Sandler            return new Icon[size];
731b9f7aac3488873677377b36c57338d758098f78eDan Sandler        }
732b9f7aac3488873677377b36c57338d758098f78eDan Sandler    };
733b9f7aac3488873677377b36c57338d758098f78eDan Sandler
734b9f7aac3488873677377b36c57338d758098f78eDan Sandler    /**
735877d696c382ecb8a97972450c8819536641a963cDan Sandler     * Implement this interface to receive a callback when
736877d696c382ecb8a97972450c8819536641a963cDan Sandler     * {@link #loadDrawableAsync(Context, OnDrawableLoadedListener, Handler) loadDrawableAsync}
737b9f7aac3488873677377b36c57338d758098f78eDan Sandler     * is finished and your Drawable is ready.
738b9f7aac3488873677377b36c57338d758098f78eDan Sandler     */
739b9f7aac3488873677377b36c57338d758098f78eDan Sandler    public interface OnDrawableLoadedListener {
740b9f7aac3488873677377b36c57338d758098f78eDan Sandler        void onDrawableLoaded(Drawable d);
741b9f7aac3488873677377b36c57338d758098f78eDan Sandler    }
742b9f7aac3488873677377b36c57338d758098f78eDan Sandler
743b9f7aac3488873677377b36c57338d758098f78eDan Sandler    /**
744b9f7aac3488873677377b36c57338d758098f78eDan Sandler     * Wrapper around loadDrawable that does its work on a pooled thread and then
745b9f7aac3488873677377b36c57338d758098f78eDan Sandler     * fires back the given (targeted) Message.
746b9f7aac3488873677377b36c57338d758098f78eDan Sandler     */
747b9f7aac3488873677377b36c57338d758098f78eDan Sandler    private class LoadDrawableTask implements Runnable {
748b9f7aac3488873677377b36c57338d758098f78eDan Sandler        final Context mContext;
749b9f7aac3488873677377b36c57338d758098f78eDan Sandler        final Message mMessage;
750b9f7aac3488873677377b36c57338d758098f78eDan Sandler
751b9f7aac3488873677377b36c57338d758098f78eDan Sandler        public LoadDrawableTask(Context context, final Handler handler,
752b9f7aac3488873677377b36c57338d758098f78eDan Sandler                final OnDrawableLoadedListener listener) {
753b9f7aac3488873677377b36c57338d758098f78eDan Sandler            mContext = context;
754b9f7aac3488873677377b36c57338d758098f78eDan Sandler            mMessage = Message.obtain(handler, new Runnable() {
755b9f7aac3488873677377b36c57338d758098f78eDan Sandler                    @Override
756b9f7aac3488873677377b36c57338d758098f78eDan Sandler                    public void run() {
757b9f7aac3488873677377b36c57338d758098f78eDan Sandler                        listener.onDrawableLoaded((Drawable) mMessage.obj);
758b9f7aac3488873677377b36c57338d758098f78eDan Sandler                    }
759b9f7aac3488873677377b36c57338d758098f78eDan Sandler                });
760b9f7aac3488873677377b36c57338d758098f78eDan Sandler        }
761b9f7aac3488873677377b36c57338d758098f78eDan Sandler
762b9f7aac3488873677377b36c57338d758098f78eDan Sandler        public LoadDrawableTask(Context context, Message message) {
763b9f7aac3488873677377b36c57338d758098f78eDan Sandler            mContext = context;
764b9f7aac3488873677377b36c57338d758098f78eDan Sandler            mMessage = message;
765b9f7aac3488873677377b36c57338d758098f78eDan Sandler        }
766b9f7aac3488873677377b36c57338d758098f78eDan Sandler
767b9f7aac3488873677377b36c57338d758098f78eDan Sandler        @Override
768b9f7aac3488873677377b36c57338d758098f78eDan Sandler        public void run() {
769b9f7aac3488873677377b36c57338d758098f78eDan Sandler            mMessage.obj = loadDrawable(mContext);
770b9f7aac3488873677377b36c57338d758098f78eDan Sandler            mMessage.sendToTarget();
771b9f7aac3488873677377b36c57338d758098f78eDan Sandler        }
772b9f7aac3488873677377b36c57338d758098f78eDan Sandler
773b9f7aac3488873677377b36c57338d758098f78eDan Sandler        public void runAsync() {
774b9f7aac3488873677377b36c57338d758098f78eDan Sandler            AsyncTask.THREAD_POOL_EXECUTOR.execute(this);
775b9f7aac3488873677377b36c57338d758098f78eDan Sandler        }
776b9f7aac3488873677377b36c57338d758098f78eDan Sandler    }
777b9f7aac3488873677377b36c57338d758098f78eDan Sandler}
778