Merge "Attachments now show in a grid-like view." into jb-ub-mail
diff --git a/res/drawable-hdpi/ic_divider_dashed_holo_dark.png b/res/drawable-hdpi/ic_divider_dashed_holo_dark.png
new file mode 100644
index 0000000..663a2f8
--- /dev/null
+++ b/res/drawable-hdpi/ic_divider_dashed_holo_dark.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_divider_dashed_holo_dark.png b/res/drawable-mdpi/ic_divider_dashed_holo_dark.png
new file mode 100644
index 0000000..6652541
--- /dev/null
+++ b/res/drawable-mdpi/ic_divider_dashed_holo_dark.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_divider_dashed_holo_dark.png b/res/drawable-xhdpi/ic_divider_dashed_holo_dark.png
new file mode 100644
index 0000000..34e8fd2
--- /dev/null
+++ b/res/drawable-xhdpi/ic_divider_dashed_holo_dark.png
Binary files differ
diff --git a/res/layout/conversation_message_attachment.xml b/res/layout/conversation_message_attachment.xml
index df0a466..e60ea5a 100644
--- a/res/layout/conversation_message_attachment.xml
+++ b/res/layout/conversation_message_attachment.xml
@@ -15,8 +15,10 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<com.android.mail.browse.MessageHeaderAttachment xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
+<com.android.mail.browse.MessageAttachmentTile
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/attachment_tile"
+ android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:orientation="vertical"
@@ -25,59 +27,87 @@
android:background="@drawable/attachment_bg_holo">
<RelativeLayout
+ android:id="@+id/attachment_tile_layout"
android:layout_width="match_parent"
- android:layout_height="48dp">
+ android:layout_height="match_parent" >
<ImageView
- android:id="@+id/attachment_icon"
- android:layout_width="48dp"
+ android:id="@+id/attachment_tile_image"
+ android:layout_width="match_parent"
android:layout_height="match_parent"
- android:scaleType="centerCrop"
- android:background="#e5e5e5" />
+ android:scaleType="centerCrop" />
<RelativeLayout
android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_toRightOf="@id/attachment_icon"
+ android:layout_height="@dimen/attachment_tile_shadowbox_height"
+ android:background="@color/attachment_tile_shadow_box_color"
+ android:layout_alignParentBottom="true"
android:gravity="center_vertical"
- android:layout_marginLeft="16dp"
- android:layout_marginRight="16dp">
+ android:paddingLeft="8dip">
- <TextView
- android:id="@+id/attachment_title"
+ <LinearLayout
android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:singleLine="true" />
+ android:layout_height="match_parent"
+ android:layout_alignParentLeft="true"
+ android:layout_toLeftOf="@+id/attachment_tile_secondary_button"
+ android:orientation="vertical"
+ android:gravity="center_vertical"
+ android:paddingRight="4dip">
- <TextView
- android:id="@+id/attachment_subtitle"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_below="@id/attachment_title"
- android:singleLine="true" />
+ <TextView
+ android:id="@+id/attachment_tile_title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textColor="@android:color/white"
+ android:textSize="16sp"
+ android:singleLine="true"
+ android:fadingEdge="horizontal"
+ android:fadingEdgeLength="3dip"
+ android:ellipsize="marquee" />
+
+ <TextView
+ android:id="@+id/attachment_tile_subtitle"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textColor="@color/attachment_tile_subtitle_color"
+ android:singleLine="true"
+ android:paddingBottom="4dip"
+ android:fadingEdge="horizontal"
+ android:fadingEdgeLength="3dip"
+ android:layout_marginTop="-3dip"
+ android:ellipsize="marquee" />
+
+ </LinearLayout>
+
+ <Button
+ android:id="@id/attachment_tile_secondary_button"
+ android:background="?android:attr/selectableItemBackground"
+ android:layout_height="@dimen/attachment_tile_shadowbox_height"
+ android:layout_width="wrap_content"
+ android:drawableLeft="@drawable/ic_divider_dashed_holo_dark"
+ android:layout_alignParentRight="true"
+ android:text="@string/save_attachment"
+ android:textColor="@android:color/white" />
<ProgressBar
android:id="@+id/attachment_progress"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_below="@id/attachment_title"
+ android:layout_alignParentBottom="true"
style="?android:attr/progressBarStyleHorizontal"
android:indeterminate="false"
android:visibility="gone" />
</RelativeLayout>
+ <View
+ android:id="@+id/attachment_tile_push_state"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:focusable="true"
+ android:background="?android:attr/selectableItemBackground" />
+
</RelativeLayout>
- <LinearLayout
- android:id="@+id/attachment_buttons"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:divider="?android:attr/dividerVertical"
- android:showDividers="middle"
- android:dividerPadding="8dp"
- android:orientation="horizontal">
- <include layout="@layout/conversation_message_attachment_buttons" />
- </LinearLayout>
-
-</com.android.mail.browse.MessageHeaderAttachment>
+</com.android.mail.browse.MessageAttachmentTile>
diff --git a/res/values-land/constants.xml b/res/values-land/constants.xml
new file mode 100644
index 0000000..fc5925f
--- /dev/null
+++ b/res/values-land/constants.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2012 Google Inc.
+ Licensed to The Android Open Source Project.
+
+ 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.
+-->
+<resources>
+ <!-- Determines the number of columns in an AttachmentTileRow -->
+ <integer name="attachment_tile_column_count">3</integer>
+</resources>
diff --git a/res/values/colors.xml b/res/values/colors.xml
index e4c0366..3f71f9a 100644
--- a/res/values/colors.xml
+++ b/res/values/colors.xml
@@ -70,4 +70,9 @@
<color name="photo_background_color">#ff000000</color>
<color name="photo_crop_dim_color">#cc000000</color>
<color name="photo_crop_highlight_color">#fff</color>
+
+ <!-- Color of the semi-transparent shadow box on attachment tiles -->
+ <color name="attachment_tile_shadow_box_color">#7F000000</color>
+ <!-- Color of the subtitle message in the attachment tile -->
+ <color name="attachment_tile_subtitle_color">#CCCCCC</color>
</resources>
diff --git a/res/values/constants.xml b/res/values/constants.xml
index 0b255ed..4459642 100644
--- a/res/values/constants.xml
+++ b/res/values/constants.xml
@@ -69,4 +69,7 @@
<!-- Whether to display folder colors in the widget -->
<bool name="display_folder_colors_in_widget">false</bool>
+
+ <!-- Determines the number of columns in an AttachmentTileRow -->
+ <integer name="attachment_tile_column_count">2</integer>
</resources>
diff --git a/res/values/dimen.xml b/res/values/dimen.xml
index d39558b..cf54584 100644
--- a/res/values/dimen.xml
+++ b/res/values/dimen.xml
@@ -96,4 +96,11 @@
<dimen name="photo_crop_stroke_width">1dp</dimen>
<dimen name="photo_overlay_right_padding">4dp</dimen>
<dimen name="photo_overlay_bottom_padding">6dp</dimen>
+
+ <!-- Attachment Tile Layouts -->
+ <!--
+ Use sp instead of dip so that the shadowbox heights can all scale uniformly
+ when the font size is scaled for accessibility purposes
+ -->
+ <dimen name="attachment_tile_shadowbox_height">48sp</dimen>
</resources>
diff --git a/src/com/android/mail/browse/AttachmentTileRow.java b/src/com/android/mail/browse/AttachmentTileRow.java
new file mode 100644
index 0000000..794370e
--- /dev/null
+++ b/src/com/android/mail/browse/AttachmentTileRow.java
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * 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.browse;
+
+import android.content.Context;
+import android.net.Uri;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.FrameLayout;
+
+import com.android.mail.providers.Attachment;
+
+import java.util.List;
+
+/**
+ * Acts as a row item composed of {@link MessageAttachmentTile}s.
+ */
+public class AttachmentTileRow extends FrameLayout {
+ private int mColumnCount;
+ private LayoutInflater mInflater;
+ private Uri mAttachmentsListUri;
+
+ public AttachmentTileRow(Context context, Uri attachmentsListUri, int columnCount) {
+ super(context);
+ mColumnCount = columnCount;
+ mInflater = LayoutInflater.from(context);
+ mAttachmentsListUri = attachmentsListUri;
+ }
+
+ /**
+ * Configures the row to add {@link Attachment}s information to the views
+ */
+ public void configureRow(List<Attachment> list, int rowIndex) {
+ // Adding tiles to row and filling in attachment information
+ for (int columnCounter = 0; columnCounter < mColumnCount; columnCounter++) {
+ Attachment attachment =
+ columnCounter < list.size() ? list.get(columnCounter) : null;
+ addTileFromEntry(attachment, columnCounter, rowIndex);
+ }
+ }
+
+ private void addTileFromEntry(Attachment attachment, int columnIndex, int rowIndex) {
+ final MessageAttachmentTile attachmentTile;
+
+ if (getChildCount() <= columnIndex) {
+ attachmentTile = MessageAttachmentTile.inflate(mInflater, this);
+ addView(attachmentTile);
+ } else {
+ attachmentTile = (MessageAttachmentTile) getChildAt(columnIndex);
+ }
+
+ attachmentTile.render(attachment, mAttachmentsListUri,
+ mColumnCount*rowIndex + columnIndex); // determine the attachment's index
+ // using number of columns and the
+ // current row and column
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+ onLayoutForTiles();
+ }
+
+ private void onLayoutForTiles() {
+ final int count = getChildCount();
+
+ // Just line up children horizontally.
+ int childLeft = 0;
+ for (int i = 0; i < count; i++) {
+ final View child = getChildAt(i);
+
+ // Note MeasuredWidth includes the padding.
+ final int childWidth = child.getMeasuredWidth();
+ child.layout(childLeft, 0, childLeft + childWidth, child.getMeasuredHeight());
+ childLeft += childWidth;
+ }
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ onMeasureForTiles(widthMeasureSpec);
+ }
+
+ private void onMeasureForTiles(int widthMeasureSpec) {
+ final int width = MeasureSpec.getSize(widthMeasureSpec);
+
+ final int childCount = getChildCount();
+ if (childCount == 0) {
+ // Just in case...
+ setMeasuredDimension(width, 0);
+ return;
+ }
+
+ // 1. Calculate image size.
+ // = [total width] / [child count]
+ //
+ // 2. Set it to width/height of each children.
+ // If we have a remainder, some tiles will have 1 pixel larger width than its height.
+ //
+ // 3. Set the dimensions of itself.
+ // Let width = given width.
+ // Let height = image size + bottom paddding.
+ final int imageSize = (width) / mColumnCount;
+ final int remainder = width - (imageSize * mColumnCount);
+
+ for (int i = 0; i < childCount; i++) {
+ final View child = getChildAt(i);
+ final int childWidth = imageSize + child.getPaddingRight()
+ // Compensate for the remainder
+ + (i < remainder ? 1 : 0);
+ final int childHeight = imageSize + child.getPaddingBottom();
+ child.measure(
+ MeasureSpec.makeMeasureSpec(childWidth, MeasureSpec.EXACTLY),
+ MeasureSpec.makeMeasureSpec(childHeight, MeasureSpec.EXACTLY)
+ );
+ }
+ setMeasuredDimension(width, imageSize + getChildAt(0).getPaddingBottom());
+ }
+
+ @Override
+ public void sendAccessibilityEvent(int eventType) {
+ // This method is called when the child tile is INVISIBLE (meaning "empty"), and the
+ // Accessibility Manager needs to find alternative content description to speak.
+ // Here, we ignore the default behavior, since we don't want to let the manager speak
+ // a contact name for the tile next to the INVISIBLE tile.
+ }
+}
diff --git a/src/com/android/mail/browse/MessageHeaderAttachment.java b/src/com/android/mail/browse/MessageAttachmentTile.java
similarity index 90%
rename from src/com/android/mail/browse/MessageHeaderAttachment.java
rename to src/com/android/mail/browse/MessageAttachmentTile.java
index 3dc8344..be86463 100644
--- a/src/com/android/mail/browse/MessageHeaderAttachment.java
+++ b/src/com/android/mail/browse/MessageAttachmentTile.java
@@ -64,7 +64,7 @@
* intents to act on an attachment.
*
*/
-public class MessageHeaderAttachment extends LinearLayout implements OnClickListener,
+public class MessageAttachmentTile extends LinearLayout implements OnClickListener,
OnMenuItemClickListener, DialogInterface.OnCancelListener,
DialogInterface.OnDismissListener {
@@ -183,18 +183,18 @@
}
- public MessageHeaderAttachment(Context context) {
+ public MessageAttachmentTile(Context context) {
super(context);
}
- public MessageHeaderAttachment(Context context, AttributeSet attrs) {
+ public MessageAttachmentTile(Context context, AttributeSet attrs) {
super(context, attrs);
mCommandHandler = new AttachmentCommandHandler();
}
- public static MessageHeaderAttachment inflate(LayoutInflater inflater, ViewGroup parent) {
- MessageHeaderAttachment view = (MessageHeaderAttachment) inflater.inflate(
+ public static MessageAttachmentTile inflate(LayoutInflater inflater, ViewGroup parent) {
+ MessageAttachmentTile view = (MessageAttachmentTile) inflater.inflate(
R.layout.conversation_message_attachment, parent, false);
return view;
}
@@ -206,6 +206,11 @@
*
*/
public void render(Attachment attachment, Uri attachmentsListUri, int index) {
+ if (attachment == null) {
+ setVisibility(View.INVISIBLE);
+ return;
+ }
+
final Attachment prevAttachment = mAttachment;
mAttachment = attachment;
mAttachmentsListUri = attachmentsListUri;
@@ -244,7 +249,9 @@
setThumbnailToDefault();
}
- mProgress.setMax(attachment.size);
+ if (mProgress != null) {
+ mProgress.setMax(attachment.size);
+ }
updateActions();
updateStatus();
@@ -321,27 +328,27 @@
protected void onFinishInflate() {
super.onFinishInflate();
- mIcon = (ImageView) findViewById(R.id.attachment_icon);
- mTitle = (TextView) findViewById(R.id.attachment_title);
- mSubTitle = (TextView) findViewById(R.id.attachment_subtitle);
+ mIcon = (ImageView) findViewById(R.id.attachment_tile_image);
+ mTitle = (TextView) findViewById(R.id.attachment_tile_title);
+ mSubTitle = (TextView) findViewById(R.id.attachment_tile_subtitle);
mProgress = (ProgressBar) findViewById(R.id.attachment_progress);
- mPreviewButton = (Button) findViewById(R.id.preview_attachment);
- mViewButton = (Button) findViewById(R.id.view_attachment);
- mSaveButton = (Button) findViewById(R.id.save_attachment);
- mInfoButton = (Button) findViewById(R.id.info_attachment);
- mPlayButton = (Button) findViewById(R.id.play_attachment);
- mInstallButton = (Button) findViewById(R.id.install_attachment);
- mCancelButton = (Button) findViewById(R.id.cancel_attachment);
+// mPreviewButton = (Button) findViewById(R.id.preview_attachment);
+// mViewButton = (Button) findViewById(R.id.view_attachment);
+ mSaveButton = (Button) findViewById(R.id.attachment_tile_secondary_button);
+// mInfoButton = (Button) findViewById(R.id.info_attachment);
+// mPlayButton = (Button) findViewById(R.id.play_attachment);
+// mInstallButton = (Button) findViewById(R.id.install_attachment);
+// mCancelButton = (Button) findViewById(R.id.cancel_attachment);
setOnClickListener(this);
- mPreviewButton.setOnClickListener(this);
- mViewButton.setOnClickListener(this);
+// mPreviewButton.setOnClickListener(this);
+// mViewButton.setOnClickListener(this);
mSaveButton.setOnClickListener(this);
- mInfoButton.setOnClickListener(this);
- mPlayButton.setOnClickListener(this);
- mInstallButton.setOnClickListener(this);
- mCancelButton.setOnClickListener(this);
+// mInfoButton.setOnClickListener(this);
+// mPlayButton.setOnClickListener(this);
+// mInstallButton.setOnClickListener(this);
+// mCancelButton.setOnClickListener(this);
mIconScaleType = mIcon.getScaleType();
}
@@ -363,9 +370,11 @@
break;
case R.id.view_attachment:
case R.id.play_attachment:
+ case R.id.attachment_tile:
showAttachment(AttachmentDestination.CACHE);
break;
case R.id.save_attachment:
+ case R.id.attachment_tile_secondary_button:
if (mAttachment.canSave()) {
startDownloadingAttachment(AttachmentDestination.EXTERNAL);
}
@@ -383,8 +392,6 @@
cancelAttachment();
break;
default:
- // entire attachment view is clickable.
- // TODO: this should execute a default action
break;
}
return true;
@@ -415,7 +422,9 @@
}
private void setButtonVisible(View button, boolean visible) {
- button.setVisibility(visible ? VISIBLE : GONE);
+ if (button != null) {
+ button.setVisibility(visible ? VISIBLE : GONE);
+ }
}
/**
diff --git a/src/com/android/mail/browse/MessageFooterView.java b/src/com/android/mail/browse/MessageFooterView.java
index 3b8c2be..1dc90a7 100644
--- a/src/com/android/mail/browse/MessageFooterView.java
+++ b/src/com/android/mail/browse/MessageFooterView.java
@@ -23,9 +23,9 @@
import android.database.Cursor;
import android.os.Bundle;
import android.util.AttributeSet;
-import android.view.LayoutInflater;
import android.widget.LinearLayout;
+import com.android.mail.R;
import com.android.mail.browse.AttachmentLoader.AttachmentCursor;
import com.android.mail.browse.ConversationContainer.DetachListener;
import com.android.mail.browse.ConversationViewAdapter.MessageHeaderItem;
@@ -39,10 +39,11 @@
public class MessageFooterView extends LinearLayout implements DetachListener,
LoaderManager.LoaderCallbacks<Cursor> {
+ private int mColumnCount;
+
private MessageHeaderItem mMessageHeaderItem;
private LoaderManager mLoaderManager;
private AttachmentCursor mAttachmentsCursor;
- private LayoutInflater mInflater;
/**
* An easy way for the conversation view to disable immediately kicking off attachment loaders
@@ -59,7 +60,8 @@
public MessageFooterView(Context context, AttributeSet attrs) {
super(context, attrs);
- mInflater = LayoutInflater.from(context);
+ mColumnCount = context.getResources().getInteger(
+ R.integer.attachment_tile_column_count);
}
/**
@@ -132,19 +134,37 @@
}
private void renderAttachments(List<Attachment> attachments) {
- int index = 0;
- for (Attachment attachment : attachments) {
- MessageHeaderAttachment attachView = (MessageHeaderAttachment) findViewWithTag(
- attachment.uri);
+ if (attachments == null || attachments.isEmpty()) {
+ return;
+ }
- if (attachView == null) {
- attachView = MessageHeaderAttachment.inflate(mInflater, this);
- attachView.setTag(attachment.uri);
- addView(attachView);
+ int rowStartIndex = 0; // the index for the first attachment in the current row
+ final Context context = getContext();
+ final int attachmentListSize = attachments.size();
+ final int numRows = (attachmentListSize - 1)/mColumnCount + 1;
+
+ for (int i = 0; i < numRows; i++) {
+ // Get the row view if it already exists.
+ AttachmentTileRow rowView = (AttachmentTileRow) getChildAt(i);
+
+ // If the row view does not exist, create it and add it to its parent.
+ if (rowView == null) {
+ rowView = new AttachmentTileRow(context,
+ mMessageHeaderItem.message.attachmentListUri, mColumnCount);
+ addView(rowView);
}
- attachView.render(attachment, mMessageHeaderItem.message.attachmentListUri, index);
- index++;
+ // Get the sub-list of attachments for that row.
+ int rowEnd = rowStartIndex + mColumnCount;
+ if (rowEnd > attachmentListSize) {
+ rowEnd = attachmentListSize;
+ }
+ List<Attachment> sublist = attachments.subList(rowStartIndex, rowEnd);
+
+ // Setup the tiles in this row.
+ rowView.configureRow(sublist, i);
+
+ rowStartIndex += mColumnCount;
}
}
@@ -188,5 +208,4 @@
public void onLoaderReset(Loader<Cursor> loader) {
mAttachmentsCursor = null;
}
-
}
diff --git a/src/com/android/mail/photo/PhotoViewActivity.java b/src/com/android/mail/photo/PhotoViewActivity.java
index 233698d..a7116a9 100644
--- a/src/com/android/mail/photo/PhotoViewActivity.java
+++ b/src/com/android/mail/photo/PhotoViewActivity.java
@@ -150,8 +150,6 @@
/** The URI of the photos we're viewing; may be {@code null} */
private String mPhotosUri;
- /** The resolved URI of the photo to view; may be {@code null}. */
- private String mResolvedPhotoUri;
/** The index of the currently viewed photo */
private int mPhotoIndex;
/** A hint for which cursor page the photo is located on */