Merge "Fix overlapping unread and name in drawer" into jb-ub-mail-ur9
diff --git a/res/layout/conversation_item_view_normal_spacious.xml b/res/layout/conversation_item_view_normal_spacious.xml
new file mode 100644
index 0000000..85c90f5
--- /dev/null
+++ b/res/layout/conversation_item_view_normal_spacious.xml
@@ -0,0 +1,189 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2013 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.
+-->
+
+<!-- This layout is used as a template to create custom view CanvasConversationHeaderView
+ in normal mode. To be able to get the correct measurements, every source field should
+ be populated with data here. E.g:
+ - Text View should set text to a random long string (android:text="@string/long_string")
+ - Image View should set source to a specific asset -->
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingBottom="1dp"
+ android:orientation="vertical">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="22dp"
+ android:layout_marginRight="16dp"
+ android:orientation="horizontal">
+
+ <ImageView
+ android:id="@+id/checkmark"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginRight="16dp"
+ android:layout_gravity="center_vertical"
+ android:src="@drawable/btn_check_on_normal_holo_light" />
+
+ <View
+ android:id="@+id/contact_image"
+ android:layout_width="48dp"
+ android:layout_height="48dp"
+ android:layout_marginRight="16dp"
+ android:layout_marginTop="16dp"
+ android:layout_marginBottom="16dp" />
+
+ <LinearLayout
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:orientation="vertical">
+
+ <RelativeLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+
+ <!-- these views overlap horizontally, that's okay. -->
+ <!-- we are only interested in the left edge of senders and the right edge -->
+ <!-- of the date. -->
+ <!-- sendersWidth, clipX, and dateX are dynamically determined later. -->
+
+ <FrameLayout
+ android:id="@+id/senders_decoration"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content">
+
+ <!-- for Email -->
+ <!-- top margin should be 16dp, but the asset has 2dp built-in padding -->
+ <ImageView
+ android:id="@+id/reply_state"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="14dp"
+ android:layout_marginRight="8dp"
+ android:src="@drawable/ic_badge_reply_holo_light" />
+
+ <!-- for Gmail -->
+ <ImageView
+ android:id="@+id/personal_indicator"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="15dp"
+ android:layout_marginLeft="-2dp"
+ android:layout_marginRight="2dp"
+ android:src="@drawable/ic_email_caret_single" />
+
+ </FrameLayout>
+
+ <TextView
+ android:id="@+id/senders"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_toRightOf="@id/senders_decoration"
+ android:layout_marginTop="16dp"
+ android:textSize="18sp"
+ android:lines="1"
+ android:includeFontPadding="false"
+ android:text="@string/long_string" />
+
+ <TextView
+ android:id="@+id/date"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentRight="true"
+ android:layout_marginTop="16dp"
+ android:paddingLeft="8dp"
+ android:textSize="12sp"
+ android:lines="1"
+ android:includeFontPadding="false"
+ android:text="@string/long_string" />
+
+ <!-- top margin should be 16dp, but the asset has 8dp built-in padding -->
+ <!-- left padding should be 8dp, but the asset has 2dp built-in padding -->
+ <ImageView
+ android:id="@+id/paperclip"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_toLeftOf="@id/date"
+ android:layout_marginTop="8dp"
+ android:paddingLeft="6dp"
+ android:src="@drawable/ic_attachment_holo_light" />
+
+ <!-- for Email -->
+ <View android:id="@+id/color_block"
+ android:layout_width="@dimen/color_block_width"
+ android:layout_height="@dimen/color_block_height"
+ android:layout_alignParentRight="true" />
+
+ </RelativeLayout>
+
+ <RelativeLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="16dp">
+
+ <ImageView
+ android:id="@+id/star"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentRight="true"
+ android:src="@drawable/btn_star_off_normal_email_holo_light" />
+
+ <!-- we assume the star asset is less than 48dp wide -->
+ <TextView
+ android:id="@+id/subject"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_toLeftOf="@id/star"
+ android:layout_marginRight="14dp"
+ android:lines="2"
+ android:textSize="13sp"
+ android:includeFontPadding="false"
+ android:text="@string/long_string" />
+
+ </RelativeLayout>
+
+ </LinearLayout>
+
+ </LinearLayout>
+
+ <ImageView
+ android:id="@+id/attachment_previews"
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_marginTop="@dimen/attachment_preview_margin_top"
+ android:layout_marginLeft="@dimen/attachment_preview_margin_side"
+ android:layout_marginRight="@dimen/attachment_preview_margin_side"
+ android:visibility="gone" />
+
+ <TextView
+ android:id="@+id/folders"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="-16dp"
+ android:fontFamily="sans-serif-light"
+ android:includeFontPadding="false"
+ android:text="@string/long_string"
+ android:textSize="11sp"
+ android:lines="1"
+ android:minHeight="16dp" />
+
+</LinearLayout>
diff --git a/res/layout/drawer_empty_view.xml b/res/layout/drawer_empty_view.xml
index f125b76..788debd 100644
--- a/res/layout/drawer_empty_view.xml
+++ b/res/layout/drawer_empty_view.xml
@@ -25,18 +25,20 @@
android:layout_height="match_parent"
android:gravity="center_horizontal">
- <ProgressBar android:id="@+id/progress"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_centerVertical="true"/>
+ <ProgressBar
+ android:id="@+id/progress"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_centerVertical="true"/>
+
<TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_toRightOf="@id/progress"
- android:layout_centerVertical="true"
- android:text="@string/wait_for_sync_title"
- android:textColor="@android:color/white"
- android:textAppearance="?android:attr/textAppearanceMedium"/>
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_toRightOf="@id/progress"
+ android:layout_centerVertical="true"
+ android:text="@string/wait_for_sync_title"
+ android:textColor="@color/dark_gray_text_color"
+ android:textAppearance="?android:attr/textAppearanceMedium"/>
</RelativeLayout>
diff --git a/res/layout/one_pane_activity.xml b/res/layout/one_pane_activity.xml
index b236819..cb33b57 100644
--- a/res/layout/one_pane_activity.xml
+++ b/res/layout/one_pane_activity.xml
@@ -41,7 +41,7 @@
<!--A drawer for phones: a pull-out that gives the list of folders. -->
<fragment class="com.android.mail.ui.DrawerFragment"
android:id="@+id/drawer_pullout"
- android:layout_width="300dp"
+ android:layout_width="@dimen/drawer_width"
android:layout_height="match_parent"
android:layout_gravity="start" />
diff --git a/res/layout/two_pane_activity.xml b/res/layout/two_pane_activity.xml
index 18a4f66..03b2734 100644
--- a/res/layout/two_pane_activity.xml
+++ b/res/layout/two_pane_activity.xml
@@ -15,41 +15,46 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<com.android.mail.ui.TwoPaneLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/two_pane_activity"
- android:orientation="horizontal"
+<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/drawer_container"
android:layout_width="match_parent"
android:layout_height="match_parent">
- <FrameLayout
- android:id="@+id/content_pane"
- android:layout_width="0dp"
- android:layout_height="match_parent"
- android:background="@drawable/drawer_shadow_tablet">
- <fragment class="com.android.mail.ui.DrawerFragment"
- android:id="@+id/drawer_fragment"
- android:layout_height="match_parent"
- android:layout_width="match_parent"
- />
+ <!-- DrawerLayout current only supports one content view (b/8752191) -->
+ <com.android.mail.ui.TwoPaneLayout
+ android:id="@+id/two_pane_activity"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <FrameLayout
+ android:id="@+id/content_pane"
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:background="@drawable/drawer_shadow_tablet">
+ <fragment class="com.android.mail.ui.DrawerFragment"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" />
</FrameLayout>
- <FrameLayout
- android:id="@+id/conversation_list_pane"
- android:layout_width="0dp"
- android:layout_height="match_parent" />
+ <FrameLayout
+ android:id="@+id/conversation_list_pane"
+ android:layout_width="0dp"
+ android:layout_height="match_parent" />
- <com.android.mail.ui.ConversationListCopy
- android:id="@+id/conversation_list_copy"
- android:layout_width="0dp"
- android:layout_height="match_parent" />
+ <com.android.mail.ui.ConversationListCopy
+ android:id="@+id/conversation_list_copy"
+ android:layout_width="0dp"
+ android:layout_height="match_parent" />
- <include layout="@layout/conversation_pager"
- android:id="@+id/conversation_pane"
- android:layout_width="0dp"
- android:layout_height="match_parent" />
+ <include layout="@layout/conversation_pager"
+ android:id="@+id/conversation_pane"
+ android:layout_width="0dp"
+ android:layout_height="match_parent" />
- <com.android.mail.ui.ActionableToastBar
- android:id="@+id/toast_bar"
- style="@style/ToastBarStyle" />
+ <com.android.mail.ui.ActionableToastBar
+ android:id="@+id/toast_bar"
+ style="@style/ToastBarStyle" />
-</com.android.mail.ui.TwoPaneLayout>
+ </com.android.mail.ui.TwoPaneLayout>
+
+</android.support.v4.widget.DrawerLayout>
diff --git a/res/layout/widget.xml b/res/layout/widget.xml
index 128f45a..aebc6c9 100644
--- a/res/layout/widget.xml
+++ b/res/layout/widget.xml
@@ -79,13 +79,6 @@
android:layout_gravity="center_vertical"
android:contentDescription="@string/compose" />
</LinearLayout>
- <ListView
- android:id="@+id/conversation_list"
- android:layout_width="match_parent"
- android:layout_height="0dip"
- android:layout_weight="1"
- android:cacheColorHint="#00000000"
- android:background="@drawable/gradient_bg_widget_holo" />
<LinearLayout
android:id="@+id/widget_configuration"
android:layout_width="match_parent"
@@ -107,6 +100,13 @@
android:textSize="16sp"
android:textStyle="bold"/>
</LinearLayout>
+ <ListView
+ android:id="@+id/conversation_list"
+ android:layout_width="match_parent"
+ android:layout_height="0dip"
+ android:layout_weight="1"
+ android:cacheColorHint="#00000000"
+ android:background="@drawable/gradient_bg_widget_holo" />
<TextView
android:id="@+id/empty_conversation_list"
android:layout_width="match_parent"
diff --git a/res/menu-sw600dp/conversation_list_menu.xml b/res/menu-sw600dp/conversation_list_menu.xml
index ef35f84..4a69777 100644
--- a/res/menu-sw600dp/conversation_list_menu.xml
+++ b/res/menu-sw600dp/conversation_list_menu.xml
@@ -34,7 +34,7 @@
<item android:id="@+id/refresh"
android:title="@string/refresh"
- android:showAsAction="ifRoom"
+ android:showAsAction="never"
android:icon="@drawable/ic_menu_refresh_holo_light"
android:alphabeticShortcut="@string/trigger_refresh_char" />
diff --git a/res/values-sw600dp-land/constants.xml b/res/values-sw600dp-land/constants.xml
index 66d7f72..ddddcae 100644
--- a/res/values-sw600dp-land/constants.xml
+++ b/res/values-sw600dp-land/constants.xml
@@ -15,8 +15,6 @@
limitations under the License.
-->
<resources>
- <integer name="conversation_list_weight">3</integer>
- <integer name="conversation_view_weight">5</integer>
<!-- Whether to show conversation subject in conversation view -->
<bool name="show_conversation_subject">false</bool>
diff --git a/res/values-sw600dp/constants.xml b/res/values-sw600dp/constants.xml
index e625602..b41b7fa 100644
--- a/res/values-sw600dp/constants.xml
+++ b/res/values-sw600dp/constants.xml
@@ -18,12 +18,10 @@
<resources>
<!-- Boolean value indicating whether the table UI should be used. -->
<integer name="use_tablet_ui">1</integer>
+ <bool name="use_expansive_tablet_ui">false</bool>
<!-- Boolean value indicating whether conversation can be collapsed. -->
<integer name="conversation_list_collapsible">1</integer>
<integer name="conversation_header_mode">1</integer>
- <integer name="folder_list_weight">1</integer>
- <integer name="conversation_list_weight">2</integer>
- <integer name="conversation_view_weight">3</integer>
<integer name="conversation_desired_font_size_px">16</integer>
<!-- Whether the list is collapsed in conversation view mode -->
diff --git a/res/values-sw720dp/constants.xml b/res/values-sw720dp/constants.xml
index 2ea59b7..c1b1315 100644
--- a/res/values-sw720dp/constants.xml
+++ b/res/values-sw720dp/constants.xml
@@ -16,11 +16,9 @@
limitations under the License.
-->
<resources>
- <integer name="folder_list_weight">1</integer>
- <integer name="conversation_list_weight">3</integer>
- <integer name="conversation_view_weight">6</integer>
<!-- Whether the list is collapsed in conversation view mode -->
<bool name="list_collapsed">true</bool>
+ <bool name="use_expansive_tablet_ui">true</bool>
<!-- Search results in portrait mode on 10" tablets should still show wide conversation
list items.
diff --git a/res/values-w1000dp/constants.xml b/res/values-w1000dp/constants.xml
index 35093e2..7fff7ff 100644
--- a/res/values-w1000dp/constants.xml
+++ b/res/values-w1000dp/constants.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- Copyright (C) 2011 Google Inc.
+ Copyright (C) 2013 Google Inc.
Licensed to The Android Open Source Project.
Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,4 +18,7 @@
<resources>
<integer name="conversation_list_header_mode">0</integer>
<integer name="conversation_list_search_header_mode">0</integer>
+ <integer name="folder_list_weight">1</integer>
+ <integer name="conversation_list_weight">3</integer>
+ <integer name="conversation_view_weight">6</integer>
</resources>
\ No newline at end of file
diff --git a/res/values-w720dp/constants.xml b/res/values-w720dp/constants.xml
new file mode 100644
index 0000000..0806c41
--- /dev/null
+++ b/res/values-w720dp/constants.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2013 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>
+ <integer name="conversation_list_header_mode">0</integer>
+ <integer name="conversation_list_search_header_mode">0</integer>
+ <integer name="folder_list_weight">9</integer>
+ <integer name="conversation_list_weight">15</integer>
+ <integer name="conversation_view_weight">25</integer>
+</resources>
\ No newline at end of file
diff --git a/res/values/colors.xml b/res/values/colors.xml
index 8cff43d..10f7ce7 100644
--- a/res/values/colors.xml
+++ b/res/values/colors.xml
@@ -40,7 +40,6 @@
<color name="default_folder_foreground_color">@color/gray_text_color</color>
<!-- Folder List/Drawer colors -->
- <color name="drawer_background_dim">#66000000</color>
<color name="account_item_selected_text_color">#35b4e3</color>
<color name="folder_list_divider_color">@color/gray_text_color</color>
<color name="folder_list_heading_text_color">@color/dark_gray_text_color</color>
diff --git a/res/values/dimen.xml b/res/values/dimen.xml
index cf54a9c..3bff4f9 100644
--- a/res/values/dimen.xml
+++ b/res/values/dimen.xml
@@ -17,6 +17,9 @@
-->
<resources>
+ <dimen name="drawer_width">300dp</dimen>
+ <dimen name="list_min_width_is_wide">720dp</dimen>
+ <dimen name="list_normal_mode_min_width_is_spacious">600dp</dimen>
<dimen name="account_dropdown_item_height">48dip</dimen>
<dimen name="senders_font_size">18sp</dimen>
<dimen name="subject_font_size">14sp</dimen>
diff --git a/src/com/android/mail/browse/ConversationItemView.java b/src/com/android/mail/browse/ConversationItemView.java
index 5c562a7..e62a97c 100644
--- a/src/com/android/mail/browse/ConversationItemView.java
+++ b/src/com/android/mail/browse/ConversationItemView.java
@@ -158,7 +158,6 @@
private int mViewWidth = -1;
/** The view mode at which we calculated mViewWidth previously. */
private int mPreviousMode;
- private int mMode = -1;
private int mDateX;
private int mPaperclipX;
private int mSendersWidth;
@@ -242,7 +241,7 @@
return mFoldersCount > 0;
}
- private int measureFolders(int mode, int availableSpace, int cellSize) {
+ private int measureFolders(int availableSpace, int cellSize) {
int totalWidth = 0;
boolean firstTime = true;
for (Folder f : mFoldersSortedSet) {
@@ -262,8 +261,7 @@
return totalWidth;
}
- public void drawFolders(Canvas canvas, ConversationItemViewCoordinates coordinates,
- int mode) {
+ public void drawFolders(Canvas canvas, ConversationItemViewCoordinates coordinates) {
if (mFoldersCount == 0) {
return;
}
@@ -280,12 +278,12 @@
// Initialize space and cell size based on the current mode.
int availableSpace = xEnd - xMinStart;
int averageWidth = availableSpace / mFoldersCount;
- int cellSize = ConversationItemViewCoordinates.getFolderCellWidth(mContext);
+ int cellSize = coordinates.getFolderCellWidth();
// TODO(ath): sFoldersPaint.measureText() is done 3x in this method. stop that.
// Extra credit: maybe cache results across items as long as font size doesn't change.
- final int totalWidth = measureFolders(mode, availableSpace, cellSize);
+ final int totalWidth = measureFolders(availableSpace, cellSize);
int xStart = xEnd - Math.min(availableSpace, totalWidth);
final boolean overflow = totalWidth > availableSpace;
@@ -600,15 +598,6 @@
return mHeader.conversation;
}
- /**
- * Sets the mode. Only used for testing.
- */
- @VisibleForTesting
- void setMode(int mode) {
- mMode = mode;
- mTesting = true;
- }
-
private static void startTimer(String tag) {
if (sTimer != null) {
sTimer.start(tag);
@@ -629,13 +618,10 @@
if (wSize != mViewWidth || mPreviousMode != currentMode) {
mViewWidth = wSize;
mPreviousMode = currentMode;
- if (!mTesting) {
- mMode = ConversationItemViewCoordinates.getMode(mContext, mPreviousMode);
- }
}
mHeader.viewWidth = mViewWidth;
- mConfig.updateWidth(wSize).setMode(mMode);
+ mConfig.updateWidth(wSize).setViewMode(currentMode);
Resources res = getResources();
mHeader.standardScaledDimen = res.getDimensionPixelOffset(R.dimen.standard_scaled_dimen);
@@ -718,8 +704,7 @@
mHeader.messageInfoString = SendersView
.createMessageInfo(context, mHeader.conversation, true);
int maxChars = ConversationItemViewCoordinates.getSendersLength(context,
- ConversationItemViewCoordinates.getMode(context, mActivity.getViewMode()),
- mHeader.conversation.hasAttachments);
+ mCoordinates.getMode(), mHeader.conversation.hasAttachments);
mHeader.displayableSenderEmails = new ArrayList<String>();
mHeader.displayableSenderNames = new ArrayList<String>();
mHeader.styledSenders = new ArrayList<SpannableString>();
@@ -776,7 +761,8 @@
if (mCoordinates.contactImagesWidth <= 0 || mCoordinates.contactImagesHeight <= 0) {
LogUtils.w(LOG_TAG,
"Contact image width(%d) or height(%d) is 0 for mode: (%d).",
- mCoordinates.contactImagesWidth, mCoordinates.contactImagesHeight, mMode);
+ mCoordinates.contactImagesWidth, mCoordinates.contactImagesHeight,
+ mCoordinates.getMode());
return;
}
mContactImagesHolder.setDimensions(mCoordinates.contactImagesWidth,
@@ -801,8 +787,8 @@
if (mCoordinates.attachmentPreviewsWidth <= 0 || attachmentPreviewsHeight <= 0) {
LogUtils.w(LOG_TAG,
"Attachment preview width(%d) or height(%d) is 0 for mode: (%d,%d).",
- mCoordinates.attachmentPreviewsWidth, attachmentPreviewsHeight, mMode,
- mAttachmentPreviewMode);
+ mCoordinates.attachmentPreviewsWidth, attachmentPreviewsHeight,
+ mCoordinates.getMode(), mAttachmentPreviewMode);
return;
}
mAttachmentPreviewsCanvas.setDimensions(mCoordinates.attachmentPreviewsWidth,
@@ -920,7 +906,7 @@
mPaperclipX = mDateX - ATTACHMENT.getWidth() - mCoordinates.datePaddingLeft;
- if (mConfig.isWide()) {
+ if (mCoordinates.isWide()) {
// In wide mode, the end of the senders should align with
// the start of the subject and is based on a max width.
mSendersWidth = mCoordinates.sendersWidth;
@@ -961,7 +947,7 @@
totalWidth += senderFragment.width;
}
- if (!ConversationItemViewCoordinates.displaySendersInline(mMode)) {
+ if (!ConversationItemViewCoordinates.displaySendersInline(mCoordinates.getMode())) {
sendersY += totalWidth <= mSendersWidth ? mCoordinates.sendersLineHeight / 2 : 0;
}
if (mSendersWidth < 0) {
@@ -1200,7 +1186,7 @@
// Folders.
if (mConfig.areFoldersVisible()) {
- mHeader.folderDisplayer.drawFolders(canvas, mCoordinates, mMode);
+ mHeader.folderDisplayer.drawFolders(canvas, mCoordinates);
}
// If this folder has a color (combined view/Email), show it here
diff --git a/src/com/android/mail/browse/ConversationItemViewCoordinates.java b/src/com/android/mail/browse/ConversationItemViewCoordinates.java
index 50fb778..bab9711 100644
--- a/src/com/android/mail/browse/ConversationItemViewCoordinates.java
+++ b/src/com/android/mail/browse/ConversationItemViewCoordinates.java
@@ -72,7 +72,7 @@
*/
public static final class Config {
private int mWidth;
- private int mMode = NORMAL_MODE;
+ private int mViewMode = ViewMode.UNKNOWN;
private int mGadgetMode = GADGET_NONE;
private int mAttachmentPreviewMode = ATTACHMENT_PREVIEW_NONE;
private boolean mShowFolders = false;
@@ -80,8 +80,8 @@
private boolean mShowColorBlock = false;
private boolean mShowPersonalIndicator = false;
- public Config setMode(int mode) {
- mMode = mode;
+ public Config setViewMode(int viewMode) {
+ mViewMode = viewMode;
return this;
}
@@ -124,12 +124,8 @@
return mWidth;
}
- public int getMode() {
- return mMode;
- }
-
- public boolean isWide() {
- return mMode == WIDE_MODE;
+ public int getViewMode() {
+ return mViewMode;
}
public int getGadgetMode() {
@@ -158,12 +154,17 @@
private int getCacheKey() {
// hash the attributes that contribute to item height and child view geometry
- return Objects.hashCode(mWidth, mMode, mGadgetMode, mAttachmentPreviewMode,
+ return Objects.hashCode(mWidth, mViewMode, mGadgetMode, mAttachmentPreviewMode,
mShowFolders, mShowReplyState, mShowPersonalIndicator);
}
}
+ /**
+ * One of either NORMAL_MODE or WIDE_MODE.
+ */
+ private final int mMode;
+
final int height;
// Attachments view
@@ -240,10 +241,38 @@
final int contactImagesX;
final int contactImagesY;
+ /**
+ * The smallest item width for which we use the "wide" layout.
+ */
+ private final int mMinListWidthForWide;
+ /**
+ * The smallest item width for which we use the "spacious" variant of the normal layout,
+ * if the normal version is used at all. Larger than {@link #mMinListWidthForWide}, we use
+ * wide mode anyway, and this value is unused.
+ */
+ private final int mMinListWidthIsSpacious;
+ private final int mFolderCellWidth;
+
private ConversationItemViewCoordinates(Context context, Config config) {
- final ViewGroup view = (ViewGroup) LayoutInflater.from(context).inflate(
- config.getMode() == WIDE_MODE ? R.layout.conversation_item_view_wide :
- R.layout.conversation_item_view_normal, null);
+ final Resources res = context.getResources();
+ mFolderCellWidth = res.getDimensionPixelSize(R.dimen.folder_cell_width);
+ mMinListWidthForWide = res.getDimensionPixelSize(R.dimen.list_min_width_is_wide);
+ mMinListWidthIsSpacious = res.getDimensionPixelSize(
+ R.dimen.list_normal_mode_min_width_is_spacious);
+
+ mMode = calculateMode(res, config);
+
+ final int layoutId;
+ if (mMode == WIDE_MODE) {
+ layoutId = R.layout.conversation_item_view_wide;
+ } else {
+ if (config.getWidth() >= mMinListWidthIsSpacious) {
+ layoutId = R.layout.conversation_item_view_normal_spacious;
+ } else {
+ layoutId = R.layout.conversation_item_view_normal;
+ }
+ }
+ final ViewGroup view = (ViewGroup) LayoutInflater.from(context).inflate(layoutId, null);
final TextView folders = (TextView) view.findViewById(R.id.folders);
folders.setVisibility(config.areFoldersVisible() ? View.VISIBLE : View.GONE);
@@ -293,7 +322,6 @@
// Layout the appropriate view.
final int widthSpec = MeasureSpec.makeMeasureSpec(config.getWidth(), MeasureSpec.EXACTLY);
final int heightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
- final Resources res = context.getResources();
view.measure(widthSpec, heightSpec);
view.layout(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight());
@@ -336,7 +364,7 @@
final TextView subject = (TextView) view.findViewById(R.id.subject);
final int subjectTopAdjust = getLatinTopAdjustment(subject);
subjectX = getX(subject);
- if (config.isWide()) {
+ if (isWide()) {
subjectY = getY(subject) + subjectTopAdjust;
} else {
subjectY = getY(subject) + sendersTopAdjust;
@@ -351,7 +379,7 @@
// vertically align folders min left edge with subject
foldersX = subjectX;
foldersXEnd = getX(folders) + folders.getWidth();
- if (config.isWide()) {
+ if (isWide()) {
foldersY = getY(folders);
} else {
foldersY = getY(folders) + sendersTopAdjust;
@@ -419,7 +447,15 @@
attachmentPreviewsWidth = 0;
}
- height = view.getHeight() + (config.isWide() ? 0 : sendersTopAdjust);
+ height = view.getHeight() + (isWide() ? 0 : sendersTopAdjust);
+ }
+
+ public int getMode() {
+ return mMode;
+ }
+
+ public boolean isWide() {
+ return mMode == WIDE_MODE;
}
/**
@@ -437,13 +473,12 @@
}
/**
- * Returns the mode of the header view (Wide/Normal/Narrow).
+ * Returns the mode of the header view (Wide/Normal).
*/
- public static int getMode(Context context, int viewMode) {
- final Resources res = context.getResources();
- switch (viewMode) {
+ private int calculateMode(Resources res, Config config) {
+ switch (config.getViewMode()) {
case ViewMode.CONVERSATION_LIST:
- return res.getInteger(R.integer.conversation_list_header_mode);
+ return config.getWidth() >= mMinListWidthForWide ? WIDE_MODE : NORMAL_MODE;
case ViewMode.SEARCH_RESULTS_LIST:
return res.getInteger(R.integer.conversation_list_search_header_mode);
@@ -454,13 +489,6 @@
}
/**
- * Returns the mode of the header view (Wide/Normal/Narrow).
- */
- public static int getMode(Context context, ViewMode viewMode) {
- return getMode(context, viewMode.getMode());
- }
-
- /**
* Returns a value array multiplied by the specified density.
*/
public static int[] getDensityDependentArray(int[] values, float density) {
@@ -605,8 +633,8 @@
* intra-cell margin within cells.
*
*/
- public static int getFolderCellWidth(Context context) {
- return context.getResources().getDimensionPixelSize(R.dimen.folder_cell_width);
+ public int getFolderCellWidth() {
+ return mFolderCellWidth;
}
public static boolean isWideMode(int mode) {
diff --git a/src/com/android/mail/ui/AbstractActivityController.java b/src/com/android/mail/ui/AbstractActivityController.java
index 4b418c5..22c635c 100644
--- a/src/com/android/mail/ui/AbstractActivityController.java
+++ b/src/com/android/mail/ui/AbstractActivityController.java
@@ -17,6 +17,7 @@
package com.android.mail.ui;
+import android.animation.ValueAnimator;
import android.app.ActionBar;
import android.app.ActionBar.LayoutParams;
import android.app.Activity;
@@ -44,7 +45,10 @@
import android.os.Bundle;
import android.os.Handler;
import android.provider.SearchRecentSuggestions;
+import android.support.v4.app.ActionBarDrawerToggle;
+import android.support.v4.widget.DrawerLayout;
import android.view.DragEvent;
+import android.view.Gravity;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.Menu;
@@ -52,6 +56,7 @@
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
+import android.widget.ListView;
import android.widget.Toast;
import com.android.mail.ConversationListContext;
@@ -336,6 +341,13 @@
private final Deque<UpOrBackHandler> mUpOrBackHandlers = Lists.newLinkedList();
+ protected DrawerLayout mDrawerContainer;
+ protected View mDrawerPullout;
+ protected ActionBarDrawerToggle mDrawerToggle;
+ protected ListView mListViewForAnimating;
+ protected boolean mHasNewAccountOrFolder;
+ protected final MailDrawerListener mDrawerListener = new MailDrawerListener();
+
public static final String SYNC_ERROR_DIALOG_FRAGMENT_TAG = "SyncErrorDialogFragment";
private final DataSetObserver mUndoNotificationObserver = new DataSetObserver() {
@@ -461,10 +473,9 @@
isSearch ? R.layout.search_actionbar_view : R.layout.actionbar_view, null);
mActionBarView.initialize(mActivity, this, actionBar);
- // If not a tablet, we always want the up/back button to show at top.
- if(!mIsTablet) {
- mActionBarView.setBackButton();
- }
+ // init the action bar to allow the 'up' affordance.
+ // any configurations that disallow 'up' should do that later.
+ mActionBarView.setBackButton();
}
/**
@@ -624,12 +635,39 @@
}
/**
- * The default behavior for drawer closed is to notify the observers as, by default, there
- * is no drawer.
+ * If the drawer is open, the function locks the drawer to the closed, thereby sliding in
+ * the drawer to the left edge, disabling events, and refreshing it once it's either closed
+ * or put in an idle state.
*/
@Override
public void closeDrawer(final boolean hasNewFolderOrAccount) {
- mDrawerObservers.notifyChanged();
+ if (!isDrawerEnabled()) {
+ mDrawerObservers.notifyChanged();
+ return;
+ }
+
+ // If there are no new folders or accounts to switch to, just close the drawer
+ if (!hasNewFolderOrAccount) {
+ mDrawerContainer.closeDrawers();
+ return;
+ }
+
+ final ConversationListFragment conversationList = getConversationListFragment();
+ if (conversationList != null) {
+ mListViewForAnimating = conversationList.getListView();
+ } else {
+ // There is no conversation list to animate, so just set it to null
+ mListViewForAnimating = null;
+ }
+
+ if (mDrawerContainer.isDrawerOpen(mDrawerPullout)) {
+ // Lets the drawer listener update the drawer contents and notify the FolderListFragment
+ mHasNewAccountOrFolder = true;
+ mDrawerContainer.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
+ } else {
+ // Drawer is already closed, notify observers that is the case.
+ mDrawerObservers.notifyChanged();
+ }
}
private void fetchSearchFolder(Intent intent) {
@@ -641,6 +679,7 @@
@Override
public void onFolderChanged(Folder folder) {
+ mDrawerContainer.closeDrawers();
changeFolder(folder, null);
}
@@ -931,6 +970,14 @@
mRecentFolderList.initialize(mActivity);
mVeiledMatcher.initialize(this);
+ mDrawerToggle = new ActionBarDrawerToggle((Activity) mActivity, mDrawerContainer,
+ R.drawable.ic_drawer, R.string.drawer_open, R.string.drawer_close);
+ mDrawerContainer.setDrawerListener(new MailDrawerListener());
+ mDrawerContainer.setDrawerShadow(
+ mContext.getResources().getDrawable(R.drawable.drawer_shadow), Gravity.START);
+
+ mDrawerToggle.setDrawerIndicatorEnabled(isDrawerEnabled());
+
// All the individual UI components listen for ViewMode changes. This
// simplifies the amount of logic in the AbstractActivityController, but increases the
// possibility of timing-related bugs.
@@ -970,12 +1017,25 @@
@Override
public void onPostCreate(Bundle savedState) {
- // Do nothing
+ // Sync the toggle state after onRestoreInstanceState has occurred.
+ mDrawerToggle.syncState();
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
- // Do nothing
+ mDrawerToggle.onConfigurationChanged(newConfig);
+ }
+
+ /**
+ * If drawer is open/visible (even partially), close it.
+ */
+ protected void closeDrawerIfOpen() {
+ if (!isDrawerEnabled()) {
+ return;
+ }
+ if(mDrawerContainer.isDrawerOpen(mDrawerPullout)) {
+ mDrawerContainer.closeDrawers();
+ }
}
@Override
@@ -1023,6 +1083,14 @@
@Override
public boolean onOptionsItemSelected(MenuItem item) {
+ /*
+ * The action bar home/up action should open or close the drawer.
+ * mDrawerToggle will take care of this.
+ */
+ if (mDrawerToggle.onOptionsItemSelected(item)) {
+ return true;
+ }
+
final int id = item.getItemId();
LogUtils.d(LOG_TAG, "AbstractController.onOptionsItemSelected(%d) called.", id);
boolean handled = true;
@@ -1141,11 +1209,20 @@
}
/**
- * Stand-in method overriden in OnePaneController for toggling the state
- * of the drawer.
+ * Toggles the drawer pullout. If it was open (Fully extended), the
+ * drawer will be closed. Otherwise, the drawer will be opened. This should
+ * only be called when used with a toggle item. Other cases should be handled
+ * explicitly with just closeDrawers() or openDrawer(View drawerView);
*/
protected void toggleFolderListState() {
- //Implemented in OnePaneController.java
+ if (!isDrawerEnabled()) {
+ return;
+ }
+ if(mDrawerContainer.isDrawerOpen(mDrawerPullout)) {
+ mDrawerContainer.closeDrawers();
+ } else {
+ mDrawerContainer.openDrawer(mDrawerPullout);
+ }
}
@Override
@@ -1165,6 +1242,12 @@
return true;
}
}
+
+ if (isDrawerEnabled() && mDrawerContainer.isDrawerVisible(mDrawerPullout)) {
+ mDrawerContainer.closeDrawers();
+ return true;
+ }
+
return handleBackPress();
}
@@ -1502,6 +1585,7 @@
}.run(mResolver, msg.uri, values, null /* selection*/, null /* selectionArgs */);
}
+ @Override
public void requestFolderRefresh() {
if (mFolder == null) {
return;
@@ -1719,6 +1803,28 @@
if (newMode != ViewMode.UNKNOWN) {
resetActionBarIcon();
}
+
+ if (isDrawerEnabled()) {
+ // if search list/conv mode, disable drawer pull and indicator
+ // allow drawer pull everywhere except conversation mode where the list is hidden
+ // only allow indicator at top level of app
+ final boolean showIndicator;
+ final boolean allowPull;
+ if (ViewMode.isSearchMode(newMode)) {
+ showIndicator = false;
+ allowPull = false;
+ } else {
+ allowPull = !(ViewMode.isConversationMode(newMode)
+ // TODO(ath): get this to work to allow drawer pull in 2-pane conv mode.
+ /* && !isConversationListVisible() */);
+ showIndicator = (newMode == ViewMode.CONVERSATION_LIST
+ || newMode == ViewMode.FOLDER_LIST);
+ }
+ mDrawerToggle.setDrawerIndicatorEnabled(showIndicator);
+ mDrawerContainer.setDrawerLockMode(allowPull ? DrawerLayout.LOCK_MODE_UNLOCKED :
+ DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
+ closeDrawerIfOpen();
+ }
}
public void disablePagerUpdates() {
@@ -3628,4 +3734,61 @@
}
mDetachedConvUri = null;
}
+
+ private class MailDrawerListener implements DrawerLayout.DrawerListener {
+ @Override
+ public void onDrawerOpened(View drawerView) {
+ mDrawerToggle.onDrawerOpened(drawerView);
+ }
+
+ @Override
+ public void onDrawerClosed(View drawerView) {
+ mDrawerToggle.onDrawerClosed(drawerView);
+ if (mHasNewAccountOrFolder) {
+ refreshDrawer();
+ }
+ }
+
+ /**
+ * As part of the overriden function, it will animate the alpha of the conversation list
+ * view along with the drawer sliding when we're in the process of switching accounts or
+ * folders. Note, this is the same amount of work done as {@link ValueAnimator#ofFloat}.
+ */
+ @Override
+ public void onDrawerSlide(View drawerView, float slideOffset) {
+ mDrawerToggle.onDrawerSlide(drawerView, slideOffset);
+ if (mHasNewAccountOrFolder && mListViewForAnimating != null) {
+ mListViewForAnimating.setAlpha(slideOffset);
+ }
+ }
+
+ /**
+ * This condition here should only be called when the drawer is stuck in a weird state
+ * and doesn't register the onDrawerClosed, but shows up as idle. Make sure to refresh
+ * and, more importantly, unlock the drawer when this is the case.
+ */
+ @Override
+ public void onDrawerStateChanged(int newState) {
+ mDrawerToggle.onDrawerStateChanged(newState);
+ if (mHasNewAccountOrFolder && newState == DrawerLayout.STATE_IDLE) {
+ refreshDrawer();
+ }
+ }
+
+ /**
+ * If we've reached a stable drawer state, unlock the drawer for usage, clear the
+ * conversation list, and finish end actions. Also, make
+ * {@link #mHasNewAccountOrFolder} false to reflect we're done changing.
+ */
+ public void refreshDrawer() {
+ mHasNewAccountOrFolder = false;
+ mDrawerContainer.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED);
+ ConversationListFragment conversationList = getConversationListFragment();
+ if (conversationList != null) {
+ conversationList.clear();
+ }
+ mDrawerObservers.notifyChanged();
+ }
+ }
+
}
diff --git a/src/com/android/mail/ui/MailActionBarView.java b/src/com/android/mail/ui/MailActionBarView.java
index 272e129..38b944d 100644
--- a/src/com/android/mail/ui/MailActionBarView.java
+++ b/src/com/android/mail/ui/MailActionBarView.java
@@ -551,7 +551,7 @@
}
public void setBackButton() {
- if (mActionBar == null){
+ if (mActionBar == null) {
return;
}
// Show home as up, and show an icon.
diff --git a/src/com/android/mail/ui/OnePaneController.java b/src/com/android/mail/ui/OnePaneController.java
index 804317b..527513a 100644
--- a/src/com/android/mail/ui/OnePaneController.java
+++ b/src/com/android/mail/ui/OnePaneController.java
@@ -17,22 +17,13 @@
package com.android.mail.ui;
-import android.animation.ValueAnimator;
-import android.app.Activity;
import android.app.Fragment;
import android.app.FragmentManager;
import android.app.FragmentTransaction;
import android.app.LoaderManager.LoaderCallbacks;
-import android.content.res.Configuration;
import android.net.Uri;
import android.os.Bundle;
-import android.support.v4.app.ActionBarDrawerToggle;
import android.support.v4.widget.DrawerLayout;
-import android.view.MenuItem;
-import android.view.View;
-import android.view.Gravity;
-import android.view.ViewGroup;
-import android.widget.ListView;
import com.android.mail.ConversationListContext;
import com.android.mail.R;
@@ -75,70 +66,6 @@
private Folder mInbox;
/** Whether a conversation list for this account has ever been shown.*/
private boolean mConversationListNeverShown = true;
- private boolean mHasNewAccountOrFolder = false;
- private DrawerLayout mDrawerContainer;
- private ViewGroup mDrawerPullout;
- private ListView mListViewForAnimating;
-
- private ActionBarDrawerToggle mDrawerToggle;
-
- private class MailDrawerListener implements DrawerLayout.DrawerListener {
- @Override
- public void onDrawerOpened(View drawerView) {
- mDrawerToggle.onDrawerOpened(drawerView);
- }
-
- @Override
- public void onDrawerClosed(View drawerView) {
- mDrawerToggle.onDrawerClosed(drawerView);
- if (mHasNewAccountOrFolder) {
- refreshDrawer();
- }
- }
-
- /**
- * As part of the overriden function, it will animate the alpha of the conversation list
- * view along with the drawer sliding when we're in the process of switching accounts or
- * folders. Note, this is the same amount of work done as {@link ValueAnimator#ofFloat}.
- */
- @Override
- public void onDrawerSlide(View drawerView, float slideOffset) {
- mDrawerToggle.onDrawerSlide(drawerView, slideOffset);
- if (mHasNewAccountOrFolder && mListViewForAnimating != null) {
- mListViewForAnimating.setAlpha(slideOffset);
- LogUtils.w(LOG_TAG, "OFFSET: " + slideOffset);
- }
- }
-
- /**
- * This condition here should only be called when the drawer is stuck in a weird state
- * and doesn't register the onDrawerClosed, but shows up as idle. Make sure to refresh
- * and, more importantly, unlock the drawer when this is the case.
- */
- @Override
- public void onDrawerStateChanged(int newState) {
- mDrawerToggle.onDrawerStateChanged(newState);
- if (mHasNewAccountOrFolder && newState == DrawerLayout.STATE_IDLE) {
- refreshDrawer();
- }
- }
-
- /**
- * If we've reached a stable drawer state, unlock the drawer for usage, clear the
- * conversation list, and finish end actions. Also, make
- * {@link OnePaneController#mHasNewAccountOrFolder} false to reflect we're done changing.
- */
- public void refreshDrawer() {
- mHasNewAccountOrFolder = false;
- mDrawerContainer.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED);
- ConversationListFragment conversationList = getConversationListFragment();
- if (conversationList != null) {
- conversationList.clear();
- }
- notifyDrawerClosed();
- }
- }
-
public OnePaneController(MailActivity activity, ViewMode viewMode) {
super(activity, viewMode);
@@ -219,77 +146,22 @@
public boolean onCreate(Bundle savedInstanceState) {
mActivity.setContentView(R.layout.one_pane_activity);
mDrawerContainer = (DrawerLayout) mActivity.findViewById(R.id.drawer_container);
- mDrawerContainer.setScrimColor(
- mContext.getResources().getColor(R.color.drawer_background_dim));
- mDrawerContainer.setDrawerListener(new MailDrawerListener());
- mDrawerPullout = (ViewGroup) mDrawerContainer.findViewById(R.id.drawer_pullout);
- mDrawerContainer.setDrawerShadow(
- mContext.getResources().getDrawable(R.drawable.drawer_shadow), Gravity.LEFT);
+ mDrawerPullout = mDrawerContainer.findViewById(R.id.drawer_pullout);
mDrawerPullout.setBackgroundResource(R.color.list_background_color);
- mDrawerToggle = new ActionBarDrawerToggle((Activity)mActivity, mDrawerContainer,
- R.drawable.ic_drawer, R.string.drawer_open, R.string.drawer_close);
-
// The parent class sets the correct viewmode and starts the application off.
return super.onCreate(savedInstanceState);
}
@Override
- public void onPostCreate(Bundle savedInstanceState) {
- super.onPostCreate(savedInstanceState);
-
- // Sync the toggle state after onRestoreInstanceState has occurred.
- mDrawerToggle.syncState();
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- /*
- * The action bar home/up action should open or close the drawer.
- * mDrawerToggle will take care of this.
- */
- if (mDrawerToggle.onOptionsItemSelected(item)) {
- return true;
- }
- return super.onOptionsItemSelected(item);
- }
-
-
- @Override
- public void onConfigurationChanged(Configuration newConfig) {
- super.onConfigurationChanged(newConfig);
- mDrawerToggle.onConfigurationChanged(newConfig);
- }
-
- @Override
protected boolean isConversationListVisible() {
return mConversationListVisible;
}
- /**
- * If drawer is open/visible (even partially), close it.
- */
- private void closeDrawerIfOpen() {
- if(mDrawerContainer.isDrawerOpen(mDrawerPullout)) {
- mDrawerContainer.closeDrawers();
- }
- }
-
@Override
public void onViewModeChanged(int newMode) {
super.onViewModeChanged(newMode);
- // When view mode changes, lock drawer if viewing search results or
- // viewing a conversation. Set unlocked otherwise.
- if (ViewMode.isSearchMode(newMode) || ViewMode.isConversationMode(newMode)) {
- mDrawerToggle.setDrawerIndicatorEnabled(false);
- mDrawerContainer.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
- } else {
- mDrawerToggle.setDrawerIndicatorEnabled(true);
- mDrawerContainer.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED);
- }
- closeDrawerIfOpen();
-
// When entering conversation list mode, hide and clean up any currently visible
// conversation.
if (ViewMode.isListMode(newMode)) {
@@ -319,6 +191,7 @@
public void showConversationList(ConversationListContext listContext) {
super.showConversationList(listContext);
enableCabMode();
+ mConversationListVisible = true;
if (ConversationListContext.isSearchResult(listContext)) {
mViewMode.enterSearchResultsListMode();
} else {
@@ -352,7 +225,6 @@
mActivity.getFragmentManager().executePendingTransactions();
- mConversationListVisible = true;
onConversationVisibilityChanged(false);
onConversationListVisibilityChanged(true);
mConversationListNeverShown = false;
@@ -361,6 +233,7 @@
@Override
protected void showConversation(Conversation conversation, boolean inLoaderCallbacks) {
super.showConversation(conversation, inLoaderCallbacks);
+ mConversationListVisible = false;
if (conversation == null) {
transitionBackToConversationListMode(inLoaderCallbacks);
return;
@@ -392,7 +265,6 @@
}
mPagerController.show(mAccount, mFolder, conversation, true /* changeVisibility */);
onConversationVisibilityChanged(true);
- mConversationListVisible = false;
onConversationListVisibilityChanged(false);
}
@@ -431,27 +303,6 @@
}
/**
- * Toggles the drawer pullout. If it was open (Fully extended), the
- * drawer will be closed. Otherwise, the drawer will be opened. This should
- * only be called when used with a toggle item. Other cases should be handled
- * explicitly with just closeDrawers() or openDrawer(View drawerView);
- */
- @Override
- protected void toggleFolderListState() {
- if(mDrawerContainer.isDrawerOpen(mDrawerPullout)) {
- mDrawerContainer.closeDrawers();
- } else {
- mDrawerContainer.openDrawer(mDrawerPullout);
- }
- }
-
- @Override
- public void onFolderChanged(Folder folder) {
- mDrawerContainer.closeDrawers();
- super.onFolderChanged(folder);
- }
-
- /**
* Replace the content_pane with the fragment specified here. The tag is specified so that
* the {@link ActivityController} can look up the fragments through the
* {@link android.app.FragmentManager}. This action will be placed on the back stack.
@@ -502,11 +353,6 @@
public boolean handleBackPress() {
final int mode = mViewMode.getMode();
- if (mDrawerContainer.isDrawerVisible(mDrawerPullout)) {
- mDrawerContainer.closeDrawers();
- return true;
- }
-
//TODO(shahrk): Remove the folder list standalone view
if (mode == ViewMode.FOLDER_LIST) {
final Folder hierarchyFolder = getHierarchyFolder();
@@ -645,6 +491,7 @@
private void transitionBackToConversationListMode(boolean inLoaderCallbacks) {
final int mode = mViewMode.getMode();
enableCabMode();
+ mConversationListVisible = true;
if (mode == ViewMode.SEARCH_RESULTS_CONVERSATION) {
mViewMode.enterSearchResultsListMode();
} else {
@@ -660,7 +507,6 @@
// Set the correct context for what the conversation view will be now.
onFolderChanged(mInbox);
}
- mConversationListVisible = true;
onConversationVisibilityChanged(false);
onConversationListVisibilityChanged(true);
}
@@ -801,46 +647,6 @@
}
}
- /**
- * The default behavior calls mDrawerObserver's notifyChanged(). So, to notify the consumer of
- * the observer that the drawer is closed, we simply make a call to
- * {@link AbstractActivityController#closeDrawer(boolean)}.
- */
- public void notifyDrawerClosed() {
- super.closeDrawer(true);
- }
-
- /**
- * If the drawer is open, the function locks the drawer to the closed, thereby sliding in
- * the drawer to the left edge, disabling events, and refreshing it once it's either closed
- * or put in an idle state.
- */
- @Override
- public void closeDrawer(final boolean hasNewFolderOrAccount) {
- // If there are no new folders or accounts to switch to, just close the drawer
- if (!hasNewFolderOrAccount) {
- mDrawerContainer.closeDrawers();
- return;
- }
-
- final ConversationListFragment conversationList = getConversationListFragment();
- if (conversationList != null) {
- mListViewForAnimating = conversationList.getListView();
- } else {
- // There is no conversation list to animate, so just set it to null
- mListViewForAnimating = null;
- }
-
- if (mDrawerContainer.isDrawerOpen(mDrawerPullout)) {
- // Lets the drawer listener update the drawer contents and notify the FolderListFragment
- mHasNewAccountOrFolder = true;
- mDrawerContainer.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
- } else {
- // Drawer is already closed, notify observers that is the case.
- notifyDrawerClosed();
- }
- }
-
@Override
public boolean isDrawerEnabled() {
// The drawer is enabled for one pane mode
diff --git a/src/com/android/mail/ui/TwoPaneController.java b/src/com/android/mail/ui/TwoPaneController.java
index 67bbbd5..2a04877 100644
--- a/src/com/android/mail/ui/TwoPaneController.java
+++ b/src/com/android/mail/ui/TwoPaneController.java
@@ -21,6 +21,7 @@
import android.app.FragmentTransaction;
import android.content.Intent;
import android.os.Bundle;
+import android.support.v4.widget.DrawerLayout;
import android.view.Gravity;
import android.widget.FrameLayout;
@@ -127,12 +128,15 @@
@Override
public boolean onCreate(Bundle savedState) {
mActivity.setContentView(R.layout.two_pane_activity);
+ mDrawerContainer = (DrawerLayout) mActivity.findViewById(R.id.drawer_container);
+ mDrawerPullout = mDrawerContainer.findViewById(R.id.content_pane);
mLayout = (TwoPaneLayout) mActivity.findViewById(R.id.two_pane_activity);
if (mLayout == null) {
// We need the layout for everything. Crash early if it is null.
LogUtils.wtf(LOG_TAG, "mLayout is null!");
}
mLayout.setController(this, Intent.ACTION_SEARCH.equals(mActivity.getIntent().getAction()));
+ mLayout.setDrawerLayout(mDrawerContainer);
// 2-pane layout is the main listener of view mode changes, and issues secondary
// notifications upon animation completion:
@@ -218,6 +222,9 @@
@Override
public void resetActionBarIcon() {
+ if (isDrawerEnabled()) {
+ return;
+ }
// On two-pane, the back button is only removed in the conversation list mode, and shown
// for every other condition.
if (mViewMode.isListMode() || mViewMode.isWaitingForSync()) {
@@ -577,7 +584,6 @@
@Override
public boolean isDrawerEnabled() {
- // The drawer is currently not enabled for two pane mode
- return false;
+ return mLayout.isDrawerEnabled();
}
}
diff --git a/src/com/android/mail/ui/TwoPaneLayout.java b/src/com/android/mail/ui/TwoPaneLayout.java
index 2164be4..011df72 100644
--- a/src/com/android/mail/ui/TwoPaneLayout.java
+++ b/src/com/android/mail/ui/TwoPaneLayout.java
@@ -23,9 +23,12 @@
import android.app.Activity;
import android.content.Context;
import android.content.res.Resources;
+import android.support.v4.widget.DrawerLayout;
import android.util.AttributeSet;
+import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
+import android.view.ViewParent;
import android.view.animation.AnimationUtils;
import android.widget.FrameLayout;
@@ -86,6 +89,8 @@
private LayoutListener mListener;
private boolean mIsSearchResult;
+ private DrawerLayout mDrawerLayout;
+
private View mConversationView;
private View mFoldersView;
private View mListView;
@@ -106,6 +111,8 @@
*/
private Integer mListCopyWidthOnComplete;
+ private final boolean mIsExpansiveLayout;
+
public TwoPaneLayout(Context context) {
this(context, null);
}
@@ -130,6 +137,8 @@
/ (folderListWeight + convListWeight);
mConversationListWeight = (double) convListWeight
/ (convListWeight + convViewWeight);
+
+ mIsExpansiveLayout = res.getBoolean(R.bool.use_expansive_tablet_ui);
}
@Override
@@ -156,6 +165,10 @@
mIsSearchResult = isSearchResult;
}
+ public void setDrawerLayout(DrawerLayout drawerLayout) {
+ mDrawerLayout = drawerLayout;
+ }
+
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
LogUtils.d(Utils.VIEW_DEBUGGING_TAG, "TPL(%s).onMeasure()", this);
@@ -180,14 +193,21 @@
*/
private void setupPaneWidths(int parentWidth) {
final int foldersWidth = computeFolderListWidth(parentWidth);
+ final int foldersFragmentWidth;
+ if (isDrawerView(mFoldersView)) {
+ foldersFragmentWidth = getResources().getDimensionPixelSize(R.dimen.drawer_width);
+ } else {
+ foldersFragmentWidth = foldersWidth;
+ }
final int convWidth = computeConversationWidth(parentWidth);
- // only adjust the fixed folder and conversation view widths when my width changes
+ setPaneWidth(mFoldersView, foldersFragmentWidth);
+
+ // only adjust the fixed conversation view width when my width changes
if (parentWidth != getMeasuredWidth()) {
LogUtils.i(LOG_TAG, "setting up new TPL, w=%d fw=%d cv=%d", parentWidth,
foldersWidth, convWidth);
- setPaneWidth(mFoldersView, foldersWidth);
setPaneWidth(mConversationView, convWidth);
}
@@ -286,8 +306,10 @@
// a view intent.
if (mPositionedMode == ViewMode.UNKNOWN) {
mConversationView.setX(convX);
- mFoldersView.setX(foldersX);
mListView.setX(listX);
+ if (!isDrawerView(mFoldersView)) {
+ mFoldersView.setX(foldersX);
+ }
// listeners need to know that the "transition" is complete, even if one is not run.
// defer notifying listeners because we're in a layout pass, and they might do layout.
@@ -310,7 +332,9 @@
useHardwareLayer(true);
mConversationView.animate().x(convX);
- mFoldersView.animate().x(foldersX);
+ if (!isDrawerView(mFoldersView)) {
+ mFoldersView.animate().x(foldersX);
+ }
mListCopyView.animate().x(listX).alpha(0.0f);
mListView.animate()
.x(listX)
@@ -334,6 +358,9 @@
private void configureAnimations(View... views) {
for (View v : views) {
+ if (isDrawerView(v)) {
+ continue;
+ }
v.animate()
.setInterpolator(mSlideInterpolator)
.setDuration(SLIDE_DURATION_MS);
@@ -342,14 +369,18 @@
private void useHardwareLayer(boolean useHardware) {
final int layerType = useHardware ? LAYER_TYPE_HARDWARE : LAYER_TYPE_NONE;
- mFoldersView.setLayerType(layerType, null);
+ if (!isDrawerView(mFoldersView)) {
+ mFoldersView.setLayerType(layerType, null);
+ }
mListView.setLayerType(layerType, null);
mListCopyView.setLayerType(layerType, null);
mConversationView.setLayerType(layerType, null);
if (useHardware) {
// these buildLayer calls are safe because layout is the only way we get here
// (i.e. these views must already be attached)
- mFoldersView.buildLayer();
+ if (!isDrawerView(mFoldersView)) {
+ mFoldersView.buildLayer();
+ }
mListView.buildLayer();
mListCopyView.buildLayer();
mConversationView.buildLayer();
@@ -434,8 +465,11 @@
private int computeFolderListWidth(int parentWidth) {
if (mIsSearchResult) {
return 0;
+ } else if (isDrawerView(mFoldersView)) {
+ return 0;
+ } else {
+ return (int) (parentWidth * mFolderListWeight);
}
- return (int) (parentWidth * mFolderListWeight);
}
private void dispatchConversationListVisibilityChange(boolean visible) {
@@ -450,14 +484,19 @@
}
}
+ // does not apply to drawer children. will return zero for those.
private int getPaneWidth(View pane) {
- return pane.getLayoutParams().width;
+ return isDrawerView(pane) ? 0 : pane.getLayoutParams().width;
}
public View getConversationView() {
return mConversationView;
}
+ private boolean isDrawerView(View child) {
+ return child != null && child.getParent() == mDrawerLayout;
+ }
+
/**
* @return Whether or not the conversation list is visible on screen.
*/
@@ -475,6 +514,26 @@
mConversationView.setVisibility(VISIBLE);
}
+ // set up the drawer as appropriate for the configuration
+ final ViewParent foldersParent = mFoldersView.getParent();
+ if (mIsExpansiveLayout && foldersParent != this) {
+ if (foldersParent != mDrawerLayout) {
+ throw new IllegalStateException("invalid Folders fragment parent: " +
+ foldersParent);
+ }
+ mDrawerLayout.removeView(mFoldersView);
+ addView(mFoldersView, 0);
+ mFoldersView.setBackgroundResource(R.drawable.drawer_shadow_tablet);
+ } else if (!mIsExpansiveLayout && foldersParent == this) {
+ removeView(mFoldersView);
+ mDrawerLayout.addView(mFoldersView);
+ final DrawerLayout.LayoutParams lp =
+ (DrawerLayout.LayoutParams) mFoldersView.getLayoutParams();
+ lp.gravity = Gravity.START;
+ mFoldersView.setLayoutParams(lp);
+ mFoldersView.setBackgroundResource(R.color.list_background_color);
+ }
+
// detach the pager immediately from its data source (to prevent processing updates)
if (ViewMode.isConversationMode(mCurrentMode)) {
mController.disablePagerUpdates();
@@ -499,6 +558,23 @@
}
lp.width = w;
pane.setLayoutParams(lp);
+ if (LogUtils.isLoggable(LOG_TAG, LogUtils.DEBUG)) {
+ final String s;
+ if (pane == mFoldersView) {
+ s = "folders";
+ } else if (pane == mListView) {
+ s = "conv-list";
+ } else if (pane == mConversationView) {
+ s = "conv-view";
+ } else {
+ s = "???:" + pane;
+ }
+ LogUtils.d(LOG_TAG, "TPL: setPaneWidth, w=%spx pane=%s", w, s);
+ }
+ }
+
+ public boolean isDrawerEnabled() {
+ return !mIsExpansiveLayout;
}
}
diff --git a/src/com/android/mail/widget/BaseWidgetProvider.java b/src/com/android/mail/widget/BaseWidgetProvider.java
index b4b85c7..9dde2bb 100644
--- a/src/com/android/mail/widget/BaseWidgetProvider.java
+++ b/src/com/android/mail/widget/BaseWidgetProvider.java
@@ -60,6 +60,8 @@
protected static final String ACTION_UPDATE_WIDGET = "com.android.mail.ACTION_UPDATE_WIDGET";
+ protected static final String
+ ACTION_VALIDATE_ALL_WIDGETS = "com.android.mail.ACTION_VALIDATE_ALL_WIDGETS";
protected static final String EXTRA_WIDGET_ID = "widgetId";
private static final String LOG_TAG = LogTag.getLogTag();
@@ -132,6 +134,8 @@
updateWidgetInternal(context, widgetId, account, folderType, folderUri,
folderConversationListUri, folderDisplayName);
}
+ } else if (ACTION_VALIDATE_ALL_WIDGETS.equals(action)) {
+ validateAllWidgetInformation(context);
} else if (Utils.ACTION_NOTIFY_DATASET_CHANGED.equals(action)) {
// Receive notification for a certain account.
final Bundle extras = intent.getExtras();
@@ -299,6 +303,12 @@
context.sendBroadcast(updateWidgetIntent);
}
+ public static void validateAllWidgets(Context context, String accountMimeType) {
+ final Intent migrateAllWidgetsIntent = new Intent(ACTION_VALIDATE_ALL_WIDGETS);
+ migrateAllWidgetsIntent.setType(accountMimeType);
+ context.sendBroadcast(migrateAllWidgetsIntent);
+ }
+
protected void updateWidgetInternal(Context context, int appWidgetId, Account account,
final int folderType, final Uri folderUri, final Uri folderConversationListUri,
final String folderDisplayName) {
@@ -348,6 +358,23 @@
return false;
}
+ protected boolean isFolderValid(Context context, Uri folderUri) {
+ if (folderUri != null) {
+ final Cursor folderCursor =
+ context.getContentResolver().query(folderUri,
+ UIProvider.FOLDERS_PROJECTION, null, null, null);
+
+ try {
+ if (folderCursor.moveToFirst()) {
+ return true;
+ }
+ } finally {
+ folderCursor.close();
+ }
+ }
+ return false;
+ }
+
protected void configureValidAccountWidget(Context context, RemoteViews remoteViews,
int appWidgetId, Account account, final int folderType, final Uri folderUri,
final Uri folderConversationListUri, String folderDisplayName) {
@@ -371,6 +398,36 @@
}
}
+ private final void validateAllWidgetInformation(Context context) {
+ final int[] widgetIds = getCurrentWidgetIds(context);
+ for (int widgetId : widgetIds) {
+ final String accountFolder = MailPrefs.get(context).getWidgetConfiguration(widgetId);
+ String accountUri = null;
+ Uri folderUri = null;
+ if (!TextUtils.isEmpty(accountFolder)) {
+ final String[] parsedInfo = TextUtils.split(accountFolder,
+ ACCOUNT_FOLDER_PREFERENCE_SEPARATOR);
+ if (parsedInfo.length == 2) {
+ accountUri = parsedInfo[0];
+ folderUri = Uri.parse(parsedInfo[1]);
+ } else {
+ accountUri = accountFolder;
+ folderUri = Uri.EMPTY;
+ }
+ }
+
+ Account account = null;
+ if (!TextUtils.isEmpty(accountUri)) {
+ account = getAccountObject(context, accountUri);
+ }
+
+ // unconfigure the widget if it is not valid
+ if (!isAccountValid(context, account) || !isFolderValid(context, folderUri)) {
+ updateWidgetInternal(context, widgetId, null, FolderType.DEFAULT, null, null, null);
+ }
+ }
+ }
+
/**
* Abstract method allowing extending classes to perform widget migration
*/