| /** |
| * Copyright (c) 2011, Google Inc. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package com.android.mail.providers; |
| |
| import android.database.Cursor; |
| import android.net.Uri; |
| import android.os.Parcel; |
| import android.os.Parcelable; |
| import android.text.TextUtils; |
| |
| import com.android.mail.providers.UIProvider.AttachmentColumns; |
| import com.android.mail.providers.UIProvider.AttachmentDestination; |
| import com.android.mail.providers.UIProvider.AttachmentState; |
| import com.android.mail.utils.LogTag; |
| import com.android.mail.utils.LogUtils; |
| import com.google.common.collect.Lists; |
| |
| import org.json.JSONArray; |
| import org.json.JSONException; |
| import org.json.JSONObject; |
| |
| import java.util.Collection; |
| import java.util.List; |
| |
| public class Attachment implements Parcelable { |
| public static final int SERVER_ATTACHMENT = 0; |
| /** Extras are "<path>". */ |
| public static final int LOCAL_FILE = 1; |
| |
| public static final String LOG_TAG = LogTag.getLogTag(); |
| |
| /** |
| * Attachment file name. See {@link AttachmentColumns#NAME}. |
| */ |
| public String name; |
| |
| /** |
| * Attachment size in bytes. See {@link AttachmentColumns#SIZE}. |
| */ |
| public int size; |
| |
| /** |
| * The provider-generated URI for this Attachment. Must be globally unique. For local |
| * attachments generated by the Compose UI prior to send/save, this field will be null. |
| * |
| *@see AttachmentColumns#URI |
| */ |
| public Uri uri; |
| |
| /** |
| * MIME type of the file. |
| * |
| * @see AttachmentColumns#CONTENT_TYPE |
| */ |
| public String contentType; |
| |
| /** |
| * @see AttachmentColumns#STATE |
| */ |
| public int state; |
| |
| /** |
| * @see AttachmentColumns#DESTINATION |
| */ |
| public int destination; |
| |
| /** |
| * @see AttachmentColumns#DOWNLOADED_SIZE |
| */ |
| public int downloadedSize; |
| |
| /** |
| * @see AttachmentColumns#CONTENT_URI |
| */ |
| public Uri contentUri; |
| |
| /** |
| * Might be null. |
| * |
| * @see AttachmentColumns#THUMBNAIL_URI |
| */ |
| public Uri thumbnailUri; |
| |
| /** |
| * Might be null. |
| * |
| * @see AttachmentColumns# PREVIEW_INTENT_URI |
| */ |
| public Uri previewIntentUri; |
| |
| /** |
| * Part id of the attachment. |
| */ |
| @Deprecated |
| // partId is provider implementation specific. providers must uniquely identify Attachments |
| // by uri. |
| public String partId; |
| |
| @Deprecated |
| // this is a local file iff the provider 'uri' field is null. |
| public int origin; |
| |
| /** |
| * Attachment origin info. |
| * TODO: do we want this? Or location? |
| */ |
| @Deprecated |
| public String originExtras; |
| |
| public Attachment(Parcel in) { |
| name = in.readString(); |
| size = in.readInt(); |
| uri = in.readParcelable(null); |
| contentType = in.readString(); |
| state = in.readInt(); |
| destination = in.readInt(); |
| downloadedSize = in.readInt(); |
| contentUri = in.readParcelable(null); |
| thumbnailUri = in.readParcelable(null); |
| previewIntentUri = in.readParcelable(null); |
| partId = in.readString(); |
| origin = in.readInt(); |
| originExtras = in.readString(); |
| } |
| |
| public Attachment() { |
| } |
| |
| public Attachment(Cursor cursor) { |
| if (cursor == null) { |
| return; |
| } |
| |
| name = cursor.getString(cursor.getColumnIndex(AttachmentColumns.NAME)); |
| size = cursor.getInt(cursor.getColumnIndex(AttachmentColumns.SIZE)); |
| uri = Uri.parse(cursor.getString(cursor.getColumnIndex(AttachmentColumns.URI))); |
| contentType = cursor.getString(cursor.getColumnIndex(AttachmentColumns.CONTENT_TYPE)); |
| state = cursor.getInt(cursor.getColumnIndex(AttachmentColumns.STATE)); |
| destination = cursor.getInt(cursor.getColumnIndex(AttachmentColumns.DESTINATION)); |
| downloadedSize = cursor.getInt(cursor.getColumnIndex(AttachmentColumns.DOWNLOADED_SIZE)); |
| contentUri = parseOptionalUri( |
| cursor.getString(cursor.getColumnIndex(AttachmentColumns.CONTENT_URI))); |
| thumbnailUri = parseOptionalUri( |
| cursor.getString(cursor.getColumnIndex(AttachmentColumns.THUMBNAIL_URI))); |
| previewIntentUri = parseOptionalUri( |
| cursor.getString(cursor.getColumnIndex(AttachmentColumns.PREVIEW_INTENT_URI))); |
| |
| // TODO: ensure that local files attached to a draft have sane values, like SAVED/EXTERNAL |
| // and that contentUri is populated |
| } |
| |
| @Deprecated |
| public Attachment(String attachmentString) { |
| String[] attachmentValues = TextUtils.split(attachmentString, "\\|"); |
| if (attachmentValues != null) { |
| partId = attachmentValues[0]; |
| name = attachmentValues[1]; |
| contentType = attachmentValues[2]; |
| try { |
| size = Integer.parseInt(attachmentValues[3]); |
| } catch (NumberFormatException e) { |
| size = 0; |
| } |
| contentType = attachmentValues[4]; |
| origin = Integer.parseInt(attachmentValues[5]); |
| contentUri = parseOptionalUri(attachmentValues[6]); |
| originExtras = attachmentValues[7]; |
| } |
| } |
| |
| @Deprecated |
| public String toJoinedString() { |
| // FIXME: contentType is read/written twice |
| return TextUtils.join("|", Lists.newArrayList(partId == null ? "" : partId, |
| name == null ? "" : name.replaceAll("[|\n]", ""), contentType, size, contentType, |
| contentUri != null ? LOCAL_FILE : SERVER_ATTACHMENT, contentUri, |
| originExtras == null ? "" : originExtras, "")); |
| } |
| |
| @Override |
| public String toString() { |
| try { |
| return toJSON().toString(); |
| } catch (JSONException e) { |
| LogUtils.e(LOG_TAG, e, "JSONException in toString"); |
| return super.toString(); |
| } |
| } |
| |
| private static Uri parseOptionalUri(String uriString) { |
| return uriString == null ? null : Uri.parse(uriString); |
| } |
| |
| @Override |
| public int describeContents() { |
| return 0; |
| } |
| |
| @Override |
| public void writeToParcel(Parcel dest, int flags) { |
| dest.writeString(name); |
| dest.writeInt(size); |
| dest.writeParcelable(uri, flags); |
| dest.writeString(contentType); |
| dest.writeInt(state); |
| dest.writeInt(destination); |
| dest.writeInt(downloadedSize); |
| dest.writeParcelable(contentUri, flags); |
| dest.writeParcelable(thumbnailUri, flags); |
| dest.writeParcelable(previewIntentUri, flags); |
| dest.writeString(partId); |
| dest.writeInt(origin); |
| dest.writeString(originExtras); |
| } |
| |
| public static final Creator<Attachment> CREATOR = new Creator<Attachment>() { |
| @Override |
| public Attachment createFromParcel(Parcel source) { |
| return new Attachment(source); |
| } |
| |
| @Override |
| public Attachment[] newArray(int size) { |
| return new Attachment[size]; |
| } |
| }; |
| |
| public boolean isImage() { |
| return !TextUtils.isEmpty(contentType) ? contentType.startsWith("image/") : false; |
| } |
| |
| public boolean isDownloading() { |
| return state == AttachmentState.DOWNLOADING; |
| } |
| |
| public boolean isPresentLocally() { |
| return state == AttachmentState.SAVED || origin == LOCAL_FILE; |
| } |
| |
| public boolean isSavedToExternal() { |
| return state == AttachmentState.SAVED && destination == AttachmentDestination.EXTERNAL; |
| } |
| |
| public boolean canSave() { |
| return origin != LOCAL_FILE && state != AttachmentState.DOWNLOADING && |
| !isSavedToExternal(); |
| } |
| |
| public boolean shouldShowProgress() { |
| return state == AttachmentState.DOWNLOADING |
| && size > 0 && downloadedSize > 0 && downloadedSize < size; |
| } |
| |
| public boolean downloadFailed() { |
| return state == AttachmentState.FAILED; |
| } |
| |
| public boolean canPreview() { |
| return previewIntentUri != null; |
| } |
| |
| // Methods to support JSON [de-]serialization of Attachment data |
| // TODO: add support for origin/originExtras (and possibly partId?) or fold those fields into |
| // other fields so Compose View can use JSON objects |
| |
| public JSONObject toJSON() throws JSONException { |
| return toJSON(name, size, uri, contentUri, contentType); |
| } |
| |
| public static JSONObject toJSON(String name, int size, Uri uri, Uri contentUri, |
| String contentType) throws JSONException { |
| final JSONObject result = new JSONObject(); |
| |
| result.putOpt(AttachmentColumns.NAME, name); |
| result.putOpt(AttachmentColumns.SIZE, size); |
| if (uri != null) { |
| result.putOpt(AttachmentColumns.URI, uri.toString()); |
| } |
| if (contentUri != null) { |
| result.putOpt(AttachmentColumns.CONTENT_URI, contentUri.toString()); |
| } |
| result.putOpt(AttachmentColumns.CONTENT_TYPE, contentType); |
| |
| return result; |
| } |
| |
| public Attachment(JSONObject srcJson) { |
| name = srcJson.optString(AttachmentColumns.NAME, null); |
| size = srcJson.optInt(AttachmentColumns.SIZE); |
| uri = parseOptionalUri(srcJson, AttachmentColumns.URI); |
| contentUri = parseOptionalUri(srcJson, AttachmentColumns.CONTENT_URI); |
| contentType = srcJson.optString(AttachmentColumns.CONTENT_TYPE, null); |
| } |
| |
| private static Uri parseOptionalUri(JSONObject srcJson, String key) { |
| final String uriStr = srcJson.optString(key, null); |
| return uriStr == null ? null : Uri.parse(uriStr); |
| } |
| |
| public static String toJSONArray(Collection<Attachment> attachments) { |
| final JSONArray result = new JSONArray(); |
| try { |
| for (Attachment attachment : attachments) { |
| result.put(attachment.toJSON()); |
| } |
| } catch (JSONException e) { |
| throw new IllegalArgumentException(e); |
| } |
| return result.toString(); |
| } |
| |
| public static List<Attachment> fromJSONArray(String jsonArrayStr) { |
| final List<Attachment> results = Lists.newArrayList(); |
| try { |
| final JSONArray arr = new JSONArray(jsonArrayStr); |
| |
| for (int i = 0; i < arr.length(); i++) { |
| results.add(new Attachment(arr.getJSONObject(i))); |
| } |
| |
| } catch (JSONException e) { |
| throw new IllegalArgumentException(e); |
| } |
| return results; |
| } |
| } |