summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Android.mk3
-rw-r--r--res/layout/compose.xml4
-rw-r--r--res/values/strings.xml27
-rw-r--r--src/com/android/email/compose/AttachmentComposeView.java70
-rw-r--r--src/com/android/email/compose/AttachmentsView.java143
-rw-r--r--src/com/android/email/compose/ComposeActivity.java14
-rw-r--r--src/com/android/email/providers/protos/Attachment.java33
-rw-r--r--src/com/android/email/providers/protos/exchange/ExchangeAttachment.java78
-rw-r--r--src/com/android/email/providers/protos/exchange/README1
-rw-r--r--src/com/android/email/providers/protos/longshadow/README1
-rw-r--r--src/com/android/email/providers/protos/mock/MockAttachment.java87
-rw-r--r--src/com/android/email/utils/AttachmentUtils.java28
-rw-r--r--src/com/android/email/utils/LogUtils.java374
-rw-r--r--src/com/android/email/utils/MimeType.java173
-rw-r--r--src/com/android/email/utils/README1
-rw-r--r--src/com/android/email/utils/Utils.java24
16 files changed, 1055 insertions, 6 deletions
diff --git a/Android.mk b/Android.mk
index a9a69b700..34d639480 100644
--- a/Android.mk
+++ b/Android.mk
@@ -11,7 +11,8 @@ include $(CLEAR_VARS)
src_dirs := src
LOCAL_PACKAGE_NAME := UnifiedEmail
-LOCAL_STATIC_JAVA_LIBRARIES = android-common-chips
+LOCAL_STATIC_JAVA_LIBRARIES := android-common-chips
+LOCAL_STATIC_JAVA_LIBRARIES += guava
LOCAL_SDK_VERSION := 14
diff --git a/res/layout/compose.xml b/res/layout/compose.xml
index 5781b6373..ea870a315 100644
--- a/res/layout/compose.xml
+++ b/res/layout/compose.xml
@@ -47,14 +47,14 @@
</LinearLayout>
<!-- Attachments -->
- <!--<com.google.android.gm.AttachmentsView android:id="@+id/attachments"
+ <com.android.email.compose.AttachmentsView android:id="@+id/attachments"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:orientation="vertical"
android:paddingTop="2dip"
android:paddingRight="5dip"
android:paddingBottom="0dip"
- android:paddingLeft="5dip" />-->
+ android:paddingLeft="5dip" />
<!-- Body -->
<include layout="@layout/compose_body"/>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index ae1894060..11a488259 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -56,6 +56,33 @@
<!-- Menu item that displays the help page for Gmail. -->
<string name="help_and_info">Help</string>
+ <!-- Attachments -->
+ <!-- Size unit, displayed in a button next to an attachment [CHAR LIMIT=5]-->
+ <string name="bytes">B</string>
+ <!-- Size unit, displayed in a button next to an attachment [CHAR LIMIT=5] -->
+ <string name="kilobytes">KB</string>
+ <!-- Size unit, displayed in a button next to an attachment [CHAR LIMIT=5]-->
+ <string name="megabytes">MB</string>
+ <!-- Attachment description for image files [CHAR LIMIT=30] -->
+ <string name="attachment_image">Image</string>
+ <!-- Attachment description for video files [CHAR LIMIT=30] -->
+ <string name="attachment_video">Video</string>
+ <!-- Attachment description for audio files [CHAR LIMIT=30] -->
+ <string name="attachment_audio">Audio</string>
+ <!-- Attachment description for text files [CHAR LIMIT=30] -->
+ <string name="attachment_text">Text</string>
+ <!-- Attachment description for .doc files [CHAR LIMIT=30] -->
+ <string name="attachment_application_msword">Document</string>
+ <!-- Attachment description for .ppt files [CHAR LIMIT=30] -->
+ <string name="attachment_application_vnd_ms_powerpoint">Presentation</string>
+ <!-- Attachment description for .pdf files [CHAR LIMIT=30] -->
+ <string name="attachment_application_vnd_ms_excel">Spreadsheet</string>
+ <!-- Attachment description for .pdf files [CHAR LIMIT=30] -->
+ <string name="attachment_application_pdf">PDF</string>
+ <!-- Attachment description for unknown files [CHAR LIMIT=30]-->
+ <string name="attachment_unknown"><xliff:g id="attachmentExtension">%s</xliff:g> File</string>
+
+
<!-- Webview Context Menu Strings -->
<!-- Title of dialog for choosing which activity to share a link with. [CHAR LIMIT=50]-->
<string name="choosertitle_sharevia">Share via</string>
diff --git a/src/com/android/email/compose/AttachmentComposeView.java b/src/com/android/email/compose/AttachmentComposeView.java
new file mode 100644
index 000000000..a376cd996
--- /dev/null
+++ b/src/com/android/email/compose/AttachmentComposeView.java
@@ -0,0 +1,70 @@
+/**
+ * Copyright (c) 2007, 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.email.compose;
+
+import android.content.Context;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import com.android.email.providers.protos.Attachment;
+import com.android.email.R;
+import com.android.email.utils.AttachmentUtils;
+import com.android.email.utils.Utils;
+import com.android.email.utils.LogUtils;
+
+/**
+ * This view is used in the ComposeActivity to display an attachment along with its name/size
+ * and a Remove button.
+ */
+class AttachmentComposeView extends LinearLayout {
+ private final long mSize;
+ private final String mFilename;
+
+ public AttachmentComposeView(Context c, Attachment attachment) {
+ super(c);
+ mFilename = attachment.getName();
+ mSize = attachment.getSize();
+
+ LogUtils.d(Utils.LOG_TAG, ">>>>> Attachment uri: %s", attachment.getOriginExtras());
+ LogUtils.d(Utils.LOG_TAG, ">>>>> type: %s", attachment.getContentType());
+ LogUtils.d(Utils.LOG_TAG, ">>>>> name: %s", mFilename);
+ LogUtils.d(Utils.LOG_TAG, ">>>>> size: %d", mSize);
+
+ LayoutInflater factory = LayoutInflater.from(getContext());
+
+ factory.inflate(R.layout.attachment, this);
+ populateAttachmentData(c);
+ }
+
+ public void addDeleteListener(OnClickListener clickListener) {
+ ImageView deleteButton = (ImageView) findViewById(R.id.remove_attachment);
+ deleteButton.setOnClickListener(clickListener);
+ }
+
+ private void populateAttachmentData(Context context) {
+ ((TextView) findViewById(R.id.attachment_name)).setText(mFilename);
+
+ if (mSize != 0) {
+ ((TextView) findViewById(R.id.attachment_size)).
+ setText(AttachmentUtils.convertToHumanReadableSize(context, mSize));
+ } else {
+ ((TextView) findViewById(R.id.attachment_size)).setVisibility(View.GONE);
+ }
+ }
+}
diff --git a/src/com/android/email/compose/AttachmentsView.java b/src/com/android/email/compose/AttachmentsView.java
new file mode 100644
index 000000000..926598416
--- /dev/null
+++ b/src/com/android/email/compose/AttachmentsView.java
@@ -0,0 +1,143 @@
+/**
+ * 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.email.compose;
+
+import com.android.email.providers.protos.Attachment;
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.collect.Lists;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.LinearLayout;
+
+import java.util.ArrayList;
+
+/*
+ * View for displaying attachments in the compose screen.
+ */
+class AttachmentsView extends LinearLayout {
+ private ArrayList<Attachment> mAttachments;
+ private AttachmentChangesListener mChangeListener;
+
+ public AttachmentsView(Context context) {
+ this(context, null);
+ }
+
+ public AttachmentsView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ mAttachments = Lists.newArrayList();
+ }
+
+ /**
+ * Set a listener for changes to the attachments.
+ * @param listener
+ */
+ public void setAttachmentChangesListener(AttachmentChangesListener listener) {
+ mChangeListener = listener;
+ }
+
+ /**
+ * Add an attachment and update the ui accordingly.
+ * @param attachment
+ */
+ public void addAttachment(final Attachment attachment) {
+ if (!isShown()) {
+ setVisibility(View.VISIBLE);
+ }
+ mAttachments.add(attachment);
+
+ final AttachmentComposeView attachmentView =
+ new AttachmentComposeView(getContext(), attachment);
+
+ attachmentView.addDeleteListener(new OnClickListener() {
+ public void onClick(View v) {
+ deleteAttachment(attachmentView, attachment);
+ }
+ });
+
+
+ addView(attachmentView, new LinearLayout.LayoutParams(
+ LinearLayout.LayoutParams.MATCH_PARENT,
+ LinearLayout.LayoutParams.MATCH_PARENT));
+
+ if (mChangeListener != null) {
+ mChangeListener.onAttachmentAdded();
+ }
+ }
+
+ @VisibleForTesting
+ protected void deleteAttachment(final AttachmentComposeView attachmentView,
+ final Attachment attachment) {
+ mAttachments.remove(attachment);
+ removeView(attachmentView);
+ if (mChangeListener != null) {
+ mChangeListener.onAttachmentDeleted();
+ }
+ if (mAttachments.size() == 0) {
+ setVisibility(View.GONE);
+ }
+ }
+
+ /**
+ * Get all attachments being managed by this view.
+ * @return attachments.
+ */
+ public ArrayList<Attachment> getAttachments() {
+ return mAttachments;
+ }
+
+ /**
+ * Delete all attachments being managed by this view.
+ */
+ public void deleteAllAttachments() {
+ mAttachments.clear();
+ removeAllViews();
+ }
+
+ /**
+ * See if all the attachments in this view are synced.
+ */
+ public boolean areAttachmentsSynced() {
+ for (Attachment a : mAttachments) {
+ if (a.isSynced()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Get the total size of all attachments currently in this view.
+ */
+ public int getTotalAttachmentsSize() {
+ int totalSize = 0;
+ for (Attachment attachment : mAttachments) {
+ totalSize += attachment.getSize();
+ }
+ return totalSize;
+ }
+
+ /**
+ * Interface to implement to be notified about changes to the attachments.
+ * @author mindyp@google.com
+ *
+ */
+ public interface AttachmentChangesListener {
+ public void onAttachmentDeleted();
+ public void onAttachmentAdded();
+ }
+}
diff --git a/src/com/android/email/compose/ComposeActivity.java b/src/com/android/email/compose/ComposeActivity.java
index c5edd4d55..31d842169 100644
--- a/src/com/android/email/compose/ComposeActivity.java
+++ b/src/com/android/email/compose/ComposeActivity.java
@@ -27,12 +27,17 @@ import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
+
+import com.android.email.providers.protos.Attachment;
+import com.android.email.providers.protos.mock.MockAttachment;
import com.android.email.R;
+import com.android.email.utils.MimeType;
public class ComposeActivity extends Activity implements OnClickListener {
private Button mCcBccButton;
private CcBccView mCcBccView;
+ private AttachmentsView mAttachmentsView;
@Override
public void onCreate(Bundle savedInstanceState) {
@@ -43,6 +48,7 @@ public class ComposeActivity extends Activity implements OnClickListener {
mCcBccButton.setOnClickListener(this);
}
mCcBccView = (CcBccView) findViewById(R.id.cc_bcc_wrapper);
+ mAttachmentsView = (AttachmentsView)findViewById(R.id.attachments);
}
@Override
@@ -71,6 +77,14 @@ public class ComposeActivity extends Activity implements OnClickListener {
int id = item.getItemId();
boolean handled = false;
switch (id) {
+ case R.id.add_attachment:
+ MockAttachment attachment = new MockAttachment();
+ attachment.partId = "0";
+ attachment.name = "testattachment.png";
+ attachment.contentType = MimeType.inferMimeType(attachment.name, null);
+ attachment.originExtras = "";
+ mAttachmentsView.addAttachment(attachment);
+ break;
case R.id.add_cc:
case R.id.add_bcc:
mCcBccView.show();
diff --git a/src/com/android/email/providers/protos/Attachment.java b/src/com/android/email/providers/protos/Attachment.java
new file mode 100644
index 000000000..6a2073e00
--- /dev/null
+++ b/src/com/android/email/providers/protos/Attachment.java
@@ -0,0 +1,33 @@
+/**
+ * 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.email.providers.protos;
+
+public interface Attachment {
+
+ String getName();
+
+ long getSize();
+
+ String getOriginExtras();
+
+ String getContentType();
+
+ Object getOrigin();
+
+ String getPartId();
+
+ boolean isSynced();
+}
diff --git a/src/com/android/email/providers/protos/exchange/ExchangeAttachment.java b/src/com/android/email/providers/protos/exchange/ExchangeAttachment.java
new file mode 100644
index 000000000..d4ccf1b83
--- /dev/null
+++ b/src/com/android/email/providers/protos/exchange/ExchangeAttachment.java
@@ -0,0 +1,78 @@
+/**
+ * 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.email.providers.protos.exchange;
+
+import com.android.email.providers.protos.Attachment;
+
+import java.io.Serializable;
+
+public class ExchangeAttachment implements Serializable, Attachment {
+ private static final long serialVersionUID = 1L;
+
+ public String mFileName;
+ public String mMimeType;
+ public long mSize;
+ public String mContentId;
+ public String mContentUri;
+ public long mMessageKey;
+ public String mLocation;
+ public String mEncoding;
+ public String mContent; // Not currently used
+ public int mFlags;
+ public byte[] mContentBytes;
+ public long mAccountKey;
+
+
+ @Override
+ public String getName() {
+ return mFileName;
+ }
+
+ @Override
+ public long getSize() {
+ return mSize;
+ }
+
+ @Override
+ public String getOriginExtras() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public String getContentType() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public Object getOrigin() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public String getPartId() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public boolean isSynced() {
+ // TODO Auto-generated method stub
+ return false;
+ }
+}
diff --git a/src/com/android/email/providers/protos/exchange/README b/src/com/android/email/providers/protos/exchange/README
deleted file mode 100644
index a3fcb7533..000000000
--- a/src/com/android/email/providers/protos/exchange/README
+++ /dev/null
@@ -1 +0,0 @@
-Unified email directories \ No newline at end of file
diff --git a/src/com/android/email/providers/protos/longshadow/README b/src/com/android/email/providers/protos/longshadow/README
deleted file mode 100644
index a3fcb7533..000000000
--- a/src/com/android/email/providers/protos/longshadow/README
+++ /dev/null
@@ -1 +0,0 @@
-Unified email directories \ No newline at end of file
diff --git a/src/com/android/email/providers/protos/mock/MockAttachment.java b/src/com/android/email/providers/protos/mock/MockAttachment.java
new file mode 100644
index 000000000..3a884af56
--- /dev/null
+++ b/src/com/android/email/providers/protos/mock/MockAttachment.java
@@ -0,0 +1,87 @@
+/**
+ * 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.email.providers.protos.mock;
+
+import com.android.email.providers.protos.Attachment;
+
+import java.io.Serializable;
+
+
+
+public class MockAttachment implements Serializable, Attachment {
+
+ private static final long serialVersionUID = 1L;
+
+ /** Identifies the attachment uniquely when combined wih a message id.*/
+ public String partId;
+
+ /** The intended filename of the attachment.*/
+ public String name;
+
+ /** The native content type.*/
+ public String contentType;
+
+ /** The size of the attachment in its native form.*/
+ public int size;
+
+ /**
+ * The content type of the simple version of the attachment. Blank if no simple version is
+ * available.
+ */
+ public String simpleContentType;
+
+ public String originExtras;
+
+ public String cachedContent;
+
+
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public long getSize() {
+ return size;
+ }
+
+ @Override
+ public String getOriginExtras() {
+ return originExtras;
+ }
+
+ @Override
+ public String getContentType() {
+ return contentType;
+ }
+
+ @Override
+ public Object getOrigin() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public String getPartId() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public boolean isSynced() {
+ return true;
+ }
+} \ No newline at end of file
diff --git a/src/com/android/email/utils/AttachmentUtils.java b/src/com/android/email/utils/AttachmentUtils.java
new file mode 100644
index 000000000..2e9a03a11
--- /dev/null
+++ b/src/com/android/email/utils/AttachmentUtils.java
@@ -0,0 +1,28 @@
+package com.android.email.utils;
+
+import android.content.Context;
+
+import com.android.email.R;
+
+import java.text.DecimalFormat;
+
+public class AttachmentUtils {
+ private static final int KILO = 1024;
+ private static final int MEGA = KILO * KILO;
+
+ /**
+ * @return A string suitable for display in bytes, kilobytes or megabytes
+ * depending on its size.
+ */
+ public static String convertToHumanReadableSize(Context context, long size) {
+ if (size < KILO) {
+ return size + context.getString(R.string.bytes);
+ } else if (size < MEGA) {
+ return (size / KILO) + context.getString(R.string.kilobytes);
+ } else {
+ DecimalFormat onePlace = new DecimalFormat("0.#");
+ return onePlace.format((float) size / (float) MEGA)
+ + context.getString(R.string.megabytes);
+ }
+ }
+}
diff --git a/src/com/android/email/utils/LogUtils.java b/src/com/android/email/utils/LogUtils.java
new file mode 100644
index 000000000..8c065a0e3
--- /dev/null
+++ b/src/com/android/email/utils/LogUtils.java
@@ -0,0 +1,374 @@
+/**
+ * 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.email.utils;
+
+import android.net.Uri;
+import android.util.Log;
+import com.google.common.annotations.VisibleForTesting;
+
+import java.util.List;
+
+public class LogUtils {
+ private static final String TAG = "Gmail";
+
+ /**
+ * Priority constant for the println method; use LogUtils.v.
+ */
+ public static final int VERBOSE = Log.VERBOSE;
+
+ /**
+ * Priority constant for the println method; use LogUtils.d.
+ */
+ public static final int DEBUG = Log.DEBUG;
+
+ /**
+ * Priority constant for the println method; use LogUtils.i.
+ */
+ public static final int INFO = Log.INFO;
+
+ /**
+ * Priority constant for the println method; use LogUtils.w.
+ */
+ public static final int WARN = Log.WARN;
+
+ /**
+ * Priority constant for the println method; use LogUtils.e.
+ */
+ public static final int ERROR = Log.ERROR;
+
+ /**
+ * Used to enable/disable logging that we don't want included in
+ * production releases.
+ */
+ private static final int MAX_ENABLED_LOG_LEVEL = VERBOSE;
+
+
+ private static Boolean sDebugLoggingEnabledForTests = null;
+
+ /**
+ * Enable debug logging for unit tests.
+ */
+ @VisibleForTesting
+ static void setDebugLoggingEnabledForTests(boolean enabled) {
+ sDebugLoggingEnabledForTests = Boolean.valueOf(enabled);
+ }
+
+ /**
+ * Returns true if the build configuration prevents debug logging.
+ */
+ @VisibleForTesting
+ static boolean buildPreventsDebugLogging() {
+ return MAX_ENABLED_LOG_LEVEL > VERBOSE;
+ }
+
+ /**
+ * Returns a boolean indicating whether debug logging is enabled.
+ */
+ private static boolean isDebugLoggingEnabled() {
+ if (buildPreventsDebugLogging()) {
+ return false;
+ }
+ if (sDebugLoggingEnabledForTests != null) {
+ return sDebugLoggingEnabledForTests.booleanValue();
+ }
+ return Log.isLoggable(TAG, Log.DEBUG);
+ }
+
+ /**
+ * Returns a String for the specified content provider uri. This will do
+ * sanitation of the uri to remove PII if debug logging is not enabled.
+ */
+ public static String contentUriToString(Uri uri) {
+
+ if (isDebugLoggingEnabled()) {
+ // Debug logging has been enabled, so log the uri as is
+ return uri.toString();
+ } else {
+ // Debug logging is not enabled, we want to remove the email address from the uri.
+ List<String> pathSegments = uri.getPathSegments();
+
+ Uri.Builder builder = new Uri.Builder()
+ .scheme(uri.getScheme())
+ .authority(uri.getAuthority())
+ .query(uri.getQuery())
+ .fragment(uri.getFragment());
+
+ // This assumes that the first path segment is the account
+ final String account = pathSegments.get(0);
+
+ builder = builder.appendPath(String.valueOf(account.hashCode()));
+ for (int i = 1; i < pathSegments.size(); i++) {
+ builder.appendPath(pathSegments.get(i));
+ }
+ return builder.toString();
+ }
+ }
+
+ /* TODO: what is the correct behavior for base case and the Gmail case? Seems like this
+ * belongs in override code in UnifiedGmail.
+ *Converts the specified set of labels to a string, and removes any PII as necessary
+ * public static String labelSetToString(Set<String> labelSet) {
+ if (isDebugLoggingEnabled() || labelSet == null) {
+ return labelSet != null ? labelSet.toString() : "";
+ } else {
+ final StringBuilder builder = new StringBuilder("[");
+ int i = 0;
+ for(String label : labelSet) {
+ if (i > 0) {
+ builder.append(", ");
+ }
+ builder.append(sanitizeLabelName(label));
+ i++;
+ }
+ builder.append(']');
+ return builder.toString();
+ }
+ }
+
+ private static String sanitizeLabelName(String canonicalName) {
+ if (TextUtils.isEmpty(canonicalName)) {
+ return "";
+ }
+
+ if (Gmail.isSystemLabel(canonicalName)) {
+ return canonicalName;
+ }
+
+ return USER_LABEL_PREFIX + String.valueOf(canonicalName.hashCode());
+ }*/
+
+ /**
+ * Checks to see whether or not a log for the specified tag is loggable at the specified level.
+ */
+ public static boolean isLoggable(String tag, int level) {
+ if (MAX_ENABLED_LOG_LEVEL > level) {
+ return false;
+ }
+ return Log.isLoggable(tag, level);
+ }
+
+ /**
+ * Send a {@link #VERBOSE} log message.
+ * @param tag Used to identify the source of a log message. It usually identifies
+ * the class or activity where the log call occurs.
+ * @param format the format string (see {@link java.util.Formatter#format})
+ * @param args
+ * the list of arguments passed to the formatter. If there are
+ * more arguments than required by {@code format},
+ * additional arguments are ignored.
+ */
+ public static int v(String tag, String format, Object... args) {
+ if (isLoggable(tag, VERBOSE)) {
+ return Log.v(tag, String.format(format, args));
+ }
+ return 0;
+ }
+
+ /**
+ * Send a {@link #VERBOSE} log message.
+ * @param tag Used to identify the source of a log message. It usually identifies
+ * the class or activity where the log call occurs.
+ * @param tr An exception to log
+ * @param format the format string (see {@link java.util.Formatter#format})
+ * @param args
+ * the list of arguments passed to the formatter. If there are
+ * more arguments than required by {@code format},
+ * additional arguments are ignored.
+ */
+ public static int v(String tag, Throwable tr, String format, Object... args) {
+ if (isLoggable(tag, VERBOSE)) {
+ return Log.v(tag, String.format(format, args), tr);
+ }
+ return 0;
+ }
+
+ /**
+ * Send a {@link #DEBUG} log message.
+ * @param tag Used to identify the source of a log message. It usually identifies
+ * the class or activity where the log call occurs.
+ * @param format the format string (see {@link java.util.Formatter#format})
+ * @param args
+ * the list of arguments passed to the formatter. If there are
+ * more arguments than required by {@code format},
+ * additional arguments are ignored.
+ */
+ public static int d(String tag, String format, Object... args) {
+ if (isLoggable(tag, DEBUG)) {
+ return Log.d(tag, String.format(format, args));
+ }
+ return 0;
+ }
+
+ /**
+ * Send a {@link #DEBUG} log message.
+ * @param tag Used to identify the source of a log message. It usually identifies
+ * the class or activity where the log call occurs.
+ * @param tr An exception to log
+ * @param format the format string (see {@link java.util.Formatter#format})
+ * @param args
+ * the list of arguments passed to the formatter. If there are
+ * more arguments than required by {@code format},
+ * additional arguments are ignored.
+ */
+ public static int d(String tag, Throwable tr, String format, Object... args) {
+ if (isLoggable(tag, DEBUG)) {
+ return Log.d(tag, String.format(format, args), tr);
+ }
+ return 0;
+ }
+
+ /**
+ * Send a {@link #INFO} log message.
+ * @param tag Used to identify the source of a log message. It usually identifies
+ * the class or activity where the log call occurs.
+ * @param format the format string (see {@link java.util.Formatter#format})
+ * @param args
+ * the list of arguments passed to the formatter. If there are
+ * more arguments than required by {@code format},
+ * additional arguments are ignored.
+ */
+ public static int i(String tag, String format, Object... args) {
+ if (isLoggable(tag, INFO)) {
+ return Log.i(tag, String.format(format, args));
+ }
+ return 0;
+ }
+
+ /**
+ * Send a {@link #INFO} log message.
+ * @param tag Used to identify the source of a log message. It usually identifies
+ * the class or activity where the log call occurs.
+ * @param tr An exception to log
+ * @param format the format string (see {@link java.util.Formatter#format})
+ * @param args
+ * the list of arguments passed to the formatter. If there are
+ * more arguments than required by {@code format},
+ * additional arguments are ignored.
+ */
+ public static int i(String tag, Throwable tr, String format, Object... args) {
+ if (isLoggable(tag, INFO)) {
+ return Log.i(tag, String.format(format, args), tr);
+ }
+ return 0;
+ }
+
+ /**
+ * Send a {@link #WARN} log message.
+ * @param tag Used to identify the source of a log message. It usually identifies
+ * the class or activity where the log call occurs.
+ * @param format the format string (see {@link java.util.Formatter#format})
+ * @param args
+ * the list of arguments passed to the formatter. If there are
+ * more arguments than required by {@code format},
+ * additional arguments are ignored.
+ */
+ public static int w(String tag, String format, Object... args) {
+ if (isLoggable(tag, WARN)) {
+ return Log.w(tag, String.format(format, args));
+ }
+ return 0;
+ }
+
+ /**
+ * Send a {@link #WARN} log message.
+ * @param tag Used to identify the source of a log message. It usually identifies
+ * the class or activity where the log call occurs.
+ * @param tr An exception to log
+ * @param format the format string (see {@link java.util.Formatter#format})
+ * @param args
+ * the list of arguments passed to the formatter. If there are
+ * more arguments than required by {@code format},
+ * additional arguments are ignored.
+ */
+ public static int w(String tag, Throwable tr, String format, Object... args) {
+ if (isLoggable(tag, WARN)) {
+ return Log.w(tag, String.format(format, args), tr);
+ }
+ return 0;
+ }
+
+ /**
+ * Send a {@link #ERROR} log message.
+ * @param tag Used to identify the source of a log message. It usually identifies
+ * the class or activity where the log call occurs.
+ * @param format the format string (see {@link java.util.Formatter#format})
+ * @param args
+ * the list of arguments passed to the formatter. If there are
+ * more arguments than required by {@code format},
+ * additional arguments are ignored.
+ */
+ public static int e(String tag, String format, Object... args) {
+ if (isLoggable(tag, ERROR)) {
+ return Log.e(tag, String.format(format, args));
+ }
+ return 0;
+ }
+
+ /**
+ * Send a {@link #ERROR} log message.
+ * @param tag Used to identify the source of a log message. It usually identifies
+ * the class or activity where the log call occurs.
+ * @param tr An exception to log
+ * @param format the format string (see {@link java.util.Formatter#format})
+ * @param args
+ * the list of arguments passed to the formatter. If there are
+ * more arguments than required by {@code format},
+ * additional arguments are ignored.
+ */
+ public static int e(String tag, Throwable tr, String format, Object... args) {
+ if (isLoggable(tag, ERROR)) {
+ return Log.e(tag, String.format(format, args), tr);
+ }
+ return 0;
+ }
+
+ /**
+ * What a Terrible Failure: Report a condition that should never happen.
+ * The error will always be logged at level ASSERT with the call stack.
+ * Depending on system configuration, a report may be added to the
+ * {@link android.os.DropBoxManager} and/or the process may be terminated
+ * immediately with an error dialog.
+ * @param tag Used to identify the source of a log message. It usually identifies
+ * the class or activity where the log call occurs.
+ * @param format the format string (see {@link java.util.Formatter#format})
+ * @param args
+ * the list of arguments passed to the formatter. If there are
+ * more arguments than required by {@code format},
+ * additional arguments are ignored.
+ */
+ public static int wtf(String tag, String format, Object... args) {
+ return Log.wtf(tag, String.format(format, args));
+ }
+
+ /**
+ * What a Terrible Failure: Report a condition that should never happen.
+ * The error will always be logged at level ASSERT with the call stack.
+ * Depending on system configuration, a report may be added to the
+ * {@link android.os.DropBoxManager} and/or the process may be terminated
+ * immediately with an error dialog.
+ * @param tag Used to identify the source of a log message. It usually identifies
+ * the class or activity where the log call occurs.
+ * @param tr An exception to log
+ * @param format the format string (see {@link java.util.Formatter#format})
+ * @param args
+ * the list of arguments passed to the formatter. If there are
+ * more arguments than required by {@code format},
+ * additional arguments are ignored.
+ */
+ public static int wtf(String tag, Throwable tr, String format, Object... args) {
+ return Log.wtf(tag, String.format(format, args), tr);
+ }
+}
diff --git a/src/com/android/email/utils/MimeType.java b/src/com/android/email/utils/MimeType.java
new file mode 100644
index 000000000..b27c30038
--- /dev/null
+++ b/src/com/android/email/utils/MimeType.java
@@ -0,0 +1,173 @@
+/**
+ * Copyright (c) 2010, 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.email.utils;
+
+import android.text.TextUtils;
+import android.webkit.MimeTypeMap;
+import com.google.common.collect.ImmutableSet;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.net.Uri;
+
+import com.google.common.annotations.VisibleForTesting;
+
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Utilities for working with different content types within Gmail.
+ */
+public class MimeType {
+ public static final String ANDROID_ARCHIVE = "application/vnd.android.package-archive";
+ private static final String TEXT_PLAIN = "text/plain";
+ @VisibleForTesting
+ static final String GENERIC_MIMETYPE = "application/octet-stream";
+
+ @VisibleForTesting
+ static final String EML_ATTACHMENT_CONTENT_TYPE = "application/eml";
+ private static final String NULL_ATTACHMENT_CONTENT_TYPE = "null";
+ private static final Set<String> UNACCEPTABLE_ATTACHMENT_TYPES = ImmutableSet.of(
+ "application/zip", "application/x-gzip", "application/x-bzip2",
+ "application/x-compress", "application/x-compressed", "application/x-tar");
+
+ private static Set<String> sGviewSupportedTypes = ImmutableSet.of(
+ "application/pdf",
+ "application/vnd.ms-powerpoint",
+ "image/tiff",
+ "application/msword",
+ "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
+ "application/vnd.openxmlformats-officedocument.presentationml.presentation");
+
+ /**
+ * Returns whether or not an attachment of the specified type is installable (e.g. an apk).
+ */
+ public static boolean isInstallable(String type) {
+ return ANDROID_ARCHIVE.equals(type);
+ }
+
+ /**
+ * Returns whether or not an attachment of the specified type is playable (e.g. a video).
+ */
+ public static boolean isPlayable(String type) {
+ return type.startsWith("video/") || type.startsWith("audio/");
+ }
+
+ /**
+ * Returns whether or not an attachment of the specified type is viewable.
+ */
+ public static boolean isViewable(Context context, Uri contentUri, String contentType) {
+ // The provider returns a contentType of "null" instead of null, when the
+ // content type is not known. Changing the provider to return null,
+ // breaks other areas that will need to be fixed in a later CL.
+ // Bug 2922948 has been written up to track this
+ if (contentType == null || contentType.length() == 0 ||
+ NULL_ATTACHMENT_CONTENT_TYPE.equals(contentType)) {
+ return false;
+ }
+
+ if (isBlocked(contentType)) {
+ return false;
+ }
+
+ Intent mimetypeIntent = new Intent(Intent.ACTION_VIEW);
+
+ mimetypeIntent.setDataAndType(contentUri, contentType);
+ PackageManager manager;
+ // We need to catch the exception to make CanvasConversationHeaderView
+ // test pass. Bug: http://b/issue?id=3470653.
+ try {
+ manager = context.getPackageManager();
+ } catch (UnsupportedOperationException e) {
+ return false;
+ }
+ List<ResolveInfo> list = manager.queryIntentActivities(mimetypeIntent,
+ PackageManager.MATCH_DEFAULT_ONLY);
+ return list.size() > 0;
+ }
+
+ /**
+ * @return whether the specified type is blocked.
+ */
+ public static boolean isBlocked(String contentType) {
+ return UNACCEPTABLE_ATTACHMENT_TYPES.contains(contentType);
+ }
+
+ /* TODO: what do we want to do about GSF keys for the unified app?
+ public static boolean isPreviewable(Context context, String contentType) {
+ final String supportedTypes = Gservices.getString(
+ context.getContentResolver(), GservicesKeys.GMAIL_GVIEW_SUPPORTED_TYPES);
+ if (supportedTypes != null) {
+ sGviewSupportedTypes = ImmutableSet.of(supportedTypes.split(","));
+ }
+ return sGviewSupportedTypes.contains(contentType);
+ }*/
+
+ /**
+ * Extract and return filename's extension, converted to lower case, and not including the "."
+ *
+ * @return extension, or null if not found (or null/empty filename)
+ */
+ private static String getFilenameExtension(String fileName) {
+ String extension = null;
+ if (!TextUtils.isEmpty(fileName)) {
+ int lastDot = fileName.lastIndexOf('.');
+ if ((lastDot > 0) && (lastDot < fileName.length() - 1)) {
+ extension = fileName.substring(lastDot + 1).toLowerCase();
+ }
+ }
+ return extension;
+ }
+
+
+ /**
+ * Returns the mime type of the attachment based on its name and
+ * original mime type. This is an workaround for bugs where Gmail
+ * server doesn't set content-type for certain types correctly.
+ * 1) EML files -> "application/eml".
+ * @param name name of the attachment.
+ * @param mimeType original mime type of the attachment.
+ * @return the inferred mime type of the attachment.
+ */
+ public static String inferMimeType(String name, String mimeType) {
+ final String extension = getFilenameExtension(name);
+ if (TextUtils.isEmpty(extension)) {
+ // Attachment doesn't have extension, just return original mime
+ // type.
+ return mimeType;
+ } else {
+ final boolean isTextPlain = TEXT_PLAIN.equalsIgnoreCase(mimeType);
+ final boolean isGenericType =
+ isTextPlain || GENERIC_MIMETYPE.equalsIgnoreCase(mimeType);
+
+ String type = null;
+ if (isGenericType || TextUtils.isEmpty(mimeType)) {
+ type = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
+ }
+ if (!TextUtils.isEmpty(type)) {
+ return type;
+ } if (extension.equals("eml")) {
+ // Extension is ".eml", return mime type "application/eml"
+ return EML_ATTACHMENT_CONTENT_TYPE;
+ } else {
+ // Extension is not ".eml", just return original mime type.
+ return !TextUtils.isEmpty(mimeType) ? mimeType : GENERIC_MIMETYPE;
+ }
+ }
+ }
+}
diff --git a/src/com/android/email/utils/README b/src/com/android/email/utils/README
deleted file mode 100644
index a3fcb7533..000000000
--- a/src/com/android/email/utils/README
+++ /dev/null
@@ -1 +0,0 @@
-Unified email directories \ No newline at end of file
diff --git a/src/com/android/email/utils/Utils.java b/src/com/android/email/utils/Utils.java
new file mode 100644
index 000000000..fd6a5878e
--- /dev/null
+++ b/src/com/android/email/utils/Utils.java
@@ -0,0 +1,24 @@
+/**
+ * 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.email.utils;
+
+public class Utils {
+ public static final String LOG_TAG = "Email";
+
+ public String getLogTag() {
+ return LOG_TAG;
+ }
+}