Attachment.java revision 856200a2abc6a90711f6eb99fc0340dd75ef6e9b
17b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira/**
27b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira * Copyright (c) 2011, Google Inc.
37b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira *
47b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira * Licensed under the Apache License, Version 2.0 (the "License");
57b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira * you may not use this file except in compliance with the License.
67b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira * You may obtain a copy of the License at
77b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira *
87b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira *     http://www.apache.org/licenses/LICENSE-2.0
97b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira *
107b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira * Unless required by applicable law or agreed to in writing, software
117b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira * distributed under the License is distributed on an "AS IS" BASIS,
127b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
137b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira * See the License for the specific language governing permissions and
147b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira * limitations under the License.
157b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira */
1630e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangpackage com.android.mail.providers;
177b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira
1888fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huangimport android.database.Cursor;
1988fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huangimport android.net.Uri;
207aee8f75f07eb39ecacdf0630d2199211aea5718Mindy Pereiraimport android.os.Parcel;
217aee8f75f07eb39ecacdf0630d2199211aea5718Mindy Pereiraimport android.os.Parcelable;
22f944e9655562e321aff52fe5f437e1d2fa2950a9Mindy Pereiraimport android.text.TextUtils;
23f944e9655562e321aff52fe5f437e1d2fa2950a9Mindy Pereira
2488fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huangimport com.android.mail.providers.UIProvider.AttachmentColumns;
2588fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huangimport com.android.mail.providers.UIProvider.AttachmentDestination;
2688fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huangimport com.android.mail.providers.UIProvider.AttachmentState;
27b334c9035e9b7a38766bb66c29da2208525d1e11Paul Westbrookimport com.android.mail.utils.LogTag;
28f467d10bb05a8df6ac3c8279f6fda24e89b87482Paul Westbrookimport com.android.mail.utils.LogUtils;
29856200a2abc6a90711f6eb99fc0340dd75ef6e9bMark Weiimport com.android.mail.utils.MimeType;
304f24bb48ab2c3e8fbda2af1e1d8fda79e8a458e7Andy Huangimport com.android.mail.utils.Utils;
314c7d8b5f38bfa80192d457025b834c975d7d38a3Andrew Sappersteinimport com.google.common.collect.Lists;
325a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang
335a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huangimport org.json.JSONArray;
345a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huangimport org.json.JSONException;
355a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huangimport org.json.JSONObject;
367b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira
375a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huangimport java.util.Collection;
385a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huangimport java.util.List;
394401c9049f0327019b0bfed554bf8ff5cdaa20e2Mindy Pereira
407aee8f75f07eb39ecacdf0630d2199211aea5718Mindy Pereirapublic class Attachment implements Parcelable {
41f944e9655562e321aff52fe5f437e1d2fa2950a9Mindy Pereira    public static final int SERVER_ATTACHMENT = 0;
42f944e9655562e321aff52fe5f437e1d2fa2950a9Mindy Pereira    /** Extras are "<path>". */
43f944e9655562e321aff52fe5f437e1d2fa2950a9Mindy Pereira    public static final int  LOCAL_FILE = 1;
44f944e9655562e321aff52fe5f437e1d2fa2950a9Mindy Pereira
45b334c9035e9b7a38766bb66c29da2208525d1e11Paul Westbrook    public static final String LOG_TAG = LogTag.getLogTag();
465a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang
477aee8f75f07eb39ecacdf0630d2199211aea5718Mindy Pereira    /**
4888fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang     * Attachment file name. See {@link AttachmentColumns#NAME}.
497aee8f75f07eb39ecacdf0630d2199211aea5718Mindy Pereira     */
507aee8f75f07eb39ecacdf0630d2199211aea5718Mindy Pereira    public String name;
51f944e9655562e321aff52fe5f437e1d2fa2950a9Mindy Pereira
5288fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang    /**
5388fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang     * Attachment size in bytes. See {@link AttachmentColumns#SIZE}.
5488fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang     */
5588fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang    public int size;
56f944e9655562e321aff52fe5f437e1d2fa2950a9Mindy Pereira
577aee8f75f07eb39ecacdf0630d2199211aea5718Mindy Pereira    /**
585c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang     * The provider-generated URI for this Attachment. Must be globally unique. For local
595c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang     * attachments generated by the Compose UI prior to send/save, this field will be null.
605c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang     *
615c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang     *@see AttachmentColumns#URI
627aee8f75f07eb39ecacdf0630d2199211aea5718Mindy Pereira     */
6388fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang    public Uri uri;
6488fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang
657aee8f75f07eb39ecacdf0630d2199211aea5718Mindy Pereira    /**
665c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang     * MIME type of the file.
675c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang     *
685c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang     * @see AttachmentColumns#CONTENT_TYPE
697aee8f75f07eb39ecacdf0630d2199211aea5718Mindy Pereira     */
701eb5f96d4e9c459d463d664563c755ec36f958f7Andy Huang    public String contentType;
7188fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang
7288fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang    /**
735c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang     * @see AttachmentColumns#STATE
7488fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang     */
7588fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang    public int state;
7688fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang
7788fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang    /**
785c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang     * @see AttachmentColumns#DESTINATION
7988fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang     */
8088fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang    public int destination;
8188fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang
827aee8f75f07eb39ecacdf0630d2199211aea5718Mindy Pereira    /**
835c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang     * @see AttachmentColumns#DOWNLOADED_SIZE
847aee8f75f07eb39ecacdf0630d2199211aea5718Mindy Pereira     */
8588fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang    public int downloadedSize;
8688fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang
8788fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang    /**
885c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang     * @see AttachmentColumns#CONTENT_URI
8988fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang     */
901eb5f96d4e9c459d463d664563c755ec36f958f7Andy Huang    public Uri contentUri;
9188fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang
9288fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang    /**
935c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang     * Might be null.
945c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang     *
955c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang     * @see AttachmentColumns#THUMBNAIL_URI
9688fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang     */
9788fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang    public Uri thumbnailUri;
9888fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang
9988fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang    /**
1005c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang     * Might be null.
1015c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang     *
102d49db8e3c4fff459f4ae3869ea80d083461eda2cPaul Westbrook     * @see AttachmentColumns# PREVIEW_INTENT_URI
10388fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang     */
104d49db8e3c4fff459f4ae3869ea80d083461eda2cPaul Westbrook    public Uri previewIntentUri;
10588fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang
1067aee8f75f07eb39ecacdf0630d2199211aea5718Mindy Pereira    /**
1077aee8f75f07eb39ecacdf0630d2199211aea5718Mindy Pereira     * Part id of the attachment.
1087aee8f75f07eb39ecacdf0630d2199211aea5718Mindy Pereira     */
1095c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang    @Deprecated
1105c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang    // partId is provider implementation specific. providers must uniquely identify Attachments
1115c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang    // by uri.
1127aee8f75f07eb39ecacdf0630d2199211aea5718Mindy Pereira    public String partId;
11388fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang
1145c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang    @Deprecated
1155c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang    // this is a local file iff the provider 'uri' field is null.
11688fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang    public int origin;
11788fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang
1187aee8f75f07eb39ecacdf0630d2199211aea5718Mindy Pereira    /**
11988fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang     * Attachment origin info.
12088fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang     * TODO: do we want this? Or location?
1217aee8f75f07eb39ecacdf0630d2199211aea5718Mindy Pereira     */
1225c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang    @Deprecated
12388fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang    public String originExtras;
1247b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira
1254f24bb48ab2c3e8fbda2af1e1d8fda79e8a458e7Andy Huang    private transient Uri mIdentifierUri;
1264f24bb48ab2c3e8fbda2af1e1d8fda79e8a458e7Andy Huang
1277aee8f75f07eb39ecacdf0630d2199211aea5718Mindy Pereira    public Attachment(Parcel in) {
1287aee8f75f07eb39ecacdf0630d2199211aea5718Mindy Pereira        name = in.readString();
12988fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang        size = in.readInt();
13088fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang        uri = in.readParcelable(null);
1311eb5f96d4e9c459d463d664563c755ec36f958f7Andy Huang        contentType = in.readString();
13288fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang        state = in.readInt();
13388fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang        destination = in.readInt();
13488fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang        downloadedSize = in.readInt();
1351eb5f96d4e9c459d463d664563c755ec36f958f7Andy Huang        contentUri = in.readParcelable(null);
13688fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang        thumbnailUri = in.readParcelable(null);
137d49db8e3c4fff459f4ae3869ea80d083461eda2cPaul Westbrook        previewIntentUri = in.readParcelable(null);
1387aee8f75f07eb39ecacdf0630d2199211aea5718Mindy Pereira        partId = in.readString();
139f944e9655562e321aff52fe5f437e1d2fa2950a9Mindy Pereira        origin = in.readInt();
14088fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang        originExtras = in.readString();
1417aee8f75f07eb39ecacdf0630d2199211aea5718Mindy Pereira    }
1427b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira
1437aee8f75f07eb39ecacdf0630d2199211aea5718Mindy Pereira    public Attachment() {
1447aee8f75f07eb39ecacdf0630d2199211aea5718Mindy Pereira    }
1457b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira
14688fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang    public Attachment(Cursor cursor) {
14788fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang        if (cursor == null) {
14888fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang            return;
14988fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang        }
15088fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang
1514c7d8b5f38bfa80192d457025b834c975d7d38a3Andrew Sapperstein        name = cursor.getString(cursor.getColumnIndex(AttachmentColumns.NAME));
1524c7d8b5f38bfa80192d457025b834c975d7d38a3Andrew Sapperstein        size = cursor.getInt(cursor.getColumnIndex(AttachmentColumns.SIZE));
1534c7d8b5f38bfa80192d457025b834c975d7d38a3Andrew Sapperstein        uri = Uri.parse(cursor.getString(cursor.getColumnIndex(AttachmentColumns.URI)));
1544c7d8b5f38bfa80192d457025b834c975d7d38a3Andrew Sapperstein        contentType = cursor.getString(cursor.getColumnIndex(AttachmentColumns.CONTENT_TYPE));
1554c7d8b5f38bfa80192d457025b834c975d7d38a3Andrew Sapperstein        state = cursor.getInt(cursor.getColumnIndex(AttachmentColumns.STATE));
1564c7d8b5f38bfa80192d457025b834c975d7d38a3Andrew Sapperstein        destination = cursor.getInt(cursor.getColumnIndex(AttachmentColumns.DESTINATION));
1574c7d8b5f38bfa80192d457025b834c975d7d38a3Andrew Sapperstein        downloadedSize = cursor.getInt(cursor.getColumnIndex(AttachmentColumns.DOWNLOADED_SIZE));
1584c7d8b5f38bfa80192d457025b834c975d7d38a3Andrew Sapperstein        contentUri = parseOptionalUri(
1594c7d8b5f38bfa80192d457025b834c975d7d38a3Andrew Sapperstein                cursor.getString(cursor.getColumnIndex(AttachmentColumns.CONTENT_URI)));
16088fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang        thumbnailUri = parseOptionalUri(
1614c7d8b5f38bfa80192d457025b834c975d7d38a3Andrew Sapperstein                cursor.getString(cursor.getColumnIndex(AttachmentColumns.THUMBNAIL_URI)));
162d49db8e3c4fff459f4ae3869ea80d083461eda2cPaul Westbrook        previewIntentUri = parseOptionalUri(
163d49db8e3c4fff459f4ae3869ea80d083461eda2cPaul Westbrook                cursor.getString(cursor.getColumnIndex(AttachmentColumns.PREVIEW_INTENT_URI)));
16488fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang
16588fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang        // TODO: ensure that local files attached to a draft have sane values, like SAVED/EXTERNAL
16688fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang        // and that contentUri is populated
16788fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang    }
16888fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang
1695c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang    @Deprecated
170f944e9655562e321aff52fe5f437e1d2fa2950a9Mindy Pereira    public Attachment(String attachmentString) {
1715e1a5b7a9d694ff812e65f4b1240366252cdcde7Paul Westbrook        String[] attachmentValues = TextUtils.split(attachmentString, "\\|");
172f944e9655562e321aff52fe5f437e1d2fa2950a9Mindy Pereira        if (attachmentValues != null) {
173f944e9655562e321aff52fe5f437e1d2fa2950a9Mindy Pereira            partId = attachmentValues[0];
174f944e9655562e321aff52fe5f437e1d2fa2950a9Mindy Pereira            name = attachmentValues[1];
1751eb5f96d4e9c459d463d664563c755ec36f958f7Andy Huang            contentType = attachmentValues[2];
176f944e9655562e321aff52fe5f437e1d2fa2950a9Mindy Pereira            try {
17788fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang                size = Integer.parseInt(attachmentValues[3]);
178f944e9655562e321aff52fe5f437e1d2fa2950a9Mindy Pereira            } catch (NumberFormatException e) {
179f944e9655562e321aff52fe5f437e1d2fa2950a9Mindy Pereira                size = 0;
180f944e9655562e321aff52fe5f437e1d2fa2950a9Mindy Pereira            }
1811eb5f96d4e9c459d463d664563c755ec36f958f7Andy Huang            contentType = attachmentValues[4];
182f944e9655562e321aff52fe5f437e1d2fa2950a9Mindy Pereira            origin = Integer.parseInt(attachmentValues[5]);
1831eb5f96d4e9c459d463d664563c755ec36f958f7Andy Huang            contentUri = parseOptionalUri(attachmentValues[6]);
184f944e9655562e321aff52fe5f437e1d2fa2950a9Mindy Pereira            originExtras = attachmentValues[7];
185f944e9655562e321aff52fe5f437e1d2fa2950a9Mindy Pereira        }
186f944e9655562e321aff52fe5f437e1d2fa2950a9Mindy Pereira    }
187f944e9655562e321aff52fe5f437e1d2fa2950a9Mindy Pereira
1885c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang    @Deprecated
18988fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang    public String toJoinedString() {
1901eb5f96d4e9c459d463d664563c755ec36f958f7Andy Huang        // FIXME: contentType is read/written twice
19188fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang        return TextUtils.join("|", Lists.newArrayList(partId == null ? "" : partId,
1921eb5f96d4e9c459d463d664563c755ec36f958f7Andy Huang                name == null ? "" : name.replaceAll("[|\n]", ""), contentType, size, contentType,
1935c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang                contentUri != null ? LOCAL_FILE : SERVER_ATTACHMENT, contentUri,
1945c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang                originExtras == null ? "" : originExtras, ""));
19588fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang    }
19688fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang
197f467d10bb05a8df6ac3c8279f6fda24e89b87482Paul Westbrook    @Override
198f467d10bb05a8df6ac3c8279f6fda24e89b87482Paul Westbrook    public String toString() {
199f467d10bb05a8df6ac3c8279f6fda24e89b87482Paul Westbrook        try {
200b0f4a7da15313c9f1316ab72230bb44cc218ffd5Paul Westbrook            final JSONObject jsonObject = toJSON();
201b0f4a7da15313c9f1316ab72230bb44cc218ffd5Paul Westbrook            // Add some additional fields that are helpful when debugging issues
202b0f4a7da15313c9f1316ab72230bb44cc218ffd5Paul Westbrook            jsonObject.put(AttachmentColumns.DOWNLOADED_SIZE, downloadedSize);
203b0f4a7da15313c9f1316ab72230bb44cc218ffd5Paul Westbrook            jsonObject.put(AttachmentColumns.DESTINATION, destination);
204b0f4a7da15313c9f1316ab72230bb44cc218ffd5Paul Westbrook            jsonObject.put(AttachmentColumns.THUMBNAIL_URI, thumbnailUri);
205b0f4a7da15313c9f1316ab72230bb44cc218ffd5Paul Westbrook            jsonObject.put(AttachmentColumns.PREVIEW_INTENT_URI, previewIntentUri);
206b0f4a7da15313c9f1316ab72230bb44cc218ffd5Paul Westbrook            return jsonObject.toString();
207f467d10bb05a8df6ac3c8279f6fda24e89b87482Paul Westbrook        } catch (JSONException e) {
208f467d10bb05a8df6ac3c8279f6fda24e89b87482Paul Westbrook            LogUtils.e(LOG_TAG, e, "JSONException in toString");
209f467d10bb05a8df6ac3c8279f6fda24e89b87482Paul Westbrook            return super.toString();
210f467d10bb05a8df6ac3c8279f6fda24e89b87482Paul Westbrook        }
211f467d10bb05a8df6ac3c8279f6fda24e89b87482Paul Westbrook    }
212f467d10bb05a8df6ac3c8279f6fda24e89b87482Paul Westbrook
21388fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang    private static Uri parseOptionalUri(String uriString) {
21488fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang        return uriString == null ? null : Uri.parse(uriString);
21588fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang    }
21688fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang
2177aee8f75f07eb39ecacdf0630d2199211aea5718Mindy Pereira    @Override
2187aee8f75f07eb39ecacdf0630d2199211aea5718Mindy Pereira    public int describeContents() {
2197aee8f75f07eb39ecacdf0630d2199211aea5718Mindy Pereira        return 0;
2207aee8f75f07eb39ecacdf0630d2199211aea5718Mindy Pereira    }
2217b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira
2227aee8f75f07eb39ecacdf0630d2199211aea5718Mindy Pereira    @Override
2237aee8f75f07eb39ecacdf0630d2199211aea5718Mindy Pereira    public void writeToParcel(Parcel dest, int flags) {
2247aee8f75f07eb39ecacdf0630d2199211aea5718Mindy Pereira        dest.writeString(name);
22588fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang        dest.writeInt(size);
22688fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang        dest.writeParcelable(uri, flags);
2271eb5f96d4e9c459d463d664563c755ec36f958f7Andy Huang        dest.writeString(contentType);
22888fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang        dest.writeInt(state);
22988fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang        dest.writeInt(destination);
23088fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang        dest.writeInt(downloadedSize);
2311eb5f96d4e9c459d463d664563c755ec36f958f7Andy Huang        dest.writeParcelable(contentUri, flags);
23288fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang        dest.writeParcelable(thumbnailUri, flags);
233d49db8e3c4fff459f4ae3869ea80d083461eda2cPaul Westbrook        dest.writeParcelable(previewIntentUri, flags);
2347aee8f75f07eb39ecacdf0630d2199211aea5718Mindy Pereira        dest.writeString(partId);
235f944e9655562e321aff52fe5f437e1d2fa2950a9Mindy Pereira        dest.writeInt(origin);
23688fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang        dest.writeString(originExtras);
2377aee8f75f07eb39ecacdf0630d2199211aea5718Mindy Pereira    }
2387b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira
2397aee8f75f07eb39ecacdf0630d2199211aea5718Mindy Pereira    public static final Creator<Attachment> CREATOR = new Creator<Attachment>() {
2407aee8f75f07eb39ecacdf0630d2199211aea5718Mindy Pereira        @Override
2417aee8f75f07eb39ecacdf0630d2199211aea5718Mindy Pereira        public Attachment createFromParcel(Parcel source) {
2427aee8f75f07eb39ecacdf0630d2199211aea5718Mindy Pereira            return new Attachment(source);
2437aee8f75f07eb39ecacdf0630d2199211aea5718Mindy Pereira        }
2447b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira
2457aee8f75f07eb39ecacdf0630d2199211aea5718Mindy Pereira        @Override
2467aee8f75f07eb39ecacdf0630d2199211aea5718Mindy Pereira        public Attachment[] newArray(int size) {
2477aee8f75f07eb39ecacdf0630d2199211aea5718Mindy Pereira            return new Attachment[size];
2487aee8f75f07eb39ecacdf0630d2199211aea5718Mindy Pereira        }
2497aee8f75f07eb39ecacdf0630d2199211aea5718Mindy Pereira    };
250f944e9655562e321aff52fe5f437e1d2fa2950a9Mindy Pereira
25188fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang    public boolean isImage() {
252ac57b84f62110b1897176807ef1a02bd11675e71Mindy Pereira        return !TextUtils.isEmpty(contentType) ? contentType.startsWith("image/") : false;
25388fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang    }
254f944e9655562e321aff52fe5f437e1d2fa2950a9Mindy Pereira
25588fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang    public boolean isDownloading() {
25688fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang        return state == AttachmentState.DOWNLOADING;
257f944e9655562e321aff52fe5f437e1d2fa2950a9Mindy Pereira    }
258f944e9655562e321aff52fe5f437e1d2fa2950a9Mindy Pereira
25988fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang    public boolean isPresentLocally() {
26088fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang        return state == AttachmentState.SAVED || origin == LOCAL_FILE;
26188fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang    }
26288fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang
26388fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang    public boolean isSavedToExternal() {
26488fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang        return state == AttachmentState.SAVED && destination == AttachmentDestination.EXTERNAL;
265f944e9655562e321aff52fe5f437e1d2fa2950a9Mindy Pereira    }
2664401c9049f0327019b0bfed554bf8ff5cdaa20e2Mindy Pereira
267856200a2abc6a90711f6eb99fc0340dd75ef6e9bMark Wei    public boolean isInstallable() {
268856200a2abc6a90711f6eb99fc0340dd75ef6e9bMark Wei        return MimeType.isInstallable(contentType);
269856200a2abc6a90711f6eb99fc0340dd75ef6e9bMark Wei    }
270856200a2abc6a90711f6eb99fc0340dd75ef6e9bMark Wei
27188fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang    public boolean canSave() {
272856200a2abc6a90711f6eb99fc0340dd75ef6e9bMark Wei        return origin != LOCAL_FILE && !isSavedToExternal() && !isInstallable();
27388fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang    }
2744401c9049f0327019b0bfed554bf8ff5cdaa20e2Mindy Pereira
275d2f279ff7f4d257ff268b27be7379d4195354798Sara Ting    public boolean canShare() {
276d2f279ff7f4d257ff268b27be7379d4195354798Sara Ting        return isPresentLocally() && contentUri != null;
277d2f279ff7f4d257ff268b27be7379d4195354798Sara Ting    }
278d2f279ff7f4d257ff268b27be7379d4195354798Sara Ting
2794cb51dbce9635f4bf68a6de88f759e2f86d20325Andrew Sapperstein    public boolean shouldShowProgress() {
2804cb51dbce9635f4bf68a6de88f759e2f86d20325Andrew Sapperstein        return state == AttachmentState.DOWNLOADING
2814cb51dbce9635f4bf68a6de88f759e2f86d20325Andrew Sapperstein                && size > 0 && downloadedSize > 0 && downloadedSize < size;
282d0991f7f0d0882ac58dfdb1f8eb8e2a0abd573fcAndy Huang    }
283d0991f7f0d0882ac58dfdb1f8eb8e2a0abd573fcAndy Huang
28414977bf661dd6dc4d2a2414d0839e628ebed4d50Andrew Sapperstein    public boolean downloadFailed() {
28514977bf661dd6dc4d2a2414d0839e628ebed4d50Andrew Sapperstein        return state == AttachmentState.FAILED;
28614977bf661dd6dc4d2a2414d0839e628ebed4d50Andrew Sapperstein    }
28714977bf661dd6dc4d2a2414d0839e628ebed4d50Andrew Sapperstein
288d6318e56adadeff4106e9696b5330239175487b1Andrew Sapperstein    public boolean canPreview() {
289d6318e56adadeff4106e9696b5330239175487b1Andrew Sapperstein        return previewIntentUri != null;
290d6318e56adadeff4106e9696b5330239175487b1Andrew Sapperstein    }
291d6318e56adadeff4106e9696b5330239175487b1Andrew Sapperstein
2924f24bb48ab2c3e8fbda2af1e1d8fda79e8a458e7Andy Huang    /**
2934f24bb48ab2c3e8fbda2af1e1d8fda79e8a458e7Andy Huang     * Returns a stable identifier URI for this attachment.
2944f24bb48ab2c3e8fbda2af1e1d8fda79e8a458e7Andy Huang     *
2954f24bb48ab2c3e8fbda2af1e1d8fda79e8a458e7Andy Huang     * TODO: make the uri field stable, and put provider-specific opaque bits and bobs elsewhere
2964f24bb48ab2c3e8fbda2af1e1d8fda79e8a458e7Andy Huang     */
2974f24bb48ab2c3e8fbda2af1e1d8fda79e8a458e7Andy Huang    public Uri getIdentifierUri() {
2984f24bb48ab2c3e8fbda2af1e1d8fda79e8a458e7Andy Huang        if (mIdentifierUri == null) {
2994f24bb48ab2c3e8fbda2af1e1d8fda79e8a458e7Andy Huang            mIdentifierUri = Utils.isEmpty(uri) ? Uri.EMPTY : uri.buildUpon().clearQuery().build();
3004f24bb48ab2c3e8fbda2af1e1d8fda79e8a458e7Andy Huang        }
3014f24bb48ab2c3e8fbda2af1e1d8fda79e8a458e7Andy Huang        return mIdentifierUri;
3024f24bb48ab2c3e8fbda2af1e1d8fda79e8a458e7Andy Huang    }
3034f24bb48ab2c3e8fbda2af1e1d8fda79e8a458e7Andy Huang
3045a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang    // Methods to support JSON [de-]serialization of Attachment data
3055a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang    // TODO: add support for origin/originExtras (and possibly partId?) or fold those fields into
3065a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang    // other fields so Compose View can use JSON objects
3075a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang
3085a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang    public JSONObject toJSON() throws JSONException {
3098081df46ef5a7794374e41cd1836e778a2da9b31Paul Westbrook        return toJSON(name, size, uri, contentUri, contentType, state);
3105a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang    }
3115a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang
3125c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang    public static JSONObject toJSON(String name, int size, Uri uri, Uri contentUri,
3138081df46ef5a7794374e41cd1836e778a2da9b31Paul Westbrook            String contentType, Integer state) throws JSONException {
3145a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang        final JSONObject result = new JSONObject();
3155a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang
3165a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang        result.putOpt(AttachmentColumns.NAME, name);
3175a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang        result.putOpt(AttachmentColumns.SIZE, size);
3185a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang        if (uri != null) {
3195a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang            result.putOpt(AttachmentColumns.URI, uri.toString());
3205a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang        }
3215c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang        if (contentUri != null) {
3225c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang            result.putOpt(AttachmentColumns.CONTENT_URI, contentUri.toString());
3235c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang        }
3245a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang        result.putOpt(AttachmentColumns.CONTENT_TYPE, contentType);
3258081df46ef5a7794374e41cd1836e778a2da9b31Paul Westbrook        if (state != null) {
3268081df46ef5a7794374e41cd1836e778a2da9b31Paul Westbrook            result.put(AttachmentColumns.STATE, state.intValue());
3278081df46ef5a7794374e41cd1836e778a2da9b31Paul Westbrook        }
3285a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang
3295a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang        return result;
3305a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang    }
3315a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang
3325a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang    public Attachment(JSONObject srcJson) {
3335a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang        name = srcJson.optString(AttachmentColumns.NAME, null);
3345a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang        size = srcJson.optInt(AttachmentColumns.SIZE);
3355a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang        uri = parseOptionalUri(srcJson, AttachmentColumns.URI);
3365c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang        contentUri = parseOptionalUri(srcJson, AttachmentColumns.CONTENT_URI);
3375a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang        contentType = srcJson.optString(AttachmentColumns.CONTENT_TYPE, null);
3388081df46ef5a7794374e41cd1836e778a2da9b31Paul Westbrook        if (srcJson.has(AttachmentColumns.STATE)) {
3398081df46ef5a7794374e41cd1836e778a2da9b31Paul Westbrook            state = srcJson.optInt(AttachmentColumns.STATE);
3408081df46ef5a7794374e41cd1836e778a2da9b31Paul Westbrook        }
3415a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang    }
3425a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang
3435a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang    private static Uri parseOptionalUri(JSONObject srcJson, String key) {
3445a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang        final String uriStr = srcJson.optString(key, null);
3455a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang        return uriStr == null ? null : Uri.parse(uriStr);
3465a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang    }
3475a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang
3485a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang    public static String toJSONArray(Collection<Attachment> attachments) {
3495a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang        final JSONArray result = new JSONArray();
3505a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang        try {
3515a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang            for (Attachment attachment : attachments) {
3525a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang                result.put(attachment.toJSON());
3535a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang            }
3545a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang        } catch (JSONException e) {
3555a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang            throw new IllegalArgumentException(e);
3565a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang        }
3575a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang        return result.toString();
3585a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang    }
3595a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang
3605a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang    public static List<Attachment> fromJSONArray(String jsonArrayStr) {
3615a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang        final List<Attachment> results = Lists.newArrayList();
3625a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang        try {
3635a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang            final JSONArray arr = new JSONArray(jsonArrayStr);
3645a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang
3655a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang            for (int i = 0; i < arr.length(); i++) {
3665a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang                results.add(new Attachment(arr.getJSONObject(i)));
3675a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang            }
3685a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang
3695a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang        } catch (JSONException e) {
3705a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang            throw new IllegalArgumentException(e);
3715a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang        }
3725a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang        return results;
3735a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang    }
3747b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira}
375