Attachment.java revision b334c9035e9b7a38766bb66c29da2208525d1e11
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.content.Intent;
1988fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huangimport android.database.Cursor;
2088fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huangimport android.net.Uri;
217aee8f75f07eb39ecacdf0630d2199211aea5718Mindy Pereiraimport android.os.Parcel;
227aee8f75f07eb39ecacdf0630d2199211aea5718Mindy Pereiraimport android.os.Parcelable;
23f944e9655562e321aff52fe5f437e1d2fa2950a9Mindy Pereiraimport android.text.TextUtils;
24f944e9655562e321aff52fe5f437e1d2fa2950a9Mindy Pereira
2588fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huangimport com.android.mail.providers.UIProvider.AttachmentColumns;
2688fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huangimport com.android.mail.providers.UIProvider.AttachmentDestination;
2788fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huangimport com.android.mail.providers.UIProvider.AttachmentState;
28b334c9035e9b7a38766bb66c29da2208525d1e11Paul Westbrookimport com.android.mail.utils.LogTag;
295a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huangimport com.android.mail.utils.LogUtils;
304c7d8b5f38bfa80192d457025b834c975d7d38a3Andrew Sappersteinimport com.google.common.collect.Lists;
315a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang
325a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huangimport org.json.JSONArray;
335a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huangimport org.json.JSONException;
345a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huangimport org.json.JSONObject;
357b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira
365a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huangimport java.util.Collection;
375a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huangimport java.util.List;
384401c9049f0327019b0bfed554bf8ff5cdaa20e2Mindy Pereira
397aee8f75f07eb39ecacdf0630d2199211aea5718Mindy Pereirapublic class Attachment implements Parcelable {
40f944e9655562e321aff52fe5f437e1d2fa2950a9Mindy Pereira    public static final int SERVER_ATTACHMENT = 0;
41f944e9655562e321aff52fe5f437e1d2fa2950a9Mindy Pereira    /** Extras are "<path>". */
42f944e9655562e321aff52fe5f437e1d2fa2950a9Mindy Pereira    public static final int  LOCAL_FILE = 1;
43f944e9655562e321aff52fe5f437e1d2fa2950a9Mindy Pereira
44b334c9035e9b7a38766bb66c29da2208525d1e11Paul Westbrook    public static final String LOG_TAG = LogTag.getLogTag();
455a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang
467aee8f75f07eb39ecacdf0630d2199211aea5718Mindy Pereira    /**
4788fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang     * Attachment file name. See {@link AttachmentColumns#NAME}.
487aee8f75f07eb39ecacdf0630d2199211aea5718Mindy Pereira     */
497aee8f75f07eb39ecacdf0630d2199211aea5718Mindy Pereira    public String name;
50f944e9655562e321aff52fe5f437e1d2fa2950a9Mindy Pereira
5188fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang    /**
5288fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang     * Attachment size in bytes. See {@link AttachmentColumns#SIZE}.
5388fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang     */
5488fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang    public int size;
55f944e9655562e321aff52fe5f437e1d2fa2950a9Mindy Pereira
567aee8f75f07eb39ecacdf0630d2199211aea5718Mindy Pereira    /**
575c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang     * The provider-generated URI for this Attachment. Must be globally unique. For local
585c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang     * attachments generated by the Compose UI prior to send/save, this field will be null.
595c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang     *
605c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang     *@see AttachmentColumns#URI
617aee8f75f07eb39ecacdf0630d2199211aea5718Mindy Pereira     */
6288fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang    public Uri uri;
6388fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang
647aee8f75f07eb39ecacdf0630d2199211aea5718Mindy Pereira    /**
655c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang     * MIME type of the file.
665c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang     *
675c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang     * @see AttachmentColumns#CONTENT_TYPE
687aee8f75f07eb39ecacdf0630d2199211aea5718Mindy Pereira     */
691eb5f96d4e9c459d463d664563c755ec36f958f7Andy Huang    public String contentType;
7088fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang
7188fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang    /**
725c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang     * @see AttachmentColumns#STATE
7388fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang     */
7488fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang    public int state;
7588fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang
7688fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang    /**
775c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang     * @see AttachmentColumns#DESTINATION
7888fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang     */
7988fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang    public int destination;
8088fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang
817aee8f75f07eb39ecacdf0630d2199211aea5718Mindy Pereira    /**
825c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang     * @see AttachmentColumns#DOWNLOADED_SIZE
837aee8f75f07eb39ecacdf0630d2199211aea5718Mindy Pereira     */
8488fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang    public int downloadedSize;
8588fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang
8688fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang    /**
875c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang     * @see AttachmentColumns#CONTENT_URI
8888fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang     */
891eb5f96d4e9c459d463d664563c755ec36f958f7Andy Huang    public Uri contentUri;
9088fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang
9188fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang    /**
925c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang     * Might be null.
935c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang     *
945c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang     * @see AttachmentColumns#THUMBNAIL_URI
9588fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang     */
9688fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang    public Uri thumbnailUri;
9788fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang
9888fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang    /**
995c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang     * Might be null.
1005c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang     *
1015c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang     * @see AttachmentColumns#PREVIEW_INTENT
10288fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang     */
10388fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang    public Intent previewIntent;
10488fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang
1057aee8f75f07eb39ecacdf0630d2199211aea5718Mindy Pereira    /**
1067aee8f75f07eb39ecacdf0630d2199211aea5718Mindy Pereira     * Part id of the attachment.
1077aee8f75f07eb39ecacdf0630d2199211aea5718Mindy Pereira     */
1085c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang    @Deprecated
1095c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang    // partId is provider implementation specific. providers must uniquely identify Attachments
1105c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang    // by uri.
1117aee8f75f07eb39ecacdf0630d2199211aea5718Mindy Pereira    public String partId;
11288fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang
1135c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang    @Deprecated
1145c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang    // this is a local file iff the provider 'uri' field is null.
11588fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang    public int origin;
11688fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang
1177aee8f75f07eb39ecacdf0630d2199211aea5718Mindy Pereira    /**
11888fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang     * Attachment origin info.
11988fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang     * TODO: do we want this? Or location?
1207aee8f75f07eb39ecacdf0630d2199211aea5718Mindy Pereira     */
1215c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang    @Deprecated
12288fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang    public String originExtras;
1237b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira
1247aee8f75f07eb39ecacdf0630d2199211aea5718Mindy Pereira    public Attachment(Parcel in) {
1257aee8f75f07eb39ecacdf0630d2199211aea5718Mindy Pereira        name = in.readString();
12688fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang        size = in.readInt();
12788fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang        uri = in.readParcelable(null);
1281eb5f96d4e9c459d463d664563c755ec36f958f7Andy Huang        contentType = in.readString();
12988fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang        state = in.readInt();
13088fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang        destination = in.readInt();
13188fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang        downloadedSize = in.readInt();
1321eb5f96d4e9c459d463d664563c755ec36f958f7Andy Huang        contentUri = in.readParcelable(null);
13388fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang        thumbnailUri = in.readParcelable(null);
13488fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang        previewIntent = in.readParcelable(null);
1357aee8f75f07eb39ecacdf0630d2199211aea5718Mindy Pereira        partId = in.readString();
136f944e9655562e321aff52fe5f437e1d2fa2950a9Mindy Pereira        origin = in.readInt();
13788fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang        originExtras = in.readString();
1387aee8f75f07eb39ecacdf0630d2199211aea5718Mindy Pereira    }
1397b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira
1407aee8f75f07eb39ecacdf0630d2199211aea5718Mindy Pereira    public Attachment() {
1417aee8f75f07eb39ecacdf0630d2199211aea5718Mindy Pereira    }
1427b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira
14388fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang    public Attachment(Cursor cursor) {
14488fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang        if (cursor == null) {
14588fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang            return;
14688fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang        }
14788fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang
1484c7d8b5f38bfa80192d457025b834c975d7d38a3Andrew Sapperstein        name = cursor.getString(cursor.getColumnIndex(AttachmentColumns.NAME));
1494c7d8b5f38bfa80192d457025b834c975d7d38a3Andrew Sapperstein        size = cursor.getInt(cursor.getColumnIndex(AttachmentColumns.SIZE));
1504c7d8b5f38bfa80192d457025b834c975d7d38a3Andrew Sapperstein        uri = Uri.parse(cursor.getString(cursor.getColumnIndex(AttachmentColumns.URI)));
1514c7d8b5f38bfa80192d457025b834c975d7d38a3Andrew Sapperstein        contentType = cursor.getString(cursor.getColumnIndex(AttachmentColumns.CONTENT_TYPE));
1524c7d8b5f38bfa80192d457025b834c975d7d38a3Andrew Sapperstein        state = cursor.getInt(cursor.getColumnIndex(AttachmentColumns.STATE));
1534c7d8b5f38bfa80192d457025b834c975d7d38a3Andrew Sapperstein        destination = cursor.getInt(cursor.getColumnIndex(AttachmentColumns.DESTINATION));
1544c7d8b5f38bfa80192d457025b834c975d7d38a3Andrew Sapperstein        downloadedSize = cursor.getInt(cursor.getColumnIndex(AttachmentColumns.DOWNLOADED_SIZE));
1554c7d8b5f38bfa80192d457025b834c975d7d38a3Andrew Sapperstein        contentUri = parseOptionalUri(
1564c7d8b5f38bfa80192d457025b834c975d7d38a3Andrew Sapperstein                cursor.getString(cursor.getColumnIndex(AttachmentColumns.CONTENT_URI)));
15788fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang        thumbnailUri = parseOptionalUri(
1584c7d8b5f38bfa80192d457025b834c975d7d38a3Andrew Sapperstein                cursor.getString(cursor.getColumnIndex(AttachmentColumns.THUMBNAIL_URI)));
15988fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang        previewIntent = getOptionalIntentFromBlob(
1604c7d8b5f38bfa80192d457025b834c975d7d38a3Andrew Sapperstein                cursor.getBlob(cursor.getColumnIndex(AttachmentColumns.PREVIEW_INTENT)));
16188fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang
16288fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang        // TODO: ensure that local files attached to a draft have sane values, like SAVED/EXTERNAL
16388fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang        // and that contentUri is populated
16488fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang    }
16588fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang
1665c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang    @Deprecated
167f944e9655562e321aff52fe5f437e1d2fa2950a9Mindy Pereira    public Attachment(String attachmentString) {
1685e1a5b7a9d694ff812e65f4b1240366252cdcde7Paul Westbrook        String[] attachmentValues = TextUtils.split(attachmentString, "\\|");
169f944e9655562e321aff52fe5f437e1d2fa2950a9Mindy Pereira        if (attachmentValues != null) {
170f944e9655562e321aff52fe5f437e1d2fa2950a9Mindy Pereira            partId = attachmentValues[0];
171f944e9655562e321aff52fe5f437e1d2fa2950a9Mindy Pereira            name = attachmentValues[1];
1721eb5f96d4e9c459d463d664563c755ec36f958f7Andy Huang            contentType = attachmentValues[2];
173f944e9655562e321aff52fe5f437e1d2fa2950a9Mindy Pereira            try {
17488fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang                size = Integer.parseInt(attachmentValues[3]);
175f944e9655562e321aff52fe5f437e1d2fa2950a9Mindy Pereira            } catch (NumberFormatException e) {
176f944e9655562e321aff52fe5f437e1d2fa2950a9Mindy Pereira                size = 0;
177f944e9655562e321aff52fe5f437e1d2fa2950a9Mindy Pereira            }
1781eb5f96d4e9c459d463d664563c755ec36f958f7Andy Huang            contentType = attachmentValues[4];
179f944e9655562e321aff52fe5f437e1d2fa2950a9Mindy Pereira            origin = Integer.parseInt(attachmentValues[5]);
1801eb5f96d4e9c459d463d664563c755ec36f958f7Andy Huang            contentUri = parseOptionalUri(attachmentValues[6]);
181f944e9655562e321aff52fe5f437e1d2fa2950a9Mindy Pereira            originExtras = attachmentValues[7];
182f944e9655562e321aff52fe5f437e1d2fa2950a9Mindy Pereira        }
183f944e9655562e321aff52fe5f437e1d2fa2950a9Mindy Pereira    }
184f944e9655562e321aff52fe5f437e1d2fa2950a9Mindy Pereira
1855c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang    @Deprecated
18688fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang    public String toJoinedString() {
1871eb5f96d4e9c459d463d664563c755ec36f958f7Andy Huang        // FIXME: contentType is read/written twice
18888fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang        return TextUtils.join("|", Lists.newArrayList(partId == null ? "" : partId,
1891eb5f96d4e9c459d463d664563c755ec36f958f7Andy Huang                name == null ? "" : name.replaceAll("[|\n]", ""), contentType, size, contentType,
1905c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang                contentUri != null ? LOCAL_FILE : SERVER_ATTACHMENT, contentUri,
1915c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang                originExtras == null ? "" : originExtras, ""));
19288fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang    }
19388fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang
19488fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang    private static Intent getOptionalIntentFromBlob(byte[] blob) {
19588fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang        if (blob == null) {
19688fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang            return null;
19788fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang        }
19888fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang        final Parcel intentParcel = Parcel.obtain();
19988fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang        intentParcel.unmarshall(blob, 0, blob.length);
20088fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang        final Intent intent = new Intent();
20188fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang        intent.readFromParcel(intentParcel);
20288fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang        return intent;
20388fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang    }
20488fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang
20588fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang    private static Uri parseOptionalUri(String uriString) {
20688fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang        return uriString == null ? null : Uri.parse(uriString);
20788fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang    }
20888fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang
2097aee8f75f07eb39ecacdf0630d2199211aea5718Mindy Pereira    @Override
2107aee8f75f07eb39ecacdf0630d2199211aea5718Mindy Pereira    public int describeContents() {
2117aee8f75f07eb39ecacdf0630d2199211aea5718Mindy Pereira        return 0;
2127aee8f75f07eb39ecacdf0630d2199211aea5718Mindy Pereira    }
2137b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira
2147aee8f75f07eb39ecacdf0630d2199211aea5718Mindy Pereira    @Override
2157aee8f75f07eb39ecacdf0630d2199211aea5718Mindy Pereira    public void writeToParcel(Parcel dest, int flags) {
2167aee8f75f07eb39ecacdf0630d2199211aea5718Mindy Pereira        dest.writeString(name);
21788fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang        dest.writeInt(size);
21888fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang        dest.writeParcelable(uri, flags);
2191eb5f96d4e9c459d463d664563c755ec36f958f7Andy Huang        dest.writeString(contentType);
22088fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang        dest.writeInt(state);
22188fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang        dest.writeInt(destination);
22288fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang        dest.writeInt(downloadedSize);
2231eb5f96d4e9c459d463d664563c755ec36f958f7Andy Huang        dest.writeParcelable(contentUri, flags);
22488fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang        dest.writeParcelable(thumbnailUri, flags);
22588fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang        dest.writeParcelable(previewIntent, flags);
2267aee8f75f07eb39ecacdf0630d2199211aea5718Mindy Pereira        dest.writeString(partId);
227f944e9655562e321aff52fe5f437e1d2fa2950a9Mindy Pereira        dest.writeInt(origin);
22888fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang        dest.writeString(originExtras);
2297aee8f75f07eb39ecacdf0630d2199211aea5718Mindy Pereira    }
2307b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira
2317aee8f75f07eb39ecacdf0630d2199211aea5718Mindy Pereira    public static final Creator<Attachment> CREATOR = new Creator<Attachment>() {
2327aee8f75f07eb39ecacdf0630d2199211aea5718Mindy Pereira        @Override
2337aee8f75f07eb39ecacdf0630d2199211aea5718Mindy Pereira        public Attachment createFromParcel(Parcel source) {
2347aee8f75f07eb39ecacdf0630d2199211aea5718Mindy Pereira            return new Attachment(source);
2357aee8f75f07eb39ecacdf0630d2199211aea5718Mindy Pereira        }
2367b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira
2377aee8f75f07eb39ecacdf0630d2199211aea5718Mindy Pereira        @Override
2387aee8f75f07eb39ecacdf0630d2199211aea5718Mindy Pereira        public Attachment[] newArray(int size) {
2397aee8f75f07eb39ecacdf0630d2199211aea5718Mindy Pereira            return new Attachment[size];
2407aee8f75f07eb39ecacdf0630d2199211aea5718Mindy Pereira        }
2417aee8f75f07eb39ecacdf0630d2199211aea5718Mindy Pereira    };
242f944e9655562e321aff52fe5f437e1d2fa2950a9Mindy Pereira
24388fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang    public boolean isImage() {
244ac57b84f62110b1897176807ef1a02bd11675e71Mindy Pereira        return !TextUtils.isEmpty(contentType) ? contentType.startsWith("image/") : false;
24588fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang    }
246f944e9655562e321aff52fe5f437e1d2fa2950a9Mindy Pereira
24788fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang    public boolean isDownloading() {
24888fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang        return state == AttachmentState.DOWNLOADING;
249f944e9655562e321aff52fe5f437e1d2fa2950a9Mindy Pereira    }
250f944e9655562e321aff52fe5f437e1d2fa2950a9Mindy Pereira
25188fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang    public boolean isPresentLocally() {
25288fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang        return state == AttachmentState.SAVED || origin == LOCAL_FILE;
25388fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang    }
25488fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang
25588fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang    public boolean isSavedToExternal() {
25688fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang        return state == AttachmentState.SAVED && destination == AttachmentDestination.EXTERNAL;
257f944e9655562e321aff52fe5f437e1d2fa2950a9Mindy Pereira    }
2584401c9049f0327019b0bfed554bf8ff5cdaa20e2Mindy Pereira
25988fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang    public boolean canSave() {
260c6663c4f87b458aefef3213599ddea65e87ae223Andy Huang        return origin != LOCAL_FILE && state != AttachmentState.DOWNLOADING &&
261c6663c4f87b458aefef3213599ddea65e87ae223Andy Huang                !isSavedToExternal();
26288fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang    }
2634401c9049f0327019b0bfed554bf8ff5cdaa20e2Mindy Pereira
264d0991f7f0d0882ac58dfdb1f8eb8e2a0abd573fcAndy Huang    /**
265d0991f7f0d0882ac58dfdb1f8eb8e2a0abd573fcAndy Huang     * If this attachment is an image, returns a Uri pointing to the image that can be used as a
266d0991f7f0d0882ac58dfdb1f8eb8e2a0abd573fcAndy Huang     * thumbnail. If the provider supports dedicated thumbnails, it will be relatively small, but
267d0991f7f0d0882ac58dfdb1f8eb8e2a0abd573fcAndy Huang     * if not, the image may be arbitrarily large. Client code must handle this efficiently. For
268d0991f7f0d0882ac58dfdb1f8eb8e2a0abd573fcAndy Huang     * non-image attachments, this method will return null. This method may also return null if the
269d0991f7f0d0882ac58dfdb1f8eb8e2a0abd573fcAndy Huang     * attachment is not yet downloaded.
270d0991f7f0d0882ac58dfdb1f8eb8e2a0abd573fcAndy Huang     */
271d0991f7f0d0882ac58dfdb1f8eb8e2a0abd573fcAndy Huang    public Uri getImageUri() {
272d0991f7f0d0882ac58dfdb1f8eb8e2a0abd573fcAndy Huang        if (!isImage()) {
273d0991f7f0d0882ac58dfdb1f8eb8e2a0abd573fcAndy Huang            return null;
274d0991f7f0d0882ac58dfdb1f8eb8e2a0abd573fcAndy Huang        }
275d0991f7f0d0882ac58dfdb1f8eb8e2a0abd573fcAndy Huang
276d0991f7f0d0882ac58dfdb1f8eb8e2a0abd573fcAndy Huang        return (thumbnailUri != null) ? thumbnailUri : contentUri;
277d0991f7f0d0882ac58dfdb1f8eb8e2a0abd573fcAndy Huang    }
278d0991f7f0d0882ac58dfdb1f8eb8e2a0abd573fcAndy Huang
2795a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang    // Methods to support JSON [de-]serialization of Attachment data
2805a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang    // TODO: add support for origin/originExtras (and possibly partId?) or fold those fields into
2815a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang    // other fields so Compose View can use JSON objects
2825a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang
2835a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang    public JSONObject toJSON() throws JSONException {
2845c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang        return toJSON(name, size, uri, contentUri, contentType);
2855a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang    }
2865a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang
2875c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang    public static JSONObject toJSON(String name, int size, Uri uri, Uri contentUri,
2885c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang            String contentType) throws JSONException {
2895a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang        final JSONObject result = new JSONObject();
2905a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang
2915a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang        result.putOpt(AttachmentColumns.NAME, name);
2925a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang        result.putOpt(AttachmentColumns.SIZE, size);
2935a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang        if (uri != null) {
2945a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang            result.putOpt(AttachmentColumns.URI, uri.toString());
2955a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang        }
2965c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang        if (contentUri != null) {
2975c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang            result.putOpt(AttachmentColumns.CONTENT_URI, contentUri.toString());
2985c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang        }
2995a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang        result.putOpt(AttachmentColumns.CONTENT_TYPE, contentType);
3005a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang
3015a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang        return result;
3025a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang    }
3035a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang
3045a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang    public Attachment(JSONObject srcJson) {
3055a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang        name = srcJson.optString(AttachmentColumns.NAME, null);
3065a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang        size = srcJson.optInt(AttachmentColumns.SIZE);
3075a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang        uri = parseOptionalUri(srcJson, AttachmentColumns.URI);
3085c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang        contentUri = parseOptionalUri(srcJson, AttachmentColumns.CONTENT_URI);
3095a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang        contentType = srcJson.optString(AttachmentColumns.CONTENT_TYPE, null);
3105a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang    }
3115a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang
3125a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang    private static Uri parseOptionalUri(JSONObject srcJson, String key) {
3135a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang        final String uriStr = srcJson.optString(key, null);
3145a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang        return uriStr == null ? null : Uri.parse(uriStr);
3155a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang    }
3165a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang
3175a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang    public static String toJSONArray(Collection<Attachment> attachments) {
3185a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang        final JSONArray result = new JSONArray();
3195a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang        try {
3205a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang            for (Attachment attachment : attachments) {
3215a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang                result.put(attachment.toJSON());
3225a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang            }
3235a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang        } catch (JSONException e) {
3245a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang            throw new IllegalArgumentException(e);
3255a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang        }
3265a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang        return result.toString();
3275a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang    }
3285a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang
3295a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang    public static List<Attachment> fromJSONArray(String jsonArrayStr) {
3305a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang        final List<Attachment> results = Lists.newArrayList();
3315a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang        try {
3325a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang            final JSONArray arr = new JSONArray(jsonArrayStr);
3335a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang
3345a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang            for (int i = 0; i < arr.length(); i++) {
3355a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang                results.add(new Attachment(arr.getJSONObject(i)));
3365a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang            }
3375a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang
3385a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang        } catch (JSONException e) {
3395a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang            throw new IllegalArgumentException(e);
3405a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang        }
3415a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang        return results;
3425a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang    }
3435a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang
3447b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira}
345