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 */
16bbe74aee04f669990e888095b0d6858dc1e17ce1Mark Wei
1730e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangpackage com.android.mail.providers;
187b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira
197434e800d4313a227120ca36bd95683752a7879fAndrew Sappersteinimport android.content.ContentResolver;
207434e800d4313a227120ca36bd95683752a7879fAndrew Sappersteinimport android.content.ContentValues;
217434e800d4313a227120ca36bd95683752a7879fAndrew Sappersteinimport android.content.Context;
2288fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huangimport android.database.Cursor;
2388fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huangimport android.net.Uri;
247aee8f75f07eb39ecacdf0630d2199211aea5718Mindy Pereiraimport android.os.Parcel;
257aee8f75f07eb39ecacdf0630d2199211aea5718Mindy Pereiraimport android.os.Parcelable;
26f944e9655562e321aff52fe5f437e1d2fa2950a9Mindy Pereiraimport android.text.TextUtils;
27f944e9655562e321aff52fe5f437e1d2fa2950a9Mindy Pereira
287434e800d4313a227120ca36bd95683752a7879fAndrew Sappersteinimport com.android.emailcommon.internet.MimeUtility;
297434e800d4313a227120ca36bd95683752a7879fAndrew Sappersteinimport com.android.emailcommon.mail.MessagingException;
307434e800d4313a227120ca36bd95683752a7879fAndrew Sappersteinimport com.android.emailcommon.mail.Part;
31bf3a5c5aa46759a238b3ca197b97bc4182cba8b6Mark Weiimport com.android.mail.browse.MessageAttachmentBar;
3288fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huangimport com.android.mail.providers.UIProvider.AttachmentColumns;
3388fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huangimport com.android.mail.providers.UIProvider.AttachmentDestination;
34479505d71969e26b0785d8e0e1b81108731cf827Mark Weiimport com.android.mail.providers.UIProvider.AttachmentRendition;
3588fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huangimport com.android.mail.providers.UIProvider.AttachmentState;
36beaf1e4d14f89e7735ba94a0b2ff92233c6f928fMark Weiimport com.android.mail.providers.UIProvider.AttachmentType;
37b334c9035e9b7a38766bb66c29da2208525d1e11Paul Westbrookimport com.android.mail.utils.LogTag;
38f467d10bb05a8df6ac3c8279f6fda24e89b87482Paul Westbrookimport com.android.mail.utils.LogUtils;
39856200a2abc6a90711f6eb99fc0340dd75ef6e9bMark Weiimport com.android.mail.utils.MimeType;
404f24bb48ab2c3e8fbda2af1e1d8fda79e8a458e7Andy Huangimport com.android.mail.utils.Utils;
417434e800d4313a227120ca36bd95683752a7879fAndrew Sappersteinimport com.google.common.base.Objects;
427434e800d4313a227120ca36bd95683752a7879fAndrew Sappersteinimport com.google.common.collect.Lists;
435a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang
447434e800d4313a227120ca36bd95683752a7879fAndrew Sappersteinimport org.apache.commons.io.IOUtils;
455a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huangimport org.json.JSONArray;
465a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huangimport org.json.JSONException;
475a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huangimport org.json.JSONObject;
487b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira
497434e800d4313a227120ca36bd95683752a7879fAndrew Sappersteinimport java.io.FileNotFoundException;
507434e800d4313a227120ca36bd95683752a7879fAndrew Sappersteinimport java.io.IOException;
517434e800d4313a227120ca36bd95683752a7879fAndrew Sappersteinimport java.io.InputStream;
527434e800d4313a227120ca36bd95683752a7879fAndrew Sappersteinimport java.io.OutputStream;
535a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huangimport java.util.Collection;
545a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huangimport java.util.List;
554401c9049f0327019b0bfed554bf8ff5cdaa20e2Mindy Pereira
567aee8f75f07eb39ecacdf0630d2199211aea5718Mindy Pereirapublic class Attachment implements Parcelable {
57479505d71969e26b0785d8e0e1b81108731cf827Mark Wei    public static final int MAX_ATTACHMENT_PREVIEWS = 2;
58b334c9035e9b7a38766bb66c29da2208525d1e11Paul Westbrook    public static final String LOG_TAG = LogTag.getLogTag();
597df813e56ba3a8620e934bd462527a2467fcae52Mark Wei    /**
607df813e56ba3a8620e934bd462527a2467fcae52Mark Wei     * Workaround for b/8070022 so that appending a null partId to the end of a
617df813e56ba3a8620e934bd462527a2467fcae52Mark Wei     * uri wouldn't remove the trailing backslash
627df813e56ba3a8620e934bd462527a2467fcae52Mark Wei     */
637df813e56ba3a8620e934bd462527a2467fcae52Mark Wei    public static final String EMPTY_PART_ID = "empty";
645a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang
65519c218db6109003ca72a35ffe276ed69b0230a4Martin Hibdon    // Indicates that this is a dummy placeholder attachment.
66519c218db6109003ca72a35ffe276ed69b0230a4Martin Hibdon    public static final int FLAG_DUMMY_ATTACHMENT = 1<<10;
67519c218db6109003ca72a35ffe276ed69b0230a4Martin Hibdon
687aee8f75f07eb39ecacdf0630d2199211aea5718Mindy Pereira    /**
69bbe74aee04f669990e888095b0d6858dc1e17ce1Mark Wei     * Part id of the attachment.
70bbe74aee04f669990e888095b0d6858dc1e17ce1Mark Wei     */
71bbe74aee04f669990e888095b0d6858dc1e17ce1Mark Wei    public String partId;
72bbe74aee04f669990e888095b0d6858dc1e17ce1Mark Wei
73bbe74aee04f669990e888095b0d6858dc1e17ce1Mark Wei    /**
74479505d71969e26b0785d8e0e1b81108731cf827Mark Wei     * Attachment file name. See {@link AttachmentColumns#NAME} Use {@link #setName(String)}.
757aee8f75f07eb39ecacdf0630d2199211aea5718Mindy Pereira     */
768750066b10f80e2a8080016973b3296d76d18266Mark Wei    private String name;
77f944e9655562e321aff52fe5f437e1d2fa2950a9Mindy Pereira
7888fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang    /**
7988fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang     * Attachment size in bytes. See {@link AttachmentColumns#SIZE}.
8088fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang     */
8188fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang    public int size;
82f944e9655562e321aff52fe5f437e1d2fa2950a9Mindy Pereira
837aee8f75f07eb39ecacdf0630d2199211aea5718Mindy Pereira    /**
84bbe74aee04f669990e888095b0d6858dc1e17ce1Mark Wei     * The provider-generated URI for this Attachment. Must be globally unique.
85bbe74aee04f669990e888095b0d6858dc1e17ce1Mark Wei     * For local attachments generated by the Compose UI prior to send/save,
86bbe74aee04f669990e888095b0d6858dc1e17ce1Mark Wei     * this field will be null.
875c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang     *
88bbe74aee04f669990e888095b0d6858dc1e17ce1Mark Wei     * @see AttachmentColumns#URI
897aee8f75f07eb39ecacdf0630d2199211aea5718Mindy Pereira     */
9088fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang    public Uri uri;
9188fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang
927aee8f75f07eb39ecacdf0630d2199211aea5718Mindy Pereira    /**
93479505d71969e26b0785d8e0e1b81108731cf827Mark Wei     * MIME type of the file. Use {@link #getContentType()} and {@link #setContentType(String)}.
945c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang     *
955c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang     * @see AttachmentColumns#CONTENT_TYPE
967aee8f75f07eb39ecacdf0630d2199211aea5718Mindy Pereira     */
978750066b10f80e2a8080016973b3296d76d18266Mark Wei    private String contentType;
988750066b10f80e2a8080016973b3296d76d18266Mark Wei    private String inferredContentType;
9988fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang
10088fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang    /**
101beaf1e4d14f89e7735ba94a0b2ff92233c6f928fMark Wei     * Use {@link #setState(int)}
102beaf1e4d14f89e7735ba94a0b2ff92233c6f928fMark Wei     *
103beaf1e4d14f89e7735ba94a0b2ff92233c6f928fMark Wei     * @see AttachmentColumns#STATE
10488fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang     */
10588fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang    public int state;
10688fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang
10788fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang    /**
1085c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang     * @see AttachmentColumns#DESTINATION
10988fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang     */
11088fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang    public int destination;
11188fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang
1127aee8f75f07eb39ecacdf0630d2199211aea5718Mindy Pereira    /**
1135c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang     * @see AttachmentColumns#DOWNLOADED_SIZE
1147aee8f75f07eb39ecacdf0630d2199211aea5718Mindy Pereira     */
11588fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang    public int downloadedSize;
11688fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang
11788fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang    /**
1183ca3bf8538bbabcaf9d86818e25c40f3a9d9b0c9Mark Wei     * Shareable, openable uri for this attachment
119bf3a5c5aa46759a238b3ca197b97bc4182cba8b6Mark Wei     * <p>
1203ca3bf8538bbabcaf9d86818e25c40f3a9d9b0c9Mark Wei     * content:// Gmail.getAttachmentDefaultUri() if origin is SERVER_ATTACHMENT
121bf3a5c5aa46759a238b3ca197b97bc4182cba8b6Mark Wei     * <p>
122bf3a5c5aa46759a238b3ca197b97bc4182cba8b6Mark Wei     * content:// uri pointing to the content to be uploaded if origin is
123bf3a5c5aa46759a238b3ca197b97bc4182cba8b6Mark Wei     * LOCAL_FILE
124bf3a5c5aa46759a238b3ca197b97bc4182cba8b6Mark Wei     * <p>
125bf3a5c5aa46759a238b3ca197b97bc4182cba8b6Mark Wei     * file:// uri pointing to an EXTERNAL apk file. The package manager only
126bf3a5c5aa46759a238b3ca197b97bc4182cba8b6Mark Wei     * handles file:// uris not content:// uris. We do the same workaround in
127bf3a5c5aa46759a238b3ca197b97bc4182cba8b6Mark Wei     * {@link MessageAttachmentBar#onClick(android.view.View)} and
128bf3a5c5aa46759a238b3ca197b97bc4182cba8b6Mark Wei     * UiProvider#getUiAttachmentsCursorForUIAttachments().
129bf3a5c5aa46759a238b3ca197b97bc4182cba8b6Mark Wei     *
1305c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang     * @see AttachmentColumns#CONTENT_URI
13188fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang     */
1321eb5f96d4e9c459d463d664563c755ec36f958f7Andy Huang    public Uri contentUri;
13388fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang
13488fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang    /**
1355c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang     * Might be null.
1365c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang     *
1375c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang     * @see AttachmentColumns#THUMBNAIL_URI
13888fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang     */
13988fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang    public Uri thumbnailUri;
14088fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang
14188fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang    /**
1425c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang     * Might be null.
1435c5fd571b40a15b95ea5a5d6033f377706ffd0fbAndy Huang     *
144bbe74aee04f669990e888095b0d6858dc1e17ce1Mark Wei     * @see AttachmentColumns#PREVIEW_INTENT_URI
14588fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang     */
146d49db8e3c4fff459f4ae3869ea80d083461eda2cPaul Westbrook    public Uri previewIntentUri;
14788fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang
1487aee8f75f07eb39ecacdf0630d2199211aea5718Mindy Pereira    /**
149beaf1e4d14f89e7735ba94a0b2ff92233c6f928fMark Wei     * The visibility type of this attachment.
150beaf1e4d14f89e7735ba94a0b2ff92233c6f928fMark Wei     *
151beaf1e4d14f89e7735ba94a0b2ff92233c6f928fMark Wei     * @see AttachmentColumns#TYPE
152beaf1e4d14f89e7735ba94a0b2ff92233c6f928fMark Wei     */
153beaf1e4d14f89e7735ba94a0b2ff92233c6f928fMark Wei    public int type;
154beaf1e4d14f89e7735ba94a0b2ff92233c6f928fMark Wei
155519c218db6109003ca72a35ffe276ed69b0230a4Martin Hibdon    public int flags;
156519c218db6109003ca72a35ffe276ed69b0230a4Martin Hibdon
157beaf1e4d14f89e7735ba94a0b2ff92233c6f928fMark Wei    /**
158bbe74aee04f669990e888095b0d6858dc1e17ce1Mark Wei     * Might be null. JSON string.
159bbe74aee04f669990e888095b0d6858dc1e17ce1Mark Wei     *
160bbe74aee04f669990e888095b0d6858dc1e17ce1Mark Wei     * @see AttachmentColumns#PROVIDER_DATA
1617aee8f75f07eb39ecacdf0630d2199211aea5718Mindy Pereira     */
162bbe74aee04f669990e888095b0d6858dc1e17ce1Mark Wei    public String providerData;
1637b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira
1644f24bb48ab2c3e8fbda2af1e1d8fda79e8a458e7Andy Huang    private transient Uri mIdentifierUri;
1654f24bb48ab2c3e8fbda2af1e1d8fda79e8a458e7Andy Huang
1667434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein    /**
1677434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein     * True if this attachment can be downloaded again.
1687434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein     */
1697434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein    private boolean supportsDownloadAgain;
1707434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein
171519c218db6109003ca72a35ffe276ed69b0230a4Martin Hibdon
172bbe74aee04f669990e888095b0d6858dc1e17ce1Mark Wei    public Attachment() {
173bbe74aee04f669990e888095b0d6858dc1e17ce1Mark Wei    }
174bbe74aee04f669990e888095b0d6858dc1e17ce1Mark Wei
1757aee8f75f07eb39ecacdf0630d2199211aea5718Mindy Pereira    public Attachment(Parcel in) {
1767aee8f75f07eb39ecacdf0630d2199211aea5718Mindy Pereira        name = in.readString();
17788fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang        size = in.readInt();
17888fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang        uri = in.readParcelable(null);
1791eb5f96d4e9c459d463d664563c755ec36f958f7Andy Huang        contentType = in.readString();
18088fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang        state = in.readInt();
18188fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang        destination = in.readInt();
18288fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang        downloadedSize = in.readInt();
1831eb5f96d4e9c459d463d664563c755ec36f958f7Andy Huang        contentUri = in.readParcelable(null);
18488fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang        thumbnailUri = in.readParcelable(null);
185d49db8e3c4fff459f4ae3869ea80d083461eda2cPaul Westbrook        previewIntentUri = in.readParcelable(null);
186bbe74aee04f669990e888095b0d6858dc1e17ce1Mark Wei        providerData = in.readString();
1877434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein        supportsDownloadAgain = in.readInt() == 1;
188beaf1e4d14f89e7735ba94a0b2ff92233c6f928fMark Wei        type = in.readInt();
189519c218db6109003ca72a35ffe276ed69b0230a4Martin Hibdon        flags = in.readInt();
1907aee8f75f07eb39ecacdf0630d2199211aea5718Mindy Pereira    }
1917b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira
19288fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang    public Attachment(Cursor cursor) {
19388fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang        if (cursor == null) {
19488fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang            return;
19588fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang        }
19688fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang
1974c7d8b5f38bfa80192d457025b834c975d7d38a3Andrew Sapperstein        name = cursor.getString(cursor.getColumnIndex(AttachmentColumns.NAME));
1984c7d8b5f38bfa80192d457025b834c975d7d38a3Andrew Sapperstein        size = cursor.getInt(cursor.getColumnIndex(AttachmentColumns.SIZE));
1994c7d8b5f38bfa80192d457025b834c975d7d38a3Andrew Sapperstein        uri = Uri.parse(cursor.getString(cursor.getColumnIndex(AttachmentColumns.URI)));
2004c7d8b5f38bfa80192d457025b834c975d7d38a3Andrew Sapperstein        contentType = cursor.getString(cursor.getColumnIndex(AttachmentColumns.CONTENT_TYPE));
2014c7d8b5f38bfa80192d457025b834c975d7d38a3Andrew Sapperstein        state = cursor.getInt(cursor.getColumnIndex(AttachmentColumns.STATE));
2024c7d8b5f38bfa80192d457025b834c975d7d38a3Andrew Sapperstein        destination = cursor.getInt(cursor.getColumnIndex(AttachmentColumns.DESTINATION));
2034c7d8b5f38bfa80192d457025b834c975d7d38a3Andrew Sapperstein        downloadedSize = cursor.getInt(cursor.getColumnIndex(AttachmentColumns.DOWNLOADED_SIZE));
2044c7d8b5f38bfa80192d457025b834c975d7d38a3Andrew Sapperstein        contentUri = parseOptionalUri(
2054c7d8b5f38bfa80192d457025b834c975d7d38a3Andrew Sapperstein                cursor.getString(cursor.getColumnIndex(AttachmentColumns.CONTENT_URI)));
20688fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang        thumbnailUri = parseOptionalUri(
2074c7d8b5f38bfa80192d457025b834c975d7d38a3Andrew Sapperstein                cursor.getString(cursor.getColumnIndex(AttachmentColumns.THUMBNAIL_URI)));
208d49db8e3c4fff459f4ae3869ea80d083461eda2cPaul Westbrook        previewIntentUri = parseOptionalUri(
209d49db8e3c4fff459f4ae3869ea80d083461eda2cPaul Westbrook                cursor.getString(cursor.getColumnIndex(AttachmentColumns.PREVIEW_INTENT_URI)));
210bbe74aee04f669990e888095b0d6858dc1e17ce1Mark Wei        providerData = cursor.getString(cursor.getColumnIndex(AttachmentColumns.PROVIDER_DATA));
2117434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein        supportsDownloadAgain = cursor.getInt(
2127434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein                cursor.getColumnIndex(AttachmentColumns.SUPPORTS_DOWNLOAD_AGAIN)) == 1;
213beaf1e4d14f89e7735ba94a0b2ff92233c6f928fMark Wei        type = cursor.getInt(cursor.getColumnIndex(AttachmentColumns.TYPE));
214519c218db6109003ca72a35ffe276ed69b0230a4Martin Hibdon        flags = cursor.getInt(cursor.getColumnIndex(AttachmentColumns.FLAGS));
215bbe74aee04f669990e888095b0d6858dc1e17ce1Mark Wei    }
21688fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang
217bbe74aee04f669990e888095b0d6858dc1e17ce1Mark Wei    public Attachment(JSONObject srcJson) {
218bbe74aee04f669990e888095b0d6858dc1e17ce1Mark Wei        name = srcJson.optString(AttachmentColumns.NAME, null);
219bbe74aee04f669990e888095b0d6858dc1e17ce1Mark Wei        size = srcJson.optInt(AttachmentColumns.SIZE);
220bbe74aee04f669990e888095b0d6858dc1e17ce1Mark Wei        uri = parseOptionalUri(srcJson, AttachmentColumns.URI);
221bbe74aee04f669990e888095b0d6858dc1e17ce1Mark Wei        contentType = srcJson.optString(AttachmentColumns.CONTENT_TYPE, null);
222bbe74aee04f669990e888095b0d6858dc1e17ce1Mark Wei        state = srcJson.optInt(AttachmentColumns.STATE);
2233ca3bf8538bbabcaf9d86818e25c40f3a9d9b0c9Mark Wei        destination = srcJson.optInt(AttachmentColumns.DESTINATION);
2243ca3bf8538bbabcaf9d86818e25c40f3a9d9b0c9Mark Wei        downloadedSize = srcJson.optInt(AttachmentColumns.DOWNLOADED_SIZE);
2253ca3bf8538bbabcaf9d86818e25c40f3a9d9b0c9Mark Wei        contentUri = parseOptionalUri(srcJson, AttachmentColumns.CONTENT_URI);
2263ca3bf8538bbabcaf9d86818e25c40f3a9d9b0c9Mark Wei        thumbnailUri = parseOptionalUri(srcJson, AttachmentColumns.THUMBNAIL_URI);
2273ca3bf8538bbabcaf9d86818e25c40f3a9d9b0c9Mark Wei        previewIntentUri = parseOptionalUri(srcJson, AttachmentColumns.PREVIEW_INTENT_URI);
228bbe74aee04f669990e888095b0d6858dc1e17ce1Mark Wei        providerData = srcJson.optString(AttachmentColumns.PROVIDER_DATA);
2297434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein        supportsDownloadAgain = srcJson.optBoolean(AttachmentColumns.SUPPORTS_DOWNLOAD_AGAIN, true);
230beaf1e4d14f89e7735ba94a0b2ff92233c6f928fMark Wei        type = srcJson.optInt(AttachmentColumns.TYPE);
231519c218db6109003ca72a35ffe276ed69b0230a4Martin Hibdon        flags = srcJson.optInt(AttachmentColumns.FLAGS);
2327434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein    }
2337434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein
2347434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein    /**
2357434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein     * Constructor for use when creating attachments in eml files.
2367434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein     */
2377434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein    public Attachment(Context context, Part part, Uri emlFileUri, String messageId, String partId) {
2387434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein        try {
2397434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein            // Transfer fields from mime format to provider format
2407434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein            final String contentTypeHeader = MimeUtility.unfoldAndDecode(part.getContentType());
2417434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein            name = MimeUtility.getHeaderParameter(contentTypeHeader, "name");
2427434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein            if (name == null) {
2437434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein                final String contentDisposition =
2447434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein                        MimeUtility.unfoldAndDecode(part.getDisposition());
2457434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein                name = MimeUtility.getHeaderParameter(contentDisposition, "filename");
2467434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein            }
2477434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein
2487434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein            contentType = MimeType.inferMimeType(name, part.getMimeType());
2497434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein            uri = EmlAttachmentProvider.getAttachmentUri(emlFileUri, messageId, partId);
2507434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein            contentUri = uri;
2517434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein            thumbnailUri = uri;
2527434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein            previewIntentUri = null;
2537434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein            state = AttachmentState.SAVED;
2547434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein            providerData = null;
2557434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein            supportsDownloadAgain = false;
2567434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein            destination = AttachmentDestination.CACHE;
257beaf1e4d14f89e7735ba94a0b2ff92233c6f928fMark Wei            type = AttachmentType.STANDARD;
258519c218db6109003ca72a35ffe276ed69b0230a4Martin Hibdon            flags = 0;
2597434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein
2607434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein            // insert attachment into content provider so that we can open the file
2617434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein            final ContentResolver resolver = context.getContentResolver();
2627434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein            resolver.insert(uri, toContentValues());
2637434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein
2647434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein            // save the file in the cache
2657434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein            try {
2667434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein                final InputStream in = part.getBody().getInputStream();
2677434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein                final OutputStream out = resolver.openOutputStream(uri, "rwt");
2687434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein                size = IOUtils.copy(in, out);
2697434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein                downloadedSize = size;
2707434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein                in.close();
2717434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein                out.close();
2727434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein            } catch (FileNotFoundException e) {
2737434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein                LogUtils.e(LOG_TAG, e, "Error in writing attachment to cache");
2747434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein            } catch (IOException e) {
2757434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein                LogUtils.e(LOG_TAG, e, "Error in writing attachment to cache");
2767434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein            }
2777434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein            // perform a second insert to put the updated size and downloaded size values in
2787434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein            resolver.insert(uri, toContentValues());
2797434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein        } catch (MessagingException e) {
2807434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein            LogUtils.e(LOG_TAG, e, "Error parsing eml attachment");
2817434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein        }
2827434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein    }
2837434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein
2847434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein    /**
2857434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein     * Create an attachment from a {@link ContentValues} object.
2867434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein     * The keys should be {@link AttachmentColumns}.
2877434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein     */
2887434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein    public Attachment(ContentValues values) {
2897434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein        name = values.getAsString(AttachmentColumns.NAME);
2907434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein        size = values.getAsInteger(AttachmentColumns.SIZE);
2917434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein        uri = parseOptionalUri(values.getAsString(AttachmentColumns.URI));
2927434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein        contentType = values.getAsString(AttachmentColumns.CONTENT_TYPE);
2937434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein        state = values.getAsInteger(AttachmentColumns.STATE);
2947434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein        destination = values.getAsInteger(AttachmentColumns.DESTINATION);
2957434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein        downloadedSize = values.getAsInteger(AttachmentColumns.DOWNLOADED_SIZE);
2967434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein        contentUri = parseOptionalUri(values.getAsString(AttachmentColumns.CONTENT_URI));
2977434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein        thumbnailUri = parseOptionalUri(values.getAsString(AttachmentColumns.THUMBNAIL_URI));
2987434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein        previewIntentUri =
2997434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein                parseOptionalUri(values.getAsString(AttachmentColumns.PREVIEW_INTENT_URI));
3007434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein        providerData = values.getAsString(AttachmentColumns.PROVIDER_DATA);
3017434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein        supportsDownloadAgain = values.getAsBoolean(AttachmentColumns.SUPPORTS_DOWNLOAD_AGAIN);
302beaf1e4d14f89e7735ba94a0b2ff92233c6f928fMark Wei        type = values.getAsInteger(AttachmentColumns.TYPE);
303519c218db6109003ca72a35ffe276ed69b0230a4Martin Hibdon        flags = values.getAsInteger(AttachmentColumns.FLAGS);
3047434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein    }
3057434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein
3067434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein    /**
3077434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein     * Returns the various attachment fields in a {@link ContentValues} object.
3087434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein     * The keys for each field should be {@link AttachmentColumns}.
3097434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein     */
3107434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein    public ContentValues toContentValues() {
3117434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein        final ContentValues values = new ContentValues(12);
3127434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein
3137434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein        values.put(AttachmentColumns.NAME, name);
3147434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein        values.put(AttachmentColumns.SIZE, size);
3157434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein        values.put(AttachmentColumns.URI, uri.toString());
3167434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein        values.put(AttachmentColumns.CONTENT_TYPE, contentType);
3177434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein        values.put(AttachmentColumns.STATE, state);
3187434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein        values.put(AttachmentColumns.DESTINATION, destination);
3197434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein        values.put(AttachmentColumns.DOWNLOADED_SIZE, downloadedSize);
3207434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein        values.put(AttachmentColumns.CONTENT_URI, contentUri.toString());
3217434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein        values.put(AttachmentColumns.THUMBNAIL_URI, thumbnailUri.toString());
3227434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein        values.put(AttachmentColumns.PREVIEW_INTENT_URI,
3237434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein                previewIntentUri == null ? null : previewIntentUri.toString());
3247434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein        values.put(AttachmentColumns.PROVIDER_DATA, providerData);
3257434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein        values.put(AttachmentColumns.SUPPORTS_DOWNLOAD_AGAIN, supportsDownloadAgain);
326beaf1e4d14f89e7735ba94a0b2ff92233c6f928fMark Wei        values.put(AttachmentColumns.TYPE, type);
327519c218db6109003ca72a35ffe276ed69b0230a4Martin Hibdon        values.put(AttachmentColumns.FLAGS, flags);
3287434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein
3297434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein        return values;
33088fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang    }
33188fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang
332bbe74aee04f669990e888095b0d6858dc1e17ce1Mark Wei    @Override
333bbe74aee04f669990e888095b0d6858dc1e17ce1Mark Wei    public void writeToParcel(Parcel dest, int flags) {
334bbe74aee04f669990e888095b0d6858dc1e17ce1Mark Wei        dest.writeString(name);
335bbe74aee04f669990e888095b0d6858dc1e17ce1Mark Wei        dest.writeInt(size);
336bbe74aee04f669990e888095b0d6858dc1e17ce1Mark Wei        dest.writeParcelable(uri, flags);
337bbe74aee04f669990e888095b0d6858dc1e17ce1Mark Wei        dest.writeString(contentType);
338bbe74aee04f669990e888095b0d6858dc1e17ce1Mark Wei        dest.writeInt(state);
339bbe74aee04f669990e888095b0d6858dc1e17ce1Mark Wei        dest.writeInt(destination);
340bbe74aee04f669990e888095b0d6858dc1e17ce1Mark Wei        dest.writeInt(downloadedSize);
341bbe74aee04f669990e888095b0d6858dc1e17ce1Mark Wei        dest.writeParcelable(contentUri, flags);
342bbe74aee04f669990e888095b0d6858dc1e17ce1Mark Wei        dest.writeParcelable(thumbnailUri, flags);
343bbe74aee04f669990e888095b0d6858dc1e17ce1Mark Wei        dest.writeParcelable(previewIntentUri, flags);
344bbe74aee04f669990e888095b0d6858dc1e17ce1Mark Wei        dest.writeString(providerData);
3457434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein        dest.writeInt(supportsDownloadAgain ? 1 : 0);
346beaf1e4d14f89e7735ba94a0b2ff92233c6f928fMark Wei        dest.writeInt(type);
347519c218db6109003ca72a35ffe276ed69b0230a4Martin Hibdon        dest.writeInt(flags);
348f944e9655562e321aff52fe5f437e1d2fa2950a9Mindy Pereira    }
349f944e9655562e321aff52fe5f437e1d2fa2950a9Mindy Pereira
350bbe74aee04f669990e888095b0d6858dc1e17ce1Mark Wei    public JSONObject toJSON() throws JSONException {
351bbe74aee04f669990e888095b0d6858dc1e17ce1Mark Wei        final JSONObject result = new JSONObject();
352bbe74aee04f669990e888095b0d6858dc1e17ce1Mark Wei
3538117871e95e8b5657e1588c8012d3edfc0204121Mark Wei        result.put(AttachmentColumns.NAME, name);
3548117871e95e8b5657e1588c8012d3edfc0204121Mark Wei        result.put(AttachmentColumns.SIZE, size);
3558117871e95e8b5657e1588c8012d3edfc0204121Mark Wei        result.put(AttachmentColumns.URI, stringify(uri));
3568117871e95e8b5657e1588c8012d3edfc0204121Mark Wei        result.put(AttachmentColumns.CONTENT_TYPE, contentType);
3578117871e95e8b5657e1588c8012d3edfc0204121Mark Wei        result.put(AttachmentColumns.STATE, state);
3588117871e95e8b5657e1588c8012d3edfc0204121Mark Wei        result.put(AttachmentColumns.DESTINATION, destination);
3598117871e95e8b5657e1588c8012d3edfc0204121Mark Wei        result.put(AttachmentColumns.DOWNLOADED_SIZE, downloadedSize);
3608117871e95e8b5657e1588c8012d3edfc0204121Mark Wei        result.put(AttachmentColumns.CONTENT_URI, stringify(contentUri));
3618117871e95e8b5657e1588c8012d3edfc0204121Mark Wei        result.put(AttachmentColumns.THUMBNAIL_URI, stringify(thumbnailUri));
3628117871e95e8b5657e1588c8012d3edfc0204121Mark Wei        result.put(AttachmentColumns.PREVIEW_INTENT_URI, stringify(previewIntentUri));
363bbe74aee04f669990e888095b0d6858dc1e17ce1Mark Wei        result.put(AttachmentColumns.PROVIDER_DATA, providerData);
3647434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein        result.put(AttachmentColumns.SUPPORTS_DOWNLOAD_AGAIN, supportsDownloadAgain);
365beaf1e4d14f89e7735ba94a0b2ff92233c6f928fMark Wei        result.put(AttachmentColumns.TYPE, type);
366519c218db6109003ca72a35ffe276ed69b0230a4Martin Hibdon        result.put(AttachmentColumns.FLAGS, flags);
367bbe74aee04f669990e888095b0d6858dc1e17ce1Mark Wei
368bbe74aee04f669990e888095b0d6858dc1e17ce1Mark Wei        return result;
369bbe74aee04f669990e888095b0d6858dc1e17ce1Mark Wei    }
370bbe74aee04f669990e888095b0d6858dc1e17ce1Mark Wei
371f467d10bb05a8df6ac3c8279f6fda24e89b87482Paul Westbrook    @Override
372f467d10bb05a8df6ac3c8279f6fda24e89b87482Paul Westbrook    public String toString() {
373f467d10bb05a8df6ac3c8279f6fda24e89b87482Paul Westbrook        try {
374b0f4a7da15313c9f1316ab72230bb44cc218ffd5Paul Westbrook            final JSONObject jsonObject = toJSON();
375b0f4a7da15313c9f1316ab72230bb44cc218ffd5Paul Westbrook            // Add some additional fields that are helpful when debugging issues
3763ca3bf8538bbabcaf9d86818e25c40f3a9d9b0c9Mark Wei            jsonObject.put("partId", partId);
3771e46bacc28f8cad65377559c1dfc089443498e8dPaul Westbrook            if (providerData != null) {
3781e46bacc28f8cad65377559c1dfc089443498e8dPaul Westbrook                try {
3791e46bacc28f8cad65377559c1dfc089443498e8dPaul Westbrook                    // pretty print the provider data
3801e46bacc28f8cad65377559c1dfc089443498e8dPaul Westbrook                    jsonObject.put(AttachmentColumns.PROVIDER_DATA, new JSONObject(providerData));
3811e46bacc28f8cad65377559c1dfc089443498e8dPaul Westbrook                } catch (JSONException e) {
3821e46bacc28f8cad65377559c1dfc089443498e8dPaul Westbrook                    LogUtils.e(LOG_TAG, e, "JSONException when adding provider data");
3831e46bacc28f8cad65377559c1dfc089443498e8dPaul Westbrook                }
3848117871e95e8b5657e1588c8012d3edfc0204121Mark Wei            }
3858117871e95e8b5657e1588c8012d3edfc0204121Mark Wei            return jsonObject.toString(4);
386f467d10bb05a8df6ac3c8279f6fda24e89b87482Paul Westbrook        } catch (JSONException e) {
387f467d10bb05a8df6ac3c8279f6fda24e89b87482Paul Westbrook            LogUtils.e(LOG_TAG, e, "JSONException in toString");
388f467d10bb05a8df6ac3c8279f6fda24e89b87482Paul Westbrook            return super.toString();
389f467d10bb05a8df6ac3c8279f6fda24e89b87482Paul Westbrook        }
390f467d10bb05a8df6ac3c8279f6fda24e89b87482Paul Westbrook    }
391f467d10bb05a8df6ac3c8279f6fda24e89b87482Paul Westbrook
3923b965d78774a42358ce6bbdcc43b4c8df130a60eScott Kennedy    private static String stringify(Object object) {
393bbe74aee04f669990e888095b0d6858dc1e17ce1Mark Wei        return object != null ? object.toString() : null;
394bbe74aee04f669990e888095b0d6858dc1e17ce1Mark Wei    }
395bbe74aee04f669990e888095b0d6858dc1e17ce1Mark Wei
396bbe74aee04f669990e888095b0d6858dc1e17ce1Mark Wei    protected static Uri parseOptionalUri(String uriString) {
39788fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang        return uriString == null ? null : Uri.parse(uriString);
39888fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang    }
39988fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang
400bbe74aee04f669990e888095b0d6858dc1e17ce1Mark Wei    protected static Uri parseOptionalUri(JSONObject srcJson, String key) {
401bbe74aee04f669990e888095b0d6858dc1e17ce1Mark Wei        final String uriStr = srcJson.optString(key, null);
402bbe74aee04f669990e888095b0d6858dc1e17ce1Mark Wei        return uriStr == null ? null : Uri.parse(uriStr);
403bbe74aee04f669990e888095b0d6858dc1e17ce1Mark Wei    }
404bbe74aee04f669990e888095b0d6858dc1e17ce1Mark Wei
4057aee8f75f07eb39ecacdf0630d2199211aea5718Mindy Pereira    @Override
4067aee8f75f07eb39ecacdf0630d2199211aea5718Mindy Pereira    public int describeContents() {
4077aee8f75f07eb39ecacdf0630d2199211aea5718Mindy Pereira        return 0;
4087aee8f75f07eb39ecacdf0630d2199211aea5718Mindy Pereira    }
4097b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira
410bbe74aee04f669990e888095b0d6858dc1e17ce1Mark Wei    public boolean isPresentLocally() {
411bbe74aee04f669990e888095b0d6858dc1e17ce1Mark Wei        return state == AttachmentState.SAVED;
4127aee8f75f07eb39ecacdf0630d2199211aea5718Mindy Pereira    }
4137b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira
414bbe74aee04f669990e888095b0d6858dc1e17ce1Mark Wei    public boolean canSave() {
415c30808f28ba0a85ed8495a5e840e137306d2a0f0Mark Wei        return !isSavedToExternal() && !isInstallable() && !MimeType.isBlocked(getContentType());
416bbe74aee04f669990e888095b0d6858dc1e17ce1Mark Wei    }
417f944e9655562e321aff52fe5f437e1d2fa2950a9Mindy Pereira
418bbe74aee04f669990e888095b0d6858dc1e17ce1Mark Wei    public boolean canShare() {
419bbe74aee04f669990e888095b0d6858dc1e17ce1Mark Wei        return isPresentLocally() && contentUri != null;
42088fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang    }
421f944e9655562e321aff52fe5f437e1d2fa2950a9Mindy Pereira
42288fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang    public boolean isDownloading() {
4237bed4bc31a49a2297a38eb9d7b595fba1fa1f849Mark Wei        return state == AttachmentState.DOWNLOADING || state == AttachmentState.PAUSED;
424f944e9655562e321aff52fe5f437e1d2fa2950a9Mindy Pereira    }
425f944e9655562e321aff52fe5f437e1d2fa2950a9Mindy Pereira
42688fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang    public boolean isSavedToExternal() {
42788fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang        return state == AttachmentState.SAVED && destination == AttachmentDestination.EXTERNAL;
428f944e9655562e321aff52fe5f437e1d2fa2950a9Mindy Pereira    }
4294401c9049f0327019b0bfed554bf8ff5cdaa20e2Mindy Pereira
430856200a2abc6a90711f6eb99fc0340dd75ef6e9bMark Wei    public boolean isInstallable() {
4318750066b10f80e2a8080016973b3296d76d18266Mark Wei        return MimeType.isInstallable(getContentType());
432856200a2abc6a90711f6eb99fc0340dd75ef6e9bMark Wei    }
433856200a2abc6a90711f6eb99fc0340dd75ef6e9bMark Wei
4344cb51dbce9635f4bf68a6de88f759e2f86d20325Andrew Sapperstein    public boolean shouldShowProgress() {
4357bed4bc31a49a2297a38eb9d7b595fba1fa1f849Mark Wei        return (state == AttachmentState.DOWNLOADING || state == AttachmentState.PAUSED)
4360eb46cb4c18b91ee272caca7f62f4a15ec2668efMark Wei                && size > 0 && downloadedSize > 0 && downloadedSize <= size;
437d0991f7f0d0882ac58dfdb1f8eb8e2a0abd573fcAndy Huang    }
438d0991f7f0d0882ac58dfdb1f8eb8e2a0abd573fcAndy Huang
439bbe74aee04f669990e888095b0d6858dc1e17ce1Mark Wei    public boolean isDownloadFailed() {
44014977bf661dd6dc4d2a2414d0839e628ebed4d50Andrew Sapperstein        return state == AttachmentState.FAILED;
44114977bf661dd6dc4d2a2414d0839e628ebed4d50Andrew Sapperstein    }
44214977bf661dd6dc4d2a2414d0839e628ebed4d50Andrew Sapperstein
443bbe74aee04f669990e888095b0d6858dc1e17ce1Mark Wei    public boolean isDownloadFinishedOrFailed() {
444bbe74aee04f669990e888095b0d6858dc1e17ce1Mark Wei        return state == AttachmentState.FAILED || state == AttachmentState.SAVED;
445bbe74aee04f669990e888095b0d6858dc1e17ce1Mark Wei    }
446bbe74aee04f669990e888095b0d6858dc1e17ce1Mark Wei
4477434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein    public boolean supportsDownloadAgain() {
4487434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein        return supportsDownloadAgain;
4497434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein    }
4507434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein
451d6318e56adadeff4106e9696b5330239175487b1Andrew Sapperstein    public boolean canPreview() {
452d6318e56adadeff4106e9696b5330239175487b1Andrew Sapperstein        return previewIntentUri != null;
453d6318e56adadeff4106e9696b5330239175487b1Andrew Sapperstein    }
454d6318e56adadeff4106e9696b5330239175487b1Andrew Sapperstein
4554f24bb48ab2c3e8fbda2af1e1d8fda79e8a458e7Andy Huang    /**
456bbe74aee04f669990e888095b0d6858dc1e17ce1Mark Wei     * Returns a stable identifier URI for this attachment. TODO: make the uri
457bbe74aee04f669990e888095b0d6858dc1e17ce1Mark Wei     * field stable, and put provider-specific opaque bits and bobs elsewhere
4584f24bb48ab2c3e8fbda2af1e1d8fda79e8a458e7Andy Huang     */
4594f24bb48ab2c3e8fbda2af1e1d8fda79e8a458e7Andy Huang    public Uri getIdentifierUri() {
46010f8c4f1ca3619e761d4d1f874891f6d9259ac7bMark Wei        if (Utils.isEmpty(mIdentifierUri)) {
4613ca3bf8538bbabcaf9d86818e25c40f3a9d9b0c9Mark Wei            mIdentifierUri = Utils.isEmpty(uri) ?
4623ca3bf8538bbabcaf9d86818e25c40f3a9d9b0c9Mark Wei                    (Utils.isEmpty(contentUri) ? Uri.EMPTY : contentUri)
4633ca3bf8538bbabcaf9d86818e25c40f3a9d9b0c9Mark Wei                    : uri.buildUpon().clearQuery().build();
4644f24bb48ab2c3e8fbda2af1e1d8fda79e8a458e7Andy Huang        }
4654f24bb48ab2c3e8fbda2af1e1d8fda79e8a458e7Andy Huang        return mIdentifierUri;
4664f24bb48ab2c3e8fbda2af1e1d8fda79e8a458e7Andy Huang    }
4674f24bb48ab2c3e8fbda2af1e1d8fda79e8a458e7Andy Huang
4688750066b10f80e2a8080016973b3296d76d18266Mark Wei    public String getContentType() {
4698750066b10f80e2a8080016973b3296d76d18266Mark Wei        if (TextUtils.isEmpty(inferredContentType)) {
4708750066b10f80e2a8080016973b3296d76d18266Mark Wei            inferredContentType = MimeType.inferMimeType(name, contentType);
4718750066b10f80e2a8080016973b3296d76d18266Mark Wei        }
4728750066b10f80e2a8080016973b3296d76d18266Mark Wei        return inferredContentType;
4738750066b10f80e2a8080016973b3296d76d18266Mark Wei    }
47474db99555be46ccf44691805c359839268326d2eAndy Huang
47574db99555be46ccf44691805c359839268326d2eAndy Huang    public Uri getUriForRendition(int rendition) {
47674db99555be46ccf44691805c359839268326d2eAndy Huang        final Uri uri;
47774db99555be46ccf44691805c359839268326d2eAndy Huang        switch (rendition) {
47874db99555be46ccf44691805c359839268326d2eAndy Huang            case AttachmentRendition.BEST:
47974db99555be46ccf44691805c359839268326d2eAndy Huang                uri = contentUri;
48074db99555be46ccf44691805c359839268326d2eAndy Huang                break;
48174db99555be46ccf44691805c359839268326d2eAndy Huang            case AttachmentRendition.SIMPLE:
48274db99555be46ccf44691805c359839268326d2eAndy Huang                uri = thumbnailUri;
48374db99555be46ccf44691805c359839268326d2eAndy Huang                break;
48474db99555be46ccf44691805c359839268326d2eAndy Huang            default:
48574db99555be46ccf44691805c359839268326d2eAndy Huang                throw new IllegalArgumentException("invalid rendition: " + rendition);
48674db99555be46ccf44691805c359839268326d2eAndy Huang        }
48774db99555be46ccf44691805c359839268326d2eAndy Huang        return uri;
48874db99555be46ccf44691805c359839268326d2eAndy Huang    }
4898750066b10f80e2a8080016973b3296d76d18266Mark Wei
4908750066b10f80e2a8080016973b3296d76d18266Mark Wei    public void setContentType(String contentType) {
4918750066b10f80e2a8080016973b3296d76d18266Mark Wei        if (!TextUtils.equals(this.contentType, contentType)) {
4928750066b10f80e2a8080016973b3296d76d18266Mark Wei            this.inferredContentType = null;
4938750066b10f80e2a8080016973b3296d76d18266Mark Wei            this.contentType = contentType;
4948750066b10f80e2a8080016973b3296d76d18266Mark Wei        }
4958750066b10f80e2a8080016973b3296d76d18266Mark Wei    }
4968750066b10f80e2a8080016973b3296d76d18266Mark Wei
4978750066b10f80e2a8080016973b3296d76d18266Mark Wei    public String getName() {
4988750066b10f80e2a8080016973b3296d76d18266Mark Wei        return name;
4998750066b10f80e2a8080016973b3296d76d18266Mark Wei    }
5008750066b10f80e2a8080016973b3296d76d18266Mark Wei
5018750066b10f80e2a8080016973b3296d76d18266Mark Wei    public boolean setName(String name) {
5028750066b10f80e2a8080016973b3296d76d18266Mark Wei        if (!TextUtils.equals(this.name, name)) {
5038750066b10f80e2a8080016973b3296d76d18266Mark Wei            this.inferredContentType = null;
5048750066b10f80e2a8080016973b3296d76d18266Mark Wei            this.name = name;
5058750066b10f80e2a8080016973b3296d76d18266Mark Wei            return true;
5068750066b10f80e2a8080016973b3296d76d18266Mark Wei        }
5078750066b10f80e2a8080016973b3296d76d18266Mark Wei        return false;
5088750066b10f80e2a8080016973b3296d76d18266Mark Wei    }
5098750066b10f80e2a8080016973b3296d76d18266Mark Wei
510bbe74aee04f669990e888095b0d6858dc1e17ce1Mark Wei    /**
511bbe74aee04f669990e888095b0d6858dc1e17ce1Mark Wei     * Sets the attachment state. Side effect: sets downloadedSize
512bbe74aee04f669990e888095b0d6858dc1e17ce1Mark Wei     */
513bbe74aee04f669990e888095b0d6858dc1e17ce1Mark Wei    public void setState(int state) {
514bbe74aee04f669990e888095b0d6858dc1e17ce1Mark Wei        this.state = state;
515bbe74aee04f669990e888095b0d6858dc1e17ce1Mark Wei        if (state == AttachmentState.FAILED || state == AttachmentState.NOT_SAVED) {
516bbe74aee04f669990e888095b0d6858dc1e17ce1Mark Wei            this.downloadedSize = 0;
5178081df46ef5a7794374e41cd1836e778a2da9b31Paul Westbrook        }
5185a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang    }
5195a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang
520bbe74aee04f669990e888095b0d6858dc1e17ce1Mark Wei    @Override
521beaf1e4d14f89e7735ba94a0b2ff92233c6f928fMark Wei    public boolean equals(final Object o) {
522beaf1e4d14f89e7735ba94a0b2ff92233c6f928fMark Wei        if (this == o) {
523bbe74aee04f669990e888095b0d6858dc1e17ce1Mark Wei            return true;
5248081df46ef5a7794374e41cd1836e778a2da9b31Paul Westbrook        }
525beaf1e4d14f89e7735ba94a0b2ff92233c6f928fMark Wei        if (o == null || getClass() != o.getClass()) {
526beaf1e4d14f89e7735ba94a0b2ff92233c6f928fMark Wei            return false;
527beaf1e4d14f89e7735ba94a0b2ff92233c6f928fMark Wei        }
528bbe74aee04f669990e888095b0d6858dc1e17ce1Mark Wei
529beaf1e4d14f89e7735ba94a0b2ff92233c6f928fMark Wei        final Attachment that = (Attachment) o;
530beaf1e4d14f89e7735ba94a0b2ff92233c6f928fMark Wei
531beaf1e4d14f89e7735ba94a0b2ff92233c6f928fMark Wei        if (destination != that.destination) {
532beaf1e4d14f89e7735ba94a0b2ff92233c6f928fMark Wei            return false;
533beaf1e4d14f89e7735ba94a0b2ff92233c6f928fMark Wei        }
534beaf1e4d14f89e7735ba94a0b2ff92233c6f928fMark Wei        if (downloadedSize != that.downloadedSize) {
535beaf1e4d14f89e7735ba94a0b2ff92233c6f928fMark Wei            return false;
536beaf1e4d14f89e7735ba94a0b2ff92233c6f928fMark Wei        }
537beaf1e4d14f89e7735ba94a0b2ff92233c6f928fMark Wei        if (size != that.size) {
538beaf1e4d14f89e7735ba94a0b2ff92233c6f928fMark Wei            return false;
539beaf1e4d14f89e7735ba94a0b2ff92233c6f928fMark Wei        }
540beaf1e4d14f89e7735ba94a0b2ff92233c6f928fMark Wei        if (state != that.state) {
541beaf1e4d14f89e7735ba94a0b2ff92233c6f928fMark Wei            return false;
542beaf1e4d14f89e7735ba94a0b2ff92233c6f928fMark Wei        }
543beaf1e4d14f89e7735ba94a0b2ff92233c6f928fMark Wei        if (supportsDownloadAgain != that.supportsDownloadAgain) {
544beaf1e4d14f89e7735ba94a0b2ff92233c6f928fMark Wei            return false;
545beaf1e4d14f89e7735ba94a0b2ff92233c6f928fMark Wei        }
546beaf1e4d14f89e7735ba94a0b2ff92233c6f928fMark Wei        if (type != that.type) {
547beaf1e4d14f89e7735ba94a0b2ff92233c6f928fMark Wei            return false;
548beaf1e4d14f89e7735ba94a0b2ff92233c6f928fMark Wei        }
549beaf1e4d14f89e7735ba94a0b2ff92233c6f928fMark Wei        if (contentType != null ? !contentType.equals(that.contentType)
550beaf1e4d14f89e7735ba94a0b2ff92233c6f928fMark Wei                : that.contentType != null) {
551beaf1e4d14f89e7735ba94a0b2ff92233c6f928fMark Wei            return false;
552beaf1e4d14f89e7735ba94a0b2ff92233c6f928fMark Wei        }
553beaf1e4d14f89e7735ba94a0b2ff92233c6f928fMark Wei        if (contentUri != null ? !contentUri.equals(that.contentUri) : that.contentUri != null) {
554beaf1e4d14f89e7735ba94a0b2ff92233c6f928fMark Wei            return false;
555beaf1e4d14f89e7735ba94a0b2ff92233c6f928fMark Wei        }
556beaf1e4d14f89e7735ba94a0b2ff92233c6f928fMark Wei        if (name != null ? !name.equals(that.name) : that.name != null) {
557beaf1e4d14f89e7735ba94a0b2ff92233c6f928fMark Wei            return false;
558beaf1e4d14f89e7735ba94a0b2ff92233c6f928fMark Wei        }
559beaf1e4d14f89e7735ba94a0b2ff92233c6f928fMark Wei        if (partId != null ? !partId.equals(that.partId) : that.partId != null) {
560beaf1e4d14f89e7735ba94a0b2ff92233c6f928fMark Wei            return false;
561beaf1e4d14f89e7735ba94a0b2ff92233c6f928fMark Wei        }
562beaf1e4d14f89e7735ba94a0b2ff92233c6f928fMark Wei        if (previewIntentUri != null ? !previewIntentUri.equals(that.previewIntentUri)
563beaf1e4d14f89e7735ba94a0b2ff92233c6f928fMark Wei                : that.previewIntentUri != null) {
564beaf1e4d14f89e7735ba94a0b2ff92233c6f928fMark Wei            return false;
565beaf1e4d14f89e7735ba94a0b2ff92233c6f928fMark Wei        }
566beaf1e4d14f89e7735ba94a0b2ff92233c6f928fMark Wei        if (providerData != null ? !providerData.equals(that.providerData)
567beaf1e4d14f89e7735ba94a0b2ff92233c6f928fMark Wei                : that.providerData != null) {
568beaf1e4d14f89e7735ba94a0b2ff92233c6f928fMark Wei            return false;
569beaf1e4d14f89e7735ba94a0b2ff92233c6f928fMark Wei        }
570beaf1e4d14f89e7735ba94a0b2ff92233c6f928fMark Wei        if (thumbnailUri != null ? !thumbnailUri.equals(that.thumbnailUri)
571beaf1e4d14f89e7735ba94a0b2ff92233c6f928fMark Wei                : that.thumbnailUri != null) {
572beaf1e4d14f89e7735ba94a0b2ff92233c6f928fMark Wei            return false;
573beaf1e4d14f89e7735ba94a0b2ff92233c6f928fMark Wei        }
574beaf1e4d14f89e7735ba94a0b2ff92233c6f928fMark Wei        if (uri != null ? !uri.equals(that.uri) : that.uri != null) {
575bbe74aee04f669990e888095b0d6858dc1e17ce1Mark Wei            return false;
576bbe74aee04f669990e888095b0d6858dc1e17ce1Mark Wei        }
577bbe74aee04f669990e888095b0d6858dc1e17ce1Mark Wei
578beaf1e4d14f89e7735ba94a0b2ff92233c6f928fMark Wei        return true;
5795a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang    }
5805a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang
581bbe74aee04f669990e888095b0d6858dc1e17ce1Mark Wei    @Override
582bbe74aee04f669990e888095b0d6858dc1e17ce1Mark Wei    public int hashCode() {
583beaf1e4d14f89e7735ba94a0b2ff92233c6f928fMark Wei        int result = partId != null ? partId.hashCode() : 0;
584beaf1e4d14f89e7735ba94a0b2ff92233c6f928fMark Wei        result = 31 * result + (name != null ? name.hashCode() : 0);
585beaf1e4d14f89e7735ba94a0b2ff92233c6f928fMark Wei        result = 31 * result + size;
586beaf1e4d14f89e7735ba94a0b2ff92233c6f928fMark Wei        result = 31 * result + (uri != null ? uri.hashCode() : 0);
587beaf1e4d14f89e7735ba94a0b2ff92233c6f928fMark Wei        result = 31 * result + (contentType != null ? contentType.hashCode() : 0);
588beaf1e4d14f89e7735ba94a0b2ff92233c6f928fMark Wei        result = 31 * result + state;
589beaf1e4d14f89e7735ba94a0b2ff92233c6f928fMark Wei        result = 31 * result + destination;
590beaf1e4d14f89e7735ba94a0b2ff92233c6f928fMark Wei        result = 31 * result + downloadedSize;
591beaf1e4d14f89e7735ba94a0b2ff92233c6f928fMark Wei        result = 31 * result + (contentUri != null ? contentUri.hashCode() : 0);
592beaf1e4d14f89e7735ba94a0b2ff92233c6f928fMark Wei        result = 31 * result + (thumbnailUri != null ? thumbnailUri.hashCode() : 0);
593beaf1e4d14f89e7735ba94a0b2ff92233c6f928fMark Wei        result = 31 * result + (previewIntentUri != null ? previewIntentUri.hashCode() : 0);
594beaf1e4d14f89e7735ba94a0b2ff92233c6f928fMark Wei        result = 31 * result + type;
595beaf1e4d14f89e7735ba94a0b2ff92233c6f928fMark Wei        result = 31 * result + (providerData != null ? providerData.hashCode() : 0);
596beaf1e4d14f89e7735ba94a0b2ff92233c6f928fMark Wei        result = 31 * result + (supportsDownloadAgain ? 1 : 0);
597beaf1e4d14f89e7735ba94a0b2ff92233c6f928fMark Wei        return result;
5985a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang    }
5995a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang
600bbe74aee04f669990e888095b0d6858dc1e17ce1Mark Wei    public static String toJSONArray(Collection<? extends Attachment> attachments) {
601bbe74aee04f669990e888095b0d6858dc1e17ce1Mark Wei        if (attachments == null) {
602bbe74aee04f669990e888095b0d6858dc1e17ce1Mark Wei            return null;
603bbe74aee04f669990e888095b0d6858dc1e17ce1Mark Wei        }
6045a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang        final JSONArray result = new JSONArray();
6055a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang        try {
6065a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang            for (Attachment attachment : attachments) {
6075a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang                result.put(attachment.toJSON());
6085a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang            }
6095a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang        } catch (JSONException e) {
6105a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang            throw new IllegalArgumentException(e);
6115a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang        }
6125a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang        return result.toString();
6135a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang    }
6145a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang
6155a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang    public static List<Attachment> fromJSONArray(String jsonArrayStr) {
6165a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang        final List<Attachment> results = Lists.newArrayList();
617bbe74aee04f669990e888095b0d6858dc1e17ce1Mark Wei        if (jsonArrayStr != null) {
618bbe74aee04f669990e888095b0d6858dc1e17ce1Mark Wei            try {
619bbe74aee04f669990e888095b0d6858dc1e17ce1Mark Wei                final JSONArray arr = new JSONArray(jsonArrayStr);
6205a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang
621bbe74aee04f669990e888095b0d6858dc1e17ce1Mark Wei                for (int i = 0; i < arr.length(); i++) {
622bbe74aee04f669990e888095b0d6858dc1e17ce1Mark Wei                    results.add(new Attachment(arr.getJSONObject(i)));
623bbe74aee04f669990e888095b0d6858dc1e17ce1Mark Wei                }
6245a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang
625bbe74aee04f669990e888095b0d6858dc1e17ce1Mark Wei            } catch (JSONException e) {
626bbe74aee04f669990e888095b0d6858dc1e17ce1Mark Wei                throw new IllegalArgumentException(e);
627bbe74aee04f669990e888095b0d6858dc1e17ce1Mark Wei            }
6285a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang        }
6295a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang        return results;
6305a9290731bf565538a9cf91892346c7a6f4da0ecAndy Huang    }
631bbe74aee04f669990e888095b0d6858dc1e17ce1Mark Wei
6323ca3bf8538bbabcaf9d86818e25c40f3a9d9b0c9Mark Wei    private static final String SERVER_ATTACHMENT = "SERVER_ATTACHMENT";
6333ca3bf8538bbabcaf9d86818e25c40f3a9d9b0c9Mark Wei    private static final String LOCAL_FILE = "LOCAL_FILE";
6343ca3bf8538bbabcaf9d86818e25c40f3a9d9b0c9Mark Wei
6353ca3bf8538bbabcaf9d86818e25c40f3a9d9b0c9Mark Wei    public String toJoinedString() {
636479505d71969e26b0785d8e0e1b81108731cf827Mark Wei        return TextUtils.join(UIProvider.ATTACHMENT_INFO_DELIMITER, Lists.newArrayList(
6373ca3bf8538bbabcaf9d86818e25c40f3a9d9b0c9Mark Wei                partId == null ? "" : partId,
638479505d71969e26b0785d8e0e1b81108731cf827Mark Wei                name == null ? ""
639beaf1e4d14f89e7735ba94a0b2ff92233c6f928fMark Wei                        : name.replaceAll("[" + UIProvider.ATTACHMENT_INFO_DELIMITER
640beaf1e4d14f89e7735ba94a0b2ff92233c6f928fMark Wei                                + UIProvider.ATTACHMENT_INFO_SEPARATOR + "]", ""),
6418750066b10f80e2a8080016973b3296d76d18266Mark Wei                getContentType(),
6423ca3bf8538bbabcaf9d86818e25c40f3a9d9b0c9Mark Wei                String.valueOf(size),
6438750066b10f80e2a8080016973b3296d76d18266Mark Wei                getContentType(),
6443ca3bf8538bbabcaf9d86818e25c40f3a9d9b0c9Mark Wei                contentUri != null ? SERVER_ATTACHMENT : LOCAL_FILE,
645beaf1e4d14f89e7735ba94a0b2ff92233c6f928fMark Wei                contentUri != null ? contentUri.toString() : "",
646beaf1e4d14f89e7735ba94a0b2ff92233c6f928fMark Wei                "" /* cachedFileUri */,
647beaf1e4d14f89e7735ba94a0b2ff92233c6f928fMark Wei                String.valueOf(type)));
6483ca3bf8538bbabcaf9d86818e25c40f3a9d9b0c9Mark Wei    }
6493ca3bf8538bbabcaf9d86818e25c40f3a9d9b0c9Mark Wei
650479505d71969e26b0785d8e0e1b81108731cf827Mark Wei    /**
651479505d71969e26b0785d8e0e1b81108731cf827Mark Wei     * For use with {@link UIProvider.ConversationColumns#ATTACHMENT_PREVIEW_STATES}.
652479505d71969e26b0785d8e0e1b81108731cf827Mark Wei     *
653479505d71969e26b0785d8e0e1b81108731cf827Mark Wei     * @param previewStates The packed int describing the states of multiple attachments.
654479505d71969e26b0785d8e0e1b81108731cf827Mark Wei     * @param attachmentIndex The index of the attachment to update.
655479505d71969e26b0785d8e0e1b81108731cf827Mark Wei     * @param rendition The rendition of that attachment to update.
656479505d71969e26b0785d8e0e1b81108731cf827Mark Wei     * @param downloaded Whether that specific rendition is downloaded.
657479505d71969e26b0785d8e0e1b81108731cf827Mark Wei     * @return A packed int describing the updated downloaded states of the multiple attachments.
658479505d71969e26b0785d8e0e1b81108731cf827Mark Wei     */
659479505d71969e26b0785d8e0e1b81108731cf827Mark Wei    public static int updatePreviewStates(int previewStates, int attachmentIndex, int rendition,
660479505d71969e26b0785d8e0e1b81108731cf827Mark Wei            boolean downloaded) {
661479505d71969e26b0785d8e0e1b81108731cf827Mark Wei        // find the bit that describes that specific attachment index and rendition
662479505d71969e26b0785d8e0e1b81108731cf827Mark Wei        int shift = attachmentIndex * 2 + rendition;
663479505d71969e26b0785d8e0e1b81108731cf827Mark Wei        int mask = 1 << shift;
664479505d71969e26b0785d8e0e1b81108731cf827Mark Wei        // update the packed int at that bit
665479505d71969e26b0785d8e0e1b81108731cf827Mark Wei        if (downloaded) {
666479505d71969e26b0785d8e0e1b81108731cf827Mark Wei            // turns that bit into a 1
667479505d71969e26b0785d8e0e1b81108731cf827Mark Wei            return previewStates | mask;
668479505d71969e26b0785d8e0e1b81108731cf827Mark Wei        } else {
669479505d71969e26b0785d8e0e1b81108731cf827Mark Wei            // turns that bit into a 0
670479505d71969e26b0785d8e0e1b81108731cf827Mark Wei            return previewStates & ~mask;
671479505d71969e26b0785d8e0e1b81108731cf827Mark Wei        }
672479505d71969e26b0785d8e0e1b81108731cf827Mark Wei    }
673479505d71969e26b0785d8e0e1b81108731cf827Mark Wei
674479505d71969e26b0785d8e0e1b81108731cf827Mark Wei    /**
675479505d71969e26b0785d8e0e1b81108731cf827Mark Wei     * For use with {@link UIProvider.ConversationColumns#ATTACHMENT_PREVIEW_STATES}.
676479505d71969e26b0785d8e0e1b81108731cf827Mark Wei     *
677479505d71969e26b0785d8e0e1b81108731cf827Mark Wei     * @param previewStates The packed int describing the states of multiple attachments.
678479505d71969e26b0785d8e0e1b81108731cf827Mark Wei     * @param attachmentIndex The index of the attachment.
679479505d71969e26b0785d8e0e1b81108731cf827Mark Wei     * @param rendition The rendition of the attachment.
680479505d71969e26b0785d8e0e1b81108731cf827Mark Wei     * @return The downloaded state of that particular rendition of that particular attachment.
681479505d71969e26b0785d8e0e1b81108731cf827Mark Wei     */
682479505d71969e26b0785d8e0e1b81108731cf827Mark Wei    public static boolean getPreviewState(int previewStates, int attachmentIndex, int rendition) {
683479505d71969e26b0785d8e0e1b81108731cf827Mark Wei        // find the bit that describes that specific attachment index
684479505d71969e26b0785d8e0e1b81108731cf827Mark Wei        int shift = attachmentIndex * 2;
685479505d71969e26b0785d8e0e1b81108731cf827Mark Wei        int mask = 1 << shift;
686479505d71969e26b0785d8e0e1b81108731cf827Mark Wei
687479505d71969e26b0785d8e0e1b81108731cf827Mark Wei        if (rendition == AttachmentRendition.SIMPLE) {
688479505d71969e26b0785d8e0e1b81108731cf827Mark Wei            // implicit shift of 0 finds the SIMPLE rendition bit
689479505d71969e26b0785d8e0e1b81108731cf827Mark Wei            return (previewStates & mask) != 0;
690479505d71969e26b0785d8e0e1b81108731cf827Mark Wei        } else if (rendition == AttachmentRendition.BEST) {
691479505d71969e26b0785d8e0e1b81108731cf827Mark Wei            // shift of 1 finds the BEST rendition bit
692479505d71969e26b0785d8e0e1b81108731cf827Mark Wei            return (previewStates & (mask << 1)) != 0;
693479505d71969e26b0785d8e0e1b81108731cf827Mark Wei        } else {
694479505d71969e26b0785d8e0e1b81108731cf827Mark Wei            return false;
695479505d71969e26b0785d8e0e1b81108731cf827Mark Wei        }
696479505d71969e26b0785d8e0e1b81108731cf827Mark Wei    }
697479505d71969e26b0785d8e0e1b81108731cf827Mark Wei
698bbe74aee04f669990e888095b0d6858dc1e17ce1Mark Wei    public static final Creator<Attachment> CREATOR = new Creator<Attachment>() {
699bbe74aee04f669990e888095b0d6858dc1e17ce1Mark Wei            @Override
700bbe74aee04f669990e888095b0d6858dc1e17ce1Mark Wei        public Attachment createFromParcel(Parcel source) {
701bbe74aee04f669990e888095b0d6858dc1e17ce1Mark Wei            return new Attachment(source);
702bbe74aee04f669990e888095b0d6858dc1e17ce1Mark Wei        }
703bbe74aee04f669990e888095b0d6858dc1e17ce1Mark Wei
704bbe74aee04f669990e888095b0d6858dc1e17ce1Mark Wei            @Override
705bbe74aee04f669990e888095b0d6858dc1e17ce1Mark Wei        public Attachment[] newArray(int size) {
706bbe74aee04f669990e888095b0d6858dc1e17ce1Mark Wei            return new Attachment[size];
707bbe74aee04f669990e888095b0d6858dc1e17ce1Mark Wei        }
708bbe74aee04f669990e888095b0d6858dc1e17ce1Mark Wei    };
7097b56a61174eeb202eea468b7f68b79729737ded2Mindy Pereira}
710