summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJin Cao <jinyan@google.com>2014-08-12 18:16:57 -0700
committerJin Cao <jinyan@google.com>2014-08-21 15:23:39 -0700
commitc6801eb828627c37b8992584767c095dfe11df62 (patch)
treeef75cff9964c8cc8c4fbfce495dc5a684b348fef
parent28d44b2bec95381693b203f0515218aaf5418f04 (diff)
downloadandroid_packages_apps_UnifiedEmail-c6801eb828627c37b8992584767c095dfe11df62.tar.gz
android_packages_apps_UnifiedEmail-c6801eb828627c37b8992584767c095dfe11df62.tar.bz2
android_packages_apps_UnifiedEmail-c6801eb828627c37b8992584767c095dfe11df62.zip
Quantum search - version 1
I apologize in advance for this huge CL. - New icons (yay!) - Abandon framework search and handle in-app search functionality ourselves. This is made possible because we use Toolbar and can position any custom view on top. - Remove all previous search related attributes, including search providers, searchable, search authority, default search menu item layout, etc. - Cleaned up the recent history provider to contain only the functionalities we need - query, add, and delete. Instead of using the framework to add recent queries, we directly insert into our database. Since the provider no longer needs to extend ContentProvider, removed some unnecessary callbacks such as onCreate. - Custom quantum search views: - Top search bar, this is inserted in a FrameLayout on top of Toolbar. The search bar interacts with the suggestion list and AbstractActivityController via the QuantumSearchViewController interface. - Suggestions list, this is inserted in the FrameLayout that typically contains the main content pane for either one-pane or two-pane layouts. Again, this interacts with the action bar via the controller. - Voice search, this is simply an implicit intent that converts speech to text. b/16518233 Change-Id: I589c40e6c6e3d8c719856b735d0c53e8db986e65
-rw-r--r--AndroidManifest.xml11
-rw-r--r--res/drawable-hdpi/ic_arrow_back_24dp.pngbin0 -> 2977 bytes
-rw-r--r--res/drawable-hdpi/ic_close_24dp.pngbin0 -> 3033 bytes
-rw-r--r--res/drawable-hdpi/ic_history_24dp.pngbin0 -> 4068 bytes
-rw-r--r--res/drawable-hdpi/ic_history_holo_light.pngbin749 -> 0 bytes
-rw-r--r--res/drawable-hdpi/ic_mic_24dp.pngbin0 -> 3243 bytes
-rw-r--r--res/drawable-mdpi/ic_arrow_back_24dp.pngbin0 -> 2884 bytes
-rw-r--r--res/drawable-mdpi/ic_close_24dp.pngbin0 -> 2937 bytes
-rw-r--r--res/drawable-mdpi/ic_history_24dp.pngbin0 -> 3480 bytes
-rw-r--r--res/drawable-mdpi/ic_history_holo_light.pngbin507 -> 0 bytes
-rw-r--r--res/drawable-mdpi/ic_mic_24dp.pngbin0 -> 3029 bytes
-rw-r--r--res/drawable-xhdpi/ic_arrow_back_24dp.pngbin0 -> 3017 bytes
-rw-r--r--res/drawable-xhdpi/ic_close_24dp.pngbin0 -> 3141 bytes
-rw-r--r--res/drawable-xhdpi/ic_history_24dp.pngbin0 -> 4360 bytes
-rw-r--r--res/drawable-xhdpi/ic_history_holo_light.pngbin916 -> 0 bytes
-rw-r--r--res/drawable-xhdpi/ic_mic_24dp.pngbin0 -> 3416 bytes
-rw-r--r--res/drawable-xxhdpi/ic_arrow_back_24dp.pngbin0 -> 3152 bytes
-rw-r--r--res/drawable-xxhdpi/ic_close_24dp.pngbin0 -> 3316 bytes
-rw-r--r--res/drawable-xxhdpi/ic_history_24dp.pngbin0 -> 5270 bytes
-rw-r--r--res/drawable-xxhdpi/ic_history_holo_light.pngbin2915 -> 0 bytes
-rw-r--r--res/drawable-xxhdpi/ic_mic_24dp.pngbin0 -> 3804 bytes
-rw-r--r--res/drawable-xxxhdpi/ic_arrow_back_24dp.pngbin0 -> 3355 bytes
-rw-r--r--res/drawable-xxxhdpi/ic_close_24dp.pngbin0 -> 3504 bytes
-rw-r--r--res/drawable-xxxhdpi/ic_history_24dp.pngbin0 -> 6501 bytes
-rw-r--r--res/drawable-xxxhdpi/ic_mic_24dp.pngbin0 -> 4215 bytes
-rw-r--r--res/drawable/action_bar_shadow.xml (renamed from res/values-sw600dp-land/dimen.xml)12
-rw-r--r--res/layout/mail_actionbar_searchview.xml48
-rw-r--r--res/layout/one_pane_activity.xml13
-rw-r--r--res/layout/search_suggestion_item.xml47
-rw-r--r--res/layout/search_suggestion_list.xml54
-rw-r--r--res/layout/toolbar_with_search.xml33
-rw-r--r--res/layout/two_pane_activity.xml87
-rw-r--r--res/menu-sw600dp-land/conversation_actions.xml3
-rw-r--r--res/menu-sw600dp-land/conversation_list_search_results_actions.xml3
-rw-r--r--res/menu/conversation_list_menu.xml3
-rw-r--r--res/menu/conversation_list_search_results_actions.xml3
-rw-r--r--res/values-ldrtl/styles-ldrtl.xml7
-rw-r--r--res/values-sw600dp/themes.xml2
-rw-r--r--res/values/colors.xml3
-rw-r--r--res/values/dimen.xml4
-rw-r--r--res/values/strings.xml8
-rw-r--r--res/values/styles.xml10
-rw-r--r--res/values/themes.xml7
-rw-r--r--res/xml/searchable.xml28
-rw-r--r--src/com/android/mail/providers/SearchRecentSuggestionsProvider.java175
-rw-r--r--src/com/android/mail/providers/SuggestionsProvider.java19
-rw-r--r--src/com/android/mail/ui/AbstractActivityController.java54
-rw-r--r--src/com/android/mail/ui/ActionBarController.java152
-rw-r--r--src/com/android/mail/ui/ActivityController.java2
-rw-r--r--src/com/android/mail/ui/ControllableActivity.java3
-rw-r--r--src/com/android/mail/ui/ConversationListFragment.java1
-rw-r--r--src/com/android/mail/ui/FolderSelectionActivity.java9
-rw-r--r--src/com/android/mail/ui/MailActivity.java7
-rw-r--r--src/com/android/mail/ui/MaterialSearchActionView.java148
-rw-r--r--src/com/android/mail/ui/MaterialSearchSuggestionsList.java214
-rw-r--r--src/com/android/mail/ui/MaterialSearchViewController.java197
-rw-r--r--src/com/android/mail/ui/OnePaneController.java6
-rw-r--r--src/com/android/mail/ui/SearchActionBarController.java120
-rw-r--r--src/com/android/mail/ui/TwoPaneController.java9
-rw-r--r--src/com/android/mail/ui/settings/GeneralPrefsFragment.java9
-rw-r--r--unified_src/com/android/mail/providers/UnifiedAccountCacheProvider.java12
61 files changed, 951 insertions, 572 deletions
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index a8dd8d764..3c5b30e2d 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -43,7 +43,8 @@
android:label="@string/app_name"
android:name=".ui.MailActivity"
android:launchMode="singleTop"
- android:theme="@style/MailActivityTheme" >
+ android:theme="@style/MailActivityTheme"
+ android:windowSoftInputMode="stateHidden">
<intent-filter >
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
@@ -58,7 +59,6 @@
<action android:name="android.intent.action.SEARCH" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
- <meta-data android:name="android.app.searchable" android:resource="@xml/searchable" />
</activity>
<activity android:name=".compose.ComposeActivity"
android:theme="@style/ComposeTheme">
@@ -159,13 +159,6 @@
<grant-uri-permission android:pathPattern=".*" />
</provider>
- <!-- The android:name is the name of the Provider class which is stored in
- UnifiedEmail, and has package name com.android.mail.providers and the class is
- called SuggestionsProvider. The authority name is specified in the MailAppProvider
- which is specific to the two apps separately. -->
- <provider android:name="com.android.mail.providers.SuggestionsProvider"
- android:authorities="com.android.mail.suggestionsprovider" />
-
<service android:name=".compose.EmptyService"/>
<!-- Widget -->
diff --git a/res/drawable-hdpi/ic_arrow_back_24dp.png b/res/drawable-hdpi/ic_arrow_back_24dp.png
new file mode 100644
index 000000000..9b5f436f6
--- /dev/null
+++ b/res/drawable-hdpi/ic_arrow_back_24dp.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_close_24dp.png b/res/drawable-hdpi/ic_close_24dp.png
new file mode 100644
index 000000000..33db9eef6
--- /dev/null
+++ b/res/drawable-hdpi/ic_close_24dp.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_history_24dp.png b/res/drawable-hdpi/ic_history_24dp.png
new file mode 100644
index 000000000..b93e92940
--- /dev/null
+++ b/res/drawable-hdpi/ic_history_24dp.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_history_holo_light.png b/res/drawable-hdpi/ic_history_holo_light.png
deleted file mode 100644
index d3feeac20..000000000
--- a/res/drawable-hdpi/ic_history_holo_light.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/ic_mic_24dp.png b/res/drawable-hdpi/ic_mic_24dp.png
new file mode 100644
index 000000000..143ccc43a
--- /dev/null
+++ b/res/drawable-hdpi/ic_mic_24dp.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_arrow_back_24dp.png b/res/drawable-mdpi/ic_arrow_back_24dp.png
new file mode 100644
index 000000000..3a5800d1e
--- /dev/null
+++ b/res/drawable-mdpi/ic_arrow_back_24dp.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_close_24dp.png b/res/drawable-mdpi/ic_close_24dp.png
new file mode 100644
index 000000000..bd39f9332
--- /dev/null
+++ b/res/drawable-mdpi/ic_close_24dp.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_history_24dp.png b/res/drawable-mdpi/ic_history_24dp.png
new file mode 100644
index 000000000..76b0a9178
--- /dev/null
+++ b/res/drawable-mdpi/ic_history_24dp.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_history_holo_light.png b/res/drawable-mdpi/ic_history_holo_light.png
deleted file mode 100644
index 2b6eec4f5..000000000
--- a/res/drawable-mdpi/ic_history_holo_light.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/ic_mic_24dp.png b/res/drawable-mdpi/ic_mic_24dp.png
new file mode 100644
index 000000000..81d0c21ad
--- /dev/null
+++ b/res/drawable-mdpi/ic_mic_24dp.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_arrow_back_24dp.png b/res/drawable-xhdpi/ic_arrow_back_24dp.png
new file mode 100644
index 000000000..73395b0ac
--- /dev/null
+++ b/res/drawable-xhdpi/ic_arrow_back_24dp.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_close_24dp.png b/res/drawable-xhdpi/ic_close_24dp.png
new file mode 100644
index 000000000..81efb7040
--- /dev/null
+++ b/res/drawable-xhdpi/ic_close_24dp.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_history_24dp.png b/res/drawable-xhdpi/ic_history_24dp.png
new file mode 100644
index 000000000..61c0bfe34
--- /dev/null
+++ b/res/drawable-xhdpi/ic_history_24dp.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_history_holo_light.png b/res/drawable-xhdpi/ic_history_holo_light.png
deleted file mode 100644
index 83d61fa68..000000000
--- a/res/drawable-xhdpi/ic_history_holo_light.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/ic_mic_24dp.png b/res/drawable-xhdpi/ic_mic_24dp.png
new file mode 100644
index 000000000..1dcf56c4e
--- /dev/null
+++ b/res/drawable-xhdpi/ic_mic_24dp.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_arrow_back_24dp.png b/res/drawable-xxhdpi/ic_arrow_back_24dp.png
new file mode 100644
index 000000000..650351d06
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_arrow_back_24dp.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_close_24dp.png b/res/drawable-xxhdpi/ic_close_24dp.png
new file mode 100644
index 000000000..0924e29a2
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_close_24dp.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_history_24dp.png b/res/drawable-xxhdpi/ic_history_24dp.png
new file mode 100644
index 000000000..4fe0a7efe
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_history_24dp.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_history_holo_light.png b/res/drawable-xxhdpi/ic_history_holo_light.png
deleted file mode 100644
index b5e82bc69..000000000
--- a/res/drawable-xxhdpi/ic_history_holo_light.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_mic_24dp.png b/res/drawable-xxhdpi/ic_mic_24dp.png
new file mode 100644
index 000000000..ce9890478
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_mic_24dp.png
Binary files differ
diff --git a/res/drawable-xxxhdpi/ic_arrow_back_24dp.png b/res/drawable-xxxhdpi/ic_arrow_back_24dp.png
new file mode 100644
index 000000000..8068c1b57
--- /dev/null
+++ b/res/drawable-xxxhdpi/ic_arrow_back_24dp.png
Binary files differ
diff --git a/res/drawable-xxxhdpi/ic_close_24dp.png b/res/drawable-xxxhdpi/ic_close_24dp.png
new file mode 100644
index 000000000..cb7a27ca8
--- /dev/null
+++ b/res/drawable-xxxhdpi/ic_close_24dp.png
Binary files differ
diff --git a/res/drawable-xxxhdpi/ic_history_24dp.png b/res/drawable-xxxhdpi/ic_history_24dp.png
new file mode 100644
index 000000000..420576b08
--- /dev/null
+++ b/res/drawable-xxxhdpi/ic_history_24dp.png
Binary files differ
diff --git a/res/drawable-xxxhdpi/ic_mic_24dp.png b/res/drawable-xxxhdpi/ic_mic_24dp.png
new file mode 100644
index 000000000..c586bb535
--- /dev/null
+++ b/res/drawable-xxxhdpi/ic_mic_24dp.png
Binary files differ
diff --git a/res/values-sw600dp-land/dimen.xml b/res/drawable/action_bar_shadow.xml
index 92359cbf0..32501171d 100644
--- a/res/values-sw600dp-land/dimen.xml
+++ b/res/drawable/action_bar_shadow.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- Copyright (C) 2012 Google Inc.
+ Copyright (C) 2014 Google Inc.
Licensed to The Android Open Source Project.
Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,6 +15,10 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<resources>
- <dimen name="search_view_width">500dip</dimen>
-</resources>
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+ <gradient
+ android:angle="270"
+ android:startColor="#3D000000"
+ android:endColor="#00000000" />
+</shape>
diff --git a/res/layout/mail_actionbar_searchview.xml b/res/layout/mail_actionbar_searchview.xml
index 730f1708a..b7bc1e662 100644
--- a/res/layout/mail_actionbar_searchview.xml
+++ b/res/layout/mail_actionbar_searchview.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- Copyright (C) 2011 Google Inc.
+ Copyright (C) 2014 Google Inc.
Licensed to The Android Open Source Project.
Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,12 +16,44 @@
limitations under the License.
-->
-<android.support.v7.widget.SearchView
+<com.android.mail.ui.MaterialSearchActionView
xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/search_layout"
- android:gravity="center_vertical"
- android:layout_height="match_parent"
+ android:id="@+id/search_actionbar_view"
android:layout_width="match_parent"
- android:hint="@string/search_hint"
- android:imeOptions="actionSearch"
- android:maxWidth="@dimen/search_view_width" />
+ android:layout_height="match_parent"
+ android:background="@android:color/white">
+
+ <ImageView
+ android:id="@+id/search_actionbar_back_button"
+ android:layout_width="@dimen/search_leading_button_width"
+ android:layout_height="match_parent"
+ android:background="?android:attr/selectableItemBackground"
+ android:src="@drawable/ic_arrow_back_24dp"
+ style="@style/SearchViewLeadingButton" />
+
+ <EditText
+ android:id="@+id/search_actionbar_query_text"
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:background="@android:color/transparent"
+ android:gravity="center_vertical"
+ android:hint="@string/search_hint"
+ android:imeOptions="actionSearch|flagNoExtractUi"
+ android:inputType="text|textNoSuggestions"
+ android:singleLine="true"
+ android:textColor="@color/search_query_text"
+ android:textColorHint="@color/search_query_hint_text"
+ android:textSize="16sp" />
+
+ <ImageView
+ android:id="@+id/search_actionbar_ending_button"
+ android:layout_width="@dimen/search_ending_button_width"
+ android:layout_height="match_parent"
+ android:background="?android:attr/selectableItemBackground"
+ android:paddingLeft="16dp"
+ android:paddingRight="16dp"
+ android:scaleType="center"
+ android:src="@drawable/ic_mic_24dp" />
+
+</com.android.mail.ui.MaterialSearchActionView> \ No newline at end of file
diff --git a/res/layout/one_pane_activity.xml b/res/layout/one_pane_activity.xml
index 478edb9a9..40072a2a8 100644
--- a/res/layout/one_pane_activity.xml
+++ b/res/layout/one_pane_activity.xml
@@ -16,7 +16,6 @@
-->
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/drawer_container"
android:layout_width="match_parent"
android:layout_height="match_parent">
@@ -27,12 +26,8 @@
android:layout_height="match_parent"
android:orientation="vertical">
- <android.support.v7.widget.Toolbar
- android:id="@+id/mail_toolbar"
- android:layout_width="match_parent"
- android:layout_height="?attr/actionBarSize"
- android:background="?attr/colorPrimary"
- app:theme="?attr/actionBarTheme" />
+ <!-- Custom toolbar/search overlay -->
+ <include layout="@layout/toolbar_with_search" />
<FrameLayout
android:layout_width="match_parent"
@@ -47,6 +42,8 @@
<include layout="@layout/floating_actions" />
+ <include layout="@layout/search_suggestion_list" />
+
</FrameLayout>
</LinearLayout>
@@ -57,4 +54,4 @@
android:layout_height="match_parent"
android:layout_gravity="start" />
-</android.support.v4.widget.DrawerLayout>
+</android.support.v4.widget.DrawerLayout> \ No newline at end of file
diff --git a/res/layout/search_suggestion_item.xml b/res/layout/search_suggestion_item.xml
new file mode 100644
index 000000000..49b0256c9
--- /dev/null
+++ b/res/layout/search_suggestion_item.xml
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2014 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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/search_suggestion_height"
+ android:orientation="vertical">
+
+ <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:gravity="center_vertical"
+ android:paddingRight="16dp">
+
+ <ImageView
+ android:id="@+id/search_overlay_item_icon"
+ android:layout_width="@dimen/search_leading_button_width"
+ android:layout_height="match_parent"
+ style="@style/SearchViewLeadingButton" />
+
+ <TextView
+ android:id="@+id/search_overlay_item_text"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:layout_weight="1"
+ android:textColor="@color/search_suggestion_item_text"
+ android:textSize="16sp" />
+
+ </LinearLayout>
+
+</LinearLayout> \ No newline at end of file
diff --git a/res/layout/search_suggestion_list.xml b/res/layout/search_suggestion_list.xml
new file mode 100644
index 000000000..d024ccfe5
--- /dev/null
+++ b/res/layout/search_suggestion_list.xml
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2014 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.
+-->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <com.android.mail.ui.MaterialSearchSuggestionsList
+ android:id="@+id/search_overlay_view"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical"
+ android:visibility="gone">
+
+ <ListView
+ android:id="@+id/search_overlay_suggestion_list"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:background="@android:color/white"
+ android:divider="@null" />
+
+ <!-- Scrim to fade the background -->
+ <View
+ android:id="@+id/search_overlay_scrim"
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_weight="1"
+ android:background="#88000000" />
+
+ </com.android.mail.ui.MaterialSearchSuggestionsList>
+
+ <!-- Search bar shadow -->
+ <View
+ android:id="@+id/search_actionbar_shadow"
+ android:layout_width="match_parent"
+ android:layout_height="7dp"
+ android:background="@drawable/action_bar_shadow"
+ android:visibility="gone" />
+</FrameLayout> \ No newline at end of file
diff --git a/res/layout/toolbar_with_search.xml b/res/layout/toolbar_with_search.xml
new file mode 100644
index 000000000..4e5abda14
--- /dev/null
+++ b/res/layout/toolbar_with_search.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2014 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.
+-->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:layout_width="match_parent"
+ android:layout_height="?attr/actionBarSize">
+
+ <android.support.v7.widget.Toolbar
+ android:id="@+id/mail_toolbar"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="?attr/colorPrimary"
+ app:theme="?attr/actionBarTheme" />
+
+ <include layout="@layout/mail_actionbar_searchview" />
+
+</FrameLayout> \ No newline at end of file
diff --git a/res/layout/two_pane_activity.xml b/res/layout/two_pane_activity.xml
index 2f8f6db6e..eb194c96c 100644
--- a/res/layout/two_pane_activity.xml
+++ b/res/layout/two_pane_activity.xml
@@ -15,49 +15,68 @@
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"
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:background="@color/tablet_background_gray">
+ android:orientation="vertical">
+ <!-- Custom toolbar/search overlay -->
+ <include layout="@layout/toolbar_with_search" />
+
+ <!-- Main content -->
<FrameLayout
- android:id="@+id/drawer"
- android:layout_width="@dimen/two_pane_drawer_width_open"
- android:layout_height="match_parent"
- android:layout_gravity="left">
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
- <include layout="@layout/drawer_fragment"
+ <com.android.mail.ui.TwoPaneLayout
+ android:id="@+id/two_pane_activity"
android:layout_width="match_parent"
- android:layout_height="match_parent" />
+ android:layout_height="match_parent"
+ android:background="@color/tablet_background_gray">
- </FrameLayout>
+ <FrameLayout
+ android:id="@+id/drawer"
+ android:layout_width="@dimen/two_pane_drawer_width_open"
+ android:layout_height="match_parent"
+ android:layout_gravity="left">
- <FrameLayout
- android:id="@+id/conversation_list_pane"
- android:layout_width="0dp"
- android:layout_height="match_parent"
- android:layout_gravity="left"
- style="@style/TwoPaneConversationList" />
-
- <com.android.mail.ui.ConversationViewFrame
- android:id="@+id/conversation_pane"
- android:layout_width="0dp"
- android:layout_height="match_parent"
- android:layout_gravity="left">
-
- <include layout="@layout/conversation_pager"
- android:layout_width="match_parent"
- android:layout_height="match_parent" />
+ <include layout="@layout/drawer_fragment"
+ 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"
+ android:layout_gravity="left"
+ style="@style/TwoPaneConversationList" />
- </com.android.mail.ui.ConversationViewFrame>
+ <com.android.mail.ui.ConversationViewFrame
+ android:id="@+id/conversation_pane"
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_gravity="left">
- <com.android.mail.ui.ConversationViewFrame
- android:id="@+id/miscellaneous_pane"
- android:layout_width="0dp"
- android:layout_height="match_parent"
- android:layout_gravity="left" />
+ <include layout="@layout/conversation_pager"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" />
- <include layout="@layout/floating_actions" />
+ </com.android.mail.ui.ConversationViewFrame>
+
+ <com.android.mail.ui.ConversationViewFrame
+ android:id="@+id/miscellaneous_pane"
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_gravity="left" />
+
+ <include layout="@layout/floating_actions" />
+
+ </com.android.mail.ui.TwoPaneLayout>
+
+ <include layout="@layout/search_suggestion_list" />
+
+ </FrameLayout>
-</com.android.mail.ui.TwoPaneLayout>
+</LinearLayout> \ No newline at end of file
diff --git a/res/menu-sw600dp-land/conversation_actions.xml b/res/menu-sw600dp-land/conversation_actions.xml
index 78325b8ce..af888ddde 100644
--- a/res/menu-sw600dp-land/conversation_actions.xml
+++ b/res/menu-sw600dp-land/conversation_actions.xml
@@ -22,8 +22,7 @@
<item android:id="@+id/search"
android:title="@string/menu_search"
app:showAsAction="always|collapseActionView"
- android:icon="@drawable/ic_menu_search"
- app:actionLayout="@layout/mail_actionbar_searchview" />
+ android:icon="@drawable/ic_menu_search" />
<item
android:id="@+id/archive"
diff --git a/res/menu-sw600dp-land/conversation_list_search_results_actions.xml b/res/menu-sw600dp-land/conversation_list_search_results_actions.xml
index 1b784bc56..1e465722d 100644
--- a/res/menu-sw600dp-land/conversation_list_search_results_actions.xml
+++ b/res/menu-sw600dp-land/conversation_list_search_results_actions.xml
@@ -21,8 +21,7 @@
<item android:id="@+id/search"
android:title="@string/menu_search"
app:showAsAction="always|collapseActionView"
- android:icon="@drawable/ic_menu_search"
- app:actionLayout="@layout/mail_actionbar_searchview" />
+ android:icon="@drawable/ic_menu_search" />
<item
android:id="@+id/delete"
diff --git a/res/menu/conversation_list_menu.xml b/res/menu/conversation_list_menu.xml
index 05568bc0d..8b7c59377 100644
--- a/res/menu/conversation_list_menu.xml
+++ b/res/menu/conversation_list_menu.xml
@@ -35,8 +35,7 @@
that supports FOLDER_SERVER_SEARCH -->
<item android:id="@+id/search" android:title="@string/menu_search"
app:showAsAction="ifRoom|collapseActionView"
- android:icon="@drawable/ic_menu_search"
- app:actionLayout="@layout/mail_actionbar_searchview" />
+ android:icon="@drawable/ic_menu_search" />
<!-- These invisible menu item are used to enable keyboard shortcuts -->
<item
diff --git a/res/menu/conversation_list_search_results_actions.xml b/res/menu/conversation_list_search_results_actions.xml
index 6708c8366..1205e9066 100644
--- a/res/menu/conversation_list_search_results_actions.xml
+++ b/res/menu/conversation_list_search_results_actions.xml
@@ -22,8 +22,7 @@
<item android:id="@+id/search"
android:title="@string/menu_search"
app:showAsAction="ifRoom|collapseActionView"
- android:icon="@drawable/ic_menu_search"
- app:actionLayout="@layout/mail_actionbar_searchview" />
+ android:icon="@drawable/ic_menu_search" />
<!-- This invisible menu item is used to map CTRL-C to the compose action -->
<item
diff --git a/res/values-ldrtl/styles-ldrtl.xml b/res/values-ldrtl/styles-ldrtl.xml
index 047db0a6e..20b69bf32 100644
--- a/res/values-ldrtl/styles-ldrtl.xml
+++ b/res/values-ldrtl/styles-ldrtl.xml
@@ -396,6 +396,13 @@
<item name="android:paddingEnd">@dimen/undo_icon_padding_end</item>
</style>
+ <style name="SearchViewLeadingButton">
+ <item name="android:layout_gravity">center_vertical</item>
+ <item name="android:paddingStart">16dp</item>
+ <item name="android:paddingEnd">32dp</item>
+ <item name="android:scaleType">center</item>
+ </style>
+
<style name="AccountItemNameStyle">
<item name="android:paddingStart">@dimen/account_item_name_start_padding</item>
<item name="android:paddingEnd">@dimen/account_item_name_end_padding</item>
diff --git a/res/values-sw600dp/themes.xml b/res/values-sw600dp/themes.xml
index 4909a9d81..d6babb92f 100644
--- a/res/values-sw600dp/themes.xml
+++ b/res/values-sw600dp/themes.xml
@@ -1,7 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
- <style name="MailActivityTheme" parent="@style/UnifiedEmailTheme.Appcompat" />
-
<!-- todo - comment out when theme exists -->
<!--<style name="ShortcutWidgetTheme" parent="@style/Theme.Appcompat.Light.Dialog.MinWidth">-->
<!--<item name="actionOverflowButtonStyle">@style/ActionBarOverflowButtonStyle</item>-->
diff --git a/res/values/colors.xml b/res/values/colors.xml
index 73f685b3f..c3834a84d 100644
--- a/res/values/colors.xml
+++ b/res/values/colors.xml
@@ -103,6 +103,9 @@
<color name="notification_icon_gmail_red">#da4336</color>
<!-- Search colors -->
+ <color name="search_query_hint_text">@color/light_gray</color>
+ <color name="search_query_text">@color/text_color_black</color>
+ <color name="search_suggestion_item_text">@color/text_color_grey</color>
<color name="search_banner_bg">#f6f6f6</color>
<color name="search_banner_text">@color/text_color_grey</color>
diff --git a/res/values/dimen.xml b/res/values/dimen.xml
index 458ae243b..6be9b7114 100644
--- a/res/values/dimen.xml
+++ b/res/values/dimen.xml
@@ -112,7 +112,6 @@
<dimen name="widget_margin_left">0dip</dimen>
<dimen name="widget_margin_right">0dip</dimen>
<dimen name="widget_margin_bottom">0dip</dimen>
- <dimen name="search_view_width">400dip</dimen>
<dimen name="wait_padding">16dp</dimen>
<integer name="chips_max_lines">2</integer>
<dimen name="tile_letter_font_size">24dp</dimen>
@@ -154,6 +153,9 @@
<dimen name="widget_senders_padding_end">16dip</dimen>
<dimen name="widget_attachment_padding_end">8dp</dimen>
+ <dimen name="search_leading_button_width">72dp</dimen>
+ <dimen name="search_ending_button_width">56dp</dimen>
+ <dimen name="search_suggestion_height">56dp</dimen>
<dimen name="search_results_padding">16dp</dimen>
<dimen name="search_banner_text_size">12sp</dimen>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 4b66b05f2..f0ce86f04 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -19,10 +19,6 @@
<!-- Names of packages and authorities that are common to all apps
and read from resources -->
- <!-- Name of the search suggestions authority that looks up recent suggestions. This
- needs to be modified in AndroidManifest.xml and res/xml/searchable.xml as well. -->
- <string name="suggestions_authority" translatable="false">com.android.mail.suggestionsprovider</string>
-
<!-- Layout tests strings -->
<string name="mock_content_provider" translatable="false">Mock Content Provider</string>
<string name="conversation_content_provider" translatable="false">Conversation Content Provider</string>
@@ -607,9 +603,11 @@
<!-- Title of the search dialog -->
<string name="search_title" translatable="false">Unified Email</string>
<!-- Shown in light gray in the Search box when no text has been entered [CHAR LIMIT=20]-->
- <string name="search_hint">Search mail</string>
+ <string name="search_hint">Search</string>
<!-- Search Results: Text for status of the search when the results are completely loaded [CHAR LIMIT=10] -->
<string name="search_results_loaded"><xliff:g id="searchCount">%1$d</xliff:g></string>
+ <!-- Voice search is not supported on this device [CHAR LIMIT=100] -->
+ <string name="voice_search_not_supported">Voice search is not supported on this device.</string>
<!-- Shown in conversation list footer when application cannot make a connection [CHAR LIMIT=20]-->
<string name="network_error">No connection</string>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 544fd24a0..4fca44e70 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -975,11 +975,11 @@
<item name="android:paddingRight">@dimen/undo_icon_padding_end</item>
</style>
- <style name="Theme.AppCompat.Translucent">
- <item name="android:windowBackground">@android:color/transparent</item>
- <item name="android:colorBackgroundCacheHint">@null</item>
- <item name="android:windowIsTranslucent">true</item>
- <item name="android:windowAnimationStyle">@android:style/Animation</item>
+ <style name="SearchViewLeadingButton">
+ <item name="android:layout_gravity">center_vertical</item>
+ <item name="android:paddingLeft">16dp</item>
+ <item name="android:paddingRight">32dp</item>
+ <item name="android:scaleType">center</item>
</style>
<style name="AccountItemNameStyle">
diff --git a/res/values/themes.xml b/res/values/themes.xml
index c2edf9f5e..7fd779e47 100644
--- a/res/values/themes.xml
+++ b/res/values/themes.xml
@@ -45,4 +45,11 @@
<item name="android:windowNoDisplay">true</item>
</style>
+ <style name="Theme.AppCompat.Translucent">
+ <item name="android:windowBackground">@android:color/transparent</item>
+ <item name="android:colorBackgroundCacheHint">@null</item>
+ <item name="android:windowIsTranslucent">true</item>
+ <item name="android:windowAnimationStyle">@android:style/Animation</item>
+ </style>
+
</resources> \ No newline at end of file
diff --git a/res/xml/searchable.xml b/res/xml/searchable.xml
deleted file mode 100644
index 5607f16cb..000000000
--- a/res/xml/searchable.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?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.
--->
-
-<!-- Override the searchSuggestAuthority in the inheriting applications to point to the
- correct package name.-->
-<searchable xmlns:android="http://schemas.android.com/apk/res/android"
- android:label="@string/search_title"
- android:hint="@string/search_hint"
- android:icon="@drawable/ic_menu_search"
- android:searchSuggestIntentAction="android.intent.action.SEARCH"
- android:searchSuggestAuthority="com.android.mail"
- android:imeOptions="actionSearch"
- android:voiceSearchMode="showVoiceSearchButton|launchRecognizer" />
diff --git a/src/com/android/mail/providers/SearchRecentSuggestionsProvider.java b/src/com/android/mail/providers/SearchRecentSuggestionsProvider.java
index 99ac4dfa4..0581869ba 100644
--- a/src/com/android/mail/providers/SearchRecentSuggestionsProvider.java
+++ b/src/com/android/mail/providers/SearchRecentSuggestionsProvider.java
@@ -18,37 +18,30 @@
package com.android.mail.providers;
import android.app.SearchManager;
-import android.content.ContentProvider;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
-import android.content.UriMatcher;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
-import android.net.Uri;
+import android.os.SystemClock;
import android.text.TextUtils;
import com.android.mail.R;
import java.util.ArrayList;
-public class SearchRecentSuggestionsProvider extends ContentProvider {
+public class SearchRecentSuggestionsProvider {
/*
* String used to delimit different parts of a query.
*/
public static final String QUERY_TOKEN_SEPARATOR = " ";
- // client-provided configuration values
- private String mAuthority;
- private int mMode;
-
// general database configuration and tables
private SQLiteOpenHelper mOpenHelper;
private static final String sDatabaseName = "suggestions.db";
private static final String sSuggestions = "suggestions";
private static final String ORDER_BY = "date DESC";
- private static final String NULL_COLUMN = "query";
// Table of database versions. Don't forget to update!
// NOTE: These version values are shifted left 8 bits (x 256) in order to create space for
@@ -56,24 +49,28 @@ public class SearchRecentSuggestionsProvider extends ContentProvider {
//
// 1 original implementation with queries, and 1 or 2 display columns
// 1->2 added UNIQUE constraint to display1 column
- private static final int DATABASE_VERSION = 2 * 256;
+ private static final int DATABASE_VERSION = 3 * 256;
/**
* This mode bit configures the database to record recent queries. <i>required</i>
- *
- * @see #setupSuggestions(String, int)
+ * @see #setupSuggestions(int)
*/
public static final int DATABASE_MODE_QUERIES = 1;
- // Uri and query support
- private static final int URI_MATCH_SUGGEST = 1;
-
- private Uri mSuggestionsUri;
- private UriMatcher mUriMatcher;
-
private String mSuggestSuggestionClause;
private String[] mSuggestionProjection;
+ protected final Context mContext;
+
+ public SearchRecentSuggestionsProvider(Context context) {
+ mContext = context;
+ mOpenHelper = new DatabaseHelper(mContext, DATABASE_VERSION);
+ }
+
+ public void cleanup() {
+ mOpenHelper.close();
+ }
+
/**
* Builds the database. This version has extra support for using the version field
* as a mode flags field, and configures the database columns depending on the mode bits
@@ -110,31 +107,20 @@ public class SearchRecentSuggestionsProvider extends ContentProvider {
* constructor. In your application or activities, you must provide the same values when
* you create the {@link android.provider.SearchRecentSuggestions} helper.
*
- * @param authority This must match the authority that you've declared in your manifest.
* @param mode You can use mode flags here to determine certain functional aspects of your
* database. Note, this value should not change from run to run, because when it does change,
* your suggestions database may be wiped.
*
* @see #DATABASE_MODE_QUERIES
*/
- protected void setupSuggestions(String authority, int mode) {
- if (TextUtils.isEmpty(authority) ||
- ((mode & DATABASE_MODE_QUERIES) == 0)) {
+ protected void setupSuggestions(int mode) {
+ if ((mode & DATABASE_MODE_QUERIES) == 0) {
throw new IllegalArgumentException();
}
- // saved values
- mAuthority = new String(authority);
- mMode = mode;
-
- // derived values
- mSuggestionsUri = Uri.parse("content://" + mAuthority + "/suggestions");
- mUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
- mUriMatcher.addURI(mAuthority, SearchManager.SUGGEST_URI_PATH_QUERY, URI_MATCH_SUGGEST);
-
// The URI of the icon that we will include on every suggestion here.
final String historicalIcon = ContentResolver.SCHEME_ANDROID_RESOURCE + "://"
- + getContext().getPackageName() + "/" + R.drawable.ic_history_holo_light;
+ + mContext.getPackageName() + "/" + R.drawable.ic_history_24dp;
mSuggestSuggestionClause = "display1 LIKE ?";
mSuggestionProjection = new String [] {
@@ -145,99 +131,6 @@ public class SearchRecentSuggestionsProvider extends ContentProvider {
};
}
- /**
- * This method is provided for use by the ContentResolver. Do not override, or directly
- * call from your own code.
- */
- @Override
- public int delete(Uri uri, String selection, String[] selectionArgs) {
- SQLiteDatabase db = mOpenHelper.getWritableDatabase();
-
- final int length = uri.getPathSegments().size();
- if (length != 1) {
- throw new IllegalArgumentException("Unknown Uri");
- }
-
- final String base = uri.getPathSegments().get(0);
- int count = 0;
- if (base.equals(sSuggestions)) {
- count = db.delete(sSuggestions, selection, selectionArgs);
- } else {
- throw new IllegalArgumentException("Unknown Uri");
- }
- getContext().getContentResolver().notifyChange(uri, null);
- return count;
- }
-
- /**
- * This method is provided for use by the ContentResolver. Do not override, or directly
- * call from your own code.
- */
- @Override
- public String getType(Uri uri) {
- if (mUriMatcher.match(uri) == URI_MATCH_SUGGEST) {
- return SearchManager.SUGGEST_MIME_TYPE;
- }
- int length = uri.getPathSegments().size();
- if (length >= 1) {
- String base = uri.getPathSegments().get(0);
- if (base.equals(sSuggestions)) {
- if (length == 1) {
- return "vnd.android.cursor.dir/suggestion";
- } else if (length == 2) {
- return "vnd.android.cursor.item/suggestion";
- }
- }
- }
- throw new IllegalArgumentException("Unknown Uri");
- }
-
- /**
- * This method is provided for use by the ContentResolver. Do not override, or directly
- * call from your own code.
- */
- @Override
- public Uri insert(Uri uri, ContentValues values) {
- SQLiteDatabase db = mOpenHelper.getWritableDatabase();
-
- int length = uri.getPathSegments().size();
- if (length < 1) {
- throw new IllegalArgumentException("Unknown Uri");
- }
- // Note: This table has on-conflict-replace semantics, so insert() may actually replace()
- long rowID = -1;
- String base = uri.getPathSegments().get(0);
- Uri newUri = null;
- if (base.equals(sSuggestions)) {
- if (length == 1) {
- rowID = db.insert(sSuggestions, NULL_COLUMN, values);
- if (rowID > 0) {
- newUri = Uri.withAppendedPath(mSuggestionsUri, String.valueOf(rowID));
- }
- }
- }
- if (rowID < 0) {
- throw new IllegalArgumentException("Unknown Uri");
- }
- getContext().getContentResolver().notifyChange(newUri, null);
- return newUri;
- }
-
- /**
- * This method is provided for use by the ContentResolver. Do not override, or directly
- * call from your own code.
- */
- @Override
- public boolean onCreate() {
- if (mAuthority == null || mMode == 0) {
- throw new IllegalArgumentException("Provider not configured");
- }
- int mWorkingDbVersion = DATABASE_VERSION + mMode;
- mOpenHelper = new DatabaseHelper(getContext(), mWorkingDbVersion);
-
- return true;
- }
-
private ArrayList<String> mFullQueryTerms;
/**
@@ -278,13 +171,8 @@ public class SearchRecentSuggestionsProvider extends ContentProvider {
mFullQueryTerms = terms;
}
- /**
- * This method is provided for use by the ContentResolver. Do not override,
- * or directly call from your own code.
- */
// TODO: Confirm no injection attacks here, or rewrite.
- @Override
- public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
+ public Cursor query(String[] projection, String selection, String[] selectionArgs,
String sortOrder) {
SQLiteDatabase db = mOpenHelper.getReadableDatabase();
@@ -300,22 +188,27 @@ public class SearchRecentSuggestionsProvider extends ContentProvider {
suggestSelection = mSuggestSuggestionClause;
}
// Suggestions are always performed with the default sort order
- // Add this to the query:
- // "select 'real_query' as SearchManager.SUGGEST_COLUMN_QUERY.
- // rest of query
- // real query will then show up in the suggestion
Cursor c = db.query(sSuggestions, createProjection(selectionArgs), suggestSelection, myArgs,
null, null, ORDER_BY, null);
- c.setNotificationUri(getContext().getContentResolver(), uri);
return c;
}
/**
- * This method is provided for use by the ContentResolver. Do not override, or directly
- * call from your own code.
+ * We are going to keep track of recent suggestions ourselves and not depend on the framework.
+ * Note that this writes to disk. DO NOT CALL FROM MAIN THREAD.
*/
- @Override
- public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
- throw new UnsupportedOperationException("Not implemented");
+ public void saveRecentQuery(String query) {
+ SQLiteDatabase db = mOpenHelper.getWritableDatabase();
+ ContentValues values = new ContentValues(3);
+ values.put("display1", query);
+ values.put("query", query);
+ values.put("date", SystemClock.elapsedRealtime());
+ // Note: This table has on-conflict-replace semantics, so insert() may actually replace()
+ db.insert(sSuggestions, null, values);
+ }
+
+ public void clearHistory() {
+ SQLiteDatabase db = mOpenHelper.getReadableDatabase();
+ db.delete(sSuggestions, null, null);
}
} \ No newline at end of file
diff --git a/src/com/android/mail/providers/SuggestionsProvider.java b/src/com/android/mail/providers/SuggestionsProvider.java
index 92c7bccf9..7efaed3f6 100644
--- a/src/com/android/mail/providers/SuggestionsProvider.java
+++ b/src/com/android/mail/providers/SuggestionsProvider.java
@@ -65,20 +65,13 @@ public class SuggestionsProvider extends SearchRecentSuggestionsProvider {
*/
static private final int MIN_QUERY_LENGTH_FOR_CONTACTS = 2;
- public SuggestionsProvider() {
- super();
+ public SuggestionsProvider(Context context) {
+ super(context);
+ setupSuggestions(MODE);
}
@Override
- public boolean onCreate() {
- final String authority = getContext().getString(R.string.suggestions_authority);
- setupSuggestions(authority, MODE);
- super.onCreate();
- return true;
- }
-
- @Override
- public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
+ public Cursor query(String[] projection, String selection, String[] selectionArgs,
String sortOrder) {
String query = selectionArgs[0];
MergeCursor mergeCursor = null;
@@ -110,7 +103,7 @@ public class SuggestionsProvider extends SearchRecentSuggestionsProvider {
ArrayList<Cursor> cursors = new ArrayList<Cursor>();
// Pass query; at this point it is either the last term OR the
// only term.
- cursors.add(super.query(uri, projection, selection, new String[] { query }, sortOrder));
+ cursors.add(super.query(projection, selection, new String[] { query }, sortOrder));
if (query.length() >= MIN_QUERY_LENGTH_FOR_CONTACTS) {
cursors.add(new ContactsCursor().query(query));
@@ -124,10 +117,8 @@ public class SuggestionsProvider extends SearchRecentSuggestionsProvider {
* Utility class to return a cursor over the contacts database
*/
private final class ContactsCursor extends MatrixCursorWithCachedColumns {
- private final Context mContext;
public ContactsCursor() {
super(CONTACTS_COLUMNS);
- mContext = getContext();
}
/**
diff --git a/src/com/android/mail/ui/AbstractActivityController.java b/src/com/android/mail/ui/AbstractActivityController.java
index d619474c8..ee2e3b104 100644
--- a/src/com/android/mail/ui/AbstractActivityController.java
+++ b/src/com/android/mail/ui/AbstractActivityController.java
@@ -46,7 +46,7 @@ import android.os.Bundle;
import android.os.Handler;
import android.os.Parcelable;
import android.os.SystemClock;
-import android.provider.SearchRecentSuggestions;
+import android.speech.RecognizerIntent;
import android.support.v4.app.ActionBarDrawerToggle;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBar;
@@ -87,7 +87,6 @@ import com.android.mail.providers.Folder;
import com.android.mail.providers.FolderWatcher;
import com.android.mail.providers.MailAppProvider;
import com.android.mail.providers.Settings;
-import com.android.mail.providers.SuggestionsProvider;
import com.android.mail.providers.UIProvider;
import com.android.mail.providers.UIProvider.AccountCapabilities;
import com.android.mail.providers.UIProvider.AccountCursorExtraKeys;
@@ -196,6 +195,7 @@ public abstract class AbstractActivityController implements ActivityController,
protected final RecentFolderList mRecentFolderList;
protected ConversationListContext mConvListContext;
protected Conversation mCurrentConversation;
+ protected MaterialSearchViewController mSearchViewController;
/**
* The hash of {@link #mCurrentConversation} in detached mode. 0 if we are not in detached mode.
*/
@@ -610,12 +610,9 @@ public abstract class AbstractActivityController implements ActivityController,
return;
}
- final boolean isSearch = mActivity.getIntent() != null
- && Intent.ACTION_SEARCH.equals(mActivity.getIntent().getAction());
- mActionBarController = isSearch ?
- new SearchActionBarController(mContext) :
- new ActionBarController(mContext);
+ mActionBarController = new ActionBarController(mContext);
mActionBarController.initialize(mActivity, this, actionBar);
+ actionBar.setShowHideAnimationEnabled(false);
// init the action bar to allow the 'up' affordance.
// any configurations that disallow 'up' should do that later.
@@ -1117,7 +1114,10 @@ public abstract class AbstractActivityController implements ActivityController,
}
break;
case CHANGE_NAVIGATION_REQUEST_CODE:
- if (resultCode == Activity.RESULT_OK && data != null) {
+ if (ViewMode.isSearchMode(mViewMode.getMode())) {
+ mActivity.setResult(resultCode, data);
+ mActivity.finish();
+ } else if (resultCode == Activity.RESULT_OK && data != null) {
// We have have received a result that indicates we need to navigate to a
// different folder or account. This happens if someone navigates using the
// drawer on the search results activity.
@@ -1132,6 +1132,17 @@ public abstract class AbstractActivityController implements ActivityController,
}
}
break;
+ case MaterialSearchViewController.VOICE_SEARCH_REQUEST_CODE:
+ if (resultCode == Activity.RESULT_OK) {
+ final ArrayList<String> matches = data.getStringArrayListExtra(
+ RecognizerIntent.EXTRA_RESULTS);
+ if (!matches.isEmpty()) {
+ // not sure how dependable the API is, but it's all we have.
+ // take the top choice.
+ mSearchViewController.onSearchPerformed(matches.get(0));
+ }
+ }
+ break;
}
}
@@ -1306,6 +1317,9 @@ public abstract class AbstractActivityController implements ActivityController,
final Intent intent = mActivity.getIntent();
+ mSearchViewController = new MaterialSearchViewController(mActivity, this, intent,
+ savedState);
+
// Immediately handle a clean launch with intent, and any state restoration
// that does not rely on restored fragments or loader data
// any state restoration that relies on those can be done later in
@@ -1596,6 +1610,9 @@ public abstract class AbstractActivityController implements ActivityController,
showEmptyDialog();
} else if (id == R.id.empty_spam) {
showEmptyDialog();
+ } else if (id == R.id.search) {
+ mSearchViewController.showSearchActionBar(
+ MaterialSearchViewController.SEARCH_VIEW_STATE_VISIBLE);
} else {
handled = false;
}
@@ -1665,6 +1682,8 @@ public abstract class AbstractActivityController implements ActivityController,
if (isDrawerEnabled() && mDrawerContainer.isDrawerVisible(mDrawerPullout)) {
mDrawerContainer.closeDrawers();
return true;
+ } else if (mSearchViewController.handleBackPress()) {
+ return true;
}
return handleBackPress();
@@ -2124,6 +2143,8 @@ public abstract class AbstractActivityController implements ActivityController,
outState.putBundle(SAVED_CONVERSATION_LIST_SCROLL_POSITIONS,
mConversationListScrollPositions);
+
+ mSearchViewController.saveState(outState);
}
/**
@@ -2141,7 +2162,8 @@ public abstract class AbstractActivityController implements ActivityController,
intent.putExtra(ConversationListContext.EXTRA_SEARCH_QUERY, query);
intent.putExtra(Utils.EXTRA_ACCOUNT, mAccount);
intent.setComponent(mActivity.getComponentName());
- mActionBarController.collapseSearch();
+ mSearchViewController.showSearchActionBar(
+ MaterialSearchViewController.SEARCH_VIEW_STATE_GONE);
// Call startActivityForResult here so we can tell if we have navigated to a different folder
// or account from search results.
mActivity.startActivityForResult(intent, CHANGE_NAVIGATION_REQUEST_CODE);
@@ -2167,6 +2189,7 @@ public abstract class AbstractActivityController implements ActivityController,
mDestroyed = true;
mHandler.removeCallbacks(mLogServiceChecker);
mLogServiceChecker = null;
+ mSearchViewController.onDestroy();
}
/**
@@ -2403,12 +2426,9 @@ public abstract class AbstractActivityController implements ActivityController,
} else if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
if (intent.hasExtra(Utils.EXTRA_ACCOUNT)) {
mHaveSearchResults = false;
- // Save this search query for future suggestions.
+ // Save this search query for future suggestions
final String query = intent.getStringExtra(SearchManager.QUERY);
- final String authority = mContext.getString(R.string.suggestions_authority);
- final SearchRecentSuggestions suggestions = new SearchRecentSuggestions(
- mContext, authority, SuggestionsProvider.MODE);
- suggestions.saveRecentQuery(query, null);
+ mSearchViewController.saveRecentQuery(query);
setAccount((Account) intent.getParcelableExtra(Utils.EXTRA_ACCOUNT));
fetchSearchFolder(intent);
if (shouldEnterSearchConvMode()) {
@@ -3239,7 +3259,8 @@ public abstract class AbstractActivityController implements ActivityController,
return;
}
if (mAccount.supportsSearch()) {
- mActionBarController.expandSearch();
+ mSearchViewController.showSearchActionBar(
+ MaterialSearchViewController.SEARCH_VIEW_STATE_VISIBLE);
} else {
Toast.makeText(mActivity.getActivityContext(), mActivity.getActivityContext()
.getString(R.string.search_unsupported), Toast.LENGTH_SHORT).show();
@@ -4559,10 +4580,9 @@ public abstract class AbstractActivityController implements ActivityController,
// TODO: Fold this into the outer class when b/16627877 is fixed
private class HomeButtonListener implements View.OnClickListener {
-
@Override
public void onClick(View v) {
onUpPressed();
}
}
-}
+} \ No newline at end of file
diff --git a/src/com/android/mail/ui/ActionBarController.java b/src/com/android/mail/ui/ActionBarController.java
index c73ebd0f5..f0b51afbe 100644
--- a/src/com/android/mail/ui/ActionBarController.java
+++ b/src/com/android/mail/ui/ActionBarController.java
@@ -17,31 +17,22 @@
package com.android.mail.ui;
-import android.app.SearchManager;
-import android.app.SearchableInfo;
import android.content.ContentResolver;
import android.content.Context;
-import android.database.Cursor;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
-import android.support.v4.view.MenuItemCompat;
import android.support.v7.app.ActionBar;
-import android.support.v7.widget.SearchView;
-import android.support.v7.widget.SearchView.OnQueryTextListener;
-import android.support.v7.widget.SearchView.OnSuggestionListener;
import android.text.TextUtils;
import android.view.Menu;
import android.view.MenuItem;
-import com.android.mail.ConversationListContext;
import com.android.mail.R;
import com.android.mail.providers.Account;
import com.android.mail.providers.AccountObserver;
import com.android.mail.providers.Conversation;
import com.android.mail.providers.Folder;
import com.android.mail.providers.FolderObserver;
-import com.android.mail.providers.SearchRecentSuggestionsProvider;
import com.android.mail.providers.UIProvider;
import com.android.mail.providers.UIProvider.AccountCapabilities;
import com.android.mail.providers.UIProvider.FolderCapabilities;
@@ -53,8 +44,7 @@ import com.android.mail.utils.Utils;
/**
* Controller to manage the various states of the {@link android.app.ActionBar}.
*/
-public class ActionBarController implements ViewMode.ModeChangeListener,
- OnQueryTextListener, OnSuggestionListener, MenuItemCompat.OnActionExpandListener {
+public class ActionBarController implements ViewMode.ModeChangeListener {
private final Context mContext;
@@ -75,8 +65,6 @@ public class ActionBarController implements ViewMode.ModeChangeListener,
*/
private Folder mFolder;
- private SearchView mSearchWidget;
- private MenuItem mSearch;
private MenuItem mEmptyTrashItem;
private MenuItem mEmptySpamItem;
@@ -117,46 +105,9 @@ public class ActionBarController implements ViewMode.ModeChangeListener,
mIsOnTablet = Utils.useTabletUI(context.getResources());
}
- public void expandSearch() {
- if (mSearch != null) {
- MenuItemCompat.expandActionView(mSearch);
- }
- }
-
- /**
- * Close the search view if it is expanded.
- */
- public void collapseSearch() {
- if (mSearch != null) {
- MenuItemCompat.collapseActionView(mSearch);
- }
- }
-
- /**
- * Get the search menu item.
- */
- protected MenuItem getSearch() {
- return mSearch;
- }
-
public boolean onCreateOptionsMenu(Menu menu) {
mEmptyTrashItem = menu.findItem(R.id.empty_trash);
mEmptySpamItem = menu.findItem(R.id.empty_spam);
- mSearch = menu.findItem(R.id.search);
-
- if (mSearch != null) {
- mSearchWidget = (SearchView) MenuItemCompat.getActionView(mSearch);
- MenuItemCompat.setOnActionExpandListener(mSearch, this);
- SearchManager searchManager = (SearchManager) mActivity.getActivityContext()
- .getSystemService(Context.SEARCH_SERVICE);
- if (searchManager != null && mSearchWidget != null) {
- SearchableInfo info = searchManager.getSearchableInfo(mActivity.getComponentName());
- mSearchWidget.setSearchableInfo(info);
- mSearchWidget.setOnQueryTextListener(this);
- mSearchWidget.setOnSuggestionListener(this);
- mSearchWidget.setIconifiedByDefault(true);
- }
- }
// the menu should be displayed if the mode is known
return getMode() != ViewMode.UNKNOWN;
@@ -245,7 +196,6 @@ public class ActionBarController implements ViewMode.ModeChangeListener,
break;
case ViewMode.CONVERSATION:
case ViewMode.AD:
- closeSearchField();
mActionBar.setDisplayHomeAsUpEnabled(true);
setEmptyMode();
break;
@@ -257,17 +207,6 @@ public class ActionBarController implements ViewMode.ModeChangeListener,
}
}
- /**
- * Close the search query entry field to avoid keyboard events, and to restore the actionbar
- * to non-search mode.
- */
- private void closeSearchField() {
- if (mSearch == null) {
- return;
- }
- mSearch.collapseActionView();
- }
-
protected int getMode() {
if (mViewModeController != null) {
return mViewModeController.getMode();
@@ -382,71 +321,6 @@ public class ActionBarController implements ViewMode.ModeChangeListener,
mActionBar.setHomeButtonEnabled(true);
}
- @Override
- public boolean onQueryTextSubmit(String query) {
- if (mSearch != null) {
- MenuItemCompat.collapseActionView(mSearch);
- mSearchWidget.setQuery("", false);
- }
- mController.executeSearch(query.trim());
- return true;
- }
-
- @Override
- public boolean onQueryTextChange(String newText) {
- return false;
- }
-
- // Next two methods are called when search suggestions are clicked.
- @Override
- public boolean onSuggestionSelect(int position) {
- return onSuggestionClick(position);
- }
-
- @Override
- public boolean onSuggestionClick(int position) {
- final Cursor c = mSearchWidget.getSuggestionsAdapter().getCursor();
- final boolean haveValidQuery = (c != null) && c.moveToPosition(position);
- if (!haveValidQuery) {
- LogUtils.d(LOG_TAG, "onSuggestionClick: Couldn't get a search query");
- // We haven't handled this query, but the default behavior will
- // leave EXTRA_ACCOUNT un-populated, leading to a crash. So claim
- // that we have handled the event.
- return true;
- }
- collapseSearch();
- // what is in the text field
- String queryText = mSearchWidget.getQuery().toString();
- // What the suggested query is
- String query = c.getString(c.getColumnIndex(SearchManager.SUGGEST_COLUMN_TEXT_1));
- // If the text the user typed in is a prefix of what is in the search
- // widget suggestion query, just take the search widget suggestion
- // query. Otherwise, it is a suffix and we want to remove matching
- // prefix portions.
- if (!TextUtils.isEmpty(queryText) && query.indexOf(queryText) != 0) {
- final int queryTokenIndex = queryText
- .lastIndexOf(SearchRecentSuggestionsProvider.QUERY_TOKEN_SEPARATOR);
- if (queryTokenIndex > -1) {
- queryText = queryText.substring(0, queryTokenIndex);
- }
- // Since we auto-complete on each token in a query, if the query the
- // user typed up until the last token is a substring of the
- // suggestion they click, make sure we don't double include the
- // query text. For example:
- // user types john, that matches john palo alto
- // User types john p, that matches john john palo alto
- // Remove the first john
- // Only do this if we have multiple query tokens.
- if (queryTokenIndex > -1 && !TextUtils.isEmpty(query) && query.contains(queryText)
- && queryText.length() < query.length()) {
- int start = query.indexOf(queryText);
- query = query.substring(0, start) + query.substring(start + queryText.length());
- }
- }
- mController.executeSearch(query.trim());
- return true;
- }
-
/**
* Uses the current state to update the current folder {@link #mFolder} and the current
* account {@link #mAccount} shown in the actionbar. Also updates the actionbar subtitle to
@@ -487,36 +361,12 @@ public class ActionBarController implements ViewMode.ModeChangeListener,
return;
}
/** True if we are changing folders. */
- final boolean changingFolders = (mFolder == null || !mFolder.equals(folder));
mFolder = folder;
setFolderAndAccount();
- final ConversationListContext listContext = mController == null ? null :
- mController.getCurrentListContext();
- if (changingFolders && !ConversationListContext.isSearchResult(listContext)) {
- closeSearchField();
- }
// make sure that we re-validate the optional menu items
validateVolatileMenuOptionVisibility();
}
- @Override
- public boolean onMenuItemActionExpand(MenuItem item) {
- // Do nothing. Required as part of the interface, we ar only interested in
- // onMenuItemActionCollapse(MenuItem).
- // Have to return true here. Unlike other callbacks, the return value here is whether
- // we want to suppress the action (rather than consume the action). We don't want to
- // suppress the action.
- return true;
- }
-
- @Override
- public boolean onMenuItemActionCollapse(MenuItem item) {
- // Have to return true here. Unlike other callbacks, the return value
- // here is whether we want to suppress the action (rather than consume the action). We
- // don't want to suppress the action.
- return true;
- }
-
/**
* Sets the actionbar mode: Pass it an integer which contains each of these values, perhaps
* OR'd together: {@link ActionBar#DISPLAY_SHOW_CUSTOM} and
diff --git a/src/com/android/mail/ui/ActivityController.java b/src/com/android/mail/ui/ActivityController.java
index fec109b4b..1b0809e2d 100644
--- a/src/com/android/mail/ui/ActivityController.java
+++ b/src/com/android/mail/ui/ActivityController.java
@@ -337,4 +337,6 @@ public interface ActivityController extends LayoutListener,
@LayoutRes int getContentViewResource();
View.OnClickListener getNavigationViewClickListener();
+
+ boolean isSearchBarShowing();
}
diff --git a/src/com/android/mail/ui/ControllableActivity.java b/src/com/android/mail/ui/ControllableActivity.java
index b9995b947..c899d34dd 100644
--- a/src/com/android/mail/ui/ControllableActivity.java
+++ b/src/com/android/mail/ui/ControllableActivity.java
@@ -24,6 +24,7 @@ import com.android.mail.bitmap.ContactResolver;
import com.android.mail.browse.ConversationListFooterView;
import com.android.mail.providers.Account;
import com.android.mail.providers.Folder;
+import com.android.mail.providers.SearchRecentSuggestionsProvider;
/**
* A controllable activity is an Activity that has a Controller attached. This activity must be
@@ -130,4 +131,6 @@ public interface ControllableActivity extends RestrictedActivity,
* Shows help to user, could be in browser or another activity.
*/
void showHelp(Account account, int viewMode);
+
+ SearchRecentSuggestionsProvider getSuggestionsProvider();
}
diff --git a/src/com/android/mail/ui/ConversationListFragment.java b/src/com/android/mail/ui/ConversationListFragment.java
index 77e286861..dd0fda701 100644
--- a/src/com/android/mail/ui/ConversationListFragment.java
+++ b/src/com/android/mail/ui/ConversationListFragment.java
@@ -722,7 +722,6 @@ public final class ConversationListFragment extends Fragment implements
// Set default navigation
if (ViewMode.isListMode(newMode)) {
mListView.setNextFocusRightId(R.id.conversation_list_view);
- mListView.requestFocus();
} else if (ViewMode.isConversationMode(newMode)) {
// This would only happen in two_pane
mListView.setNextFocusRightId(R.id.conversation_pager);
diff --git a/src/com/android/mail/ui/FolderSelectionActivity.java b/src/com/android/mail/ui/FolderSelectionActivity.java
index 96b06496f..045311449 100644
--- a/src/com/android/mail/ui/FolderSelectionActivity.java
+++ b/src/com/android/mail/ui/FolderSelectionActivity.java
@@ -39,6 +39,7 @@ import com.android.mail.bitmap.ContactResolver;
import com.android.mail.providers.Account;
import com.android.mail.providers.Folder;
import com.android.mail.providers.FolderWatcher;
+import com.android.mail.providers.SearchRecentSuggestionsProvider;
import com.android.mail.utils.LogTag;
import com.android.mail.utils.LogUtils;
import com.android.mail.utils.MailObservable;
@@ -485,6 +486,12 @@ public class FolderSelectionActivity extends ActionBarActivity implements OnClic
@Override
public void showHelp(Account account, int viewMode) {
- //Unsupported
+ // Unsupported
+ }
+
+ @Override
+ public SearchRecentSuggestionsProvider getSuggestionsProvider() {
+ // Unsupported;
+ return null;
}
}
diff --git a/src/com/android/mail/ui/MailActivity.java b/src/com/android/mail/ui/MailActivity.java
index 78507dad1..bd640c563 100644
--- a/src/com/android/mail/ui/MailActivity.java
+++ b/src/com/android/mail/ui/MailActivity.java
@@ -45,6 +45,8 @@ import com.android.mail.bitmap.ContactResolver;
import com.android.mail.compose.ComposeActivity;
import com.android.mail.providers.Account;
import com.android.mail.providers.Folder;
+import com.android.mail.providers.SearchRecentSuggestionsProvider;
+import com.android.mail.providers.SuggestionsProvider;
import com.android.mail.utils.StorageLowState;
import com.android.mail.utils.Utils;
@@ -497,6 +499,11 @@ public class MailActivity extends AbstractMailActivity implements ControllableAc
Utils.showHelp(this, account, getString(helpContext));
}
+ @Override
+ public SearchRecentSuggestionsProvider getSuggestionsProvider() {
+ return new SuggestionsProvider(this);
+ }
+
/**
* Returns the loader callback that can create a
* {@link AbstractActivityController#LOADER_WELCOME_TOUR_ACCOUNTS} followed by a
diff --git a/src/com/android/mail/ui/MaterialSearchActionView.java b/src/com/android/mail/ui/MaterialSearchActionView.java
new file mode 100644
index 000000000..80e301600
--- /dev/null
+++ b/src/com/android/mail/ui/MaterialSearchActionView.java
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2014 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.
+ */
+
+package com.android.mail.ui;
+
+import android.content.Context;
+import android.text.Editable;
+import android.text.TextWatcher;
+import android.util.AttributeSet;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputMethodManager;
+import android.widget.EditText;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import com.android.mail.R;
+
+/**
+ * Custom view for the action bar when search is displayed.
+ */
+public class MaterialSearchActionView extends LinearLayout implements TextWatcher,
+ View.OnClickListener, TextView.OnEditorActionListener {
+ private MaterialSearchViewController mController;
+ private InputMethodManager mImm;
+ private boolean mShowingClose;
+ private boolean mSupportVoice;
+
+ private View mBackButton;
+ private EditText mQueryText;
+ private ImageView mEndingButton;
+
+ public MaterialSearchActionView(Context context) {
+ super(context);
+ }
+
+ public MaterialSearchActionView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ // PUBLIC API
+ public void setController(MaterialSearchViewController controller, String initialQuery,
+ boolean supportVoice) {
+ mController = controller;
+ mQueryText.setText(initialQuery);
+ mSupportVoice = supportVoice;
+ }
+
+ public void clearSearchQuery() {
+ mQueryText.setText("");
+ }
+
+ public void focusSearchBar(boolean hasFocus) {
+ mQueryText.requestFocus();
+ if (hasFocus) {
+ mImm.showSoftInput(mQueryText, 0);
+ } else {
+ mImm.hideSoftInputFromWindow(mQueryText.getWindowToken(), 0);
+ }
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+
+ mImm = (InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
+ mBackButton = findViewById(R.id.search_actionbar_back_button);
+ mBackButton.setOnClickListener(this);
+ mQueryText = (EditText) findViewById(R.id.search_actionbar_query_text);
+ mQueryText.addTextChangedListener(this);
+ mQueryText.setOnClickListener(this);
+ mQueryText.setOnEditorActionListener(this);
+ mEndingButton = (ImageView) findViewById(R.id.search_actionbar_ending_button);
+ mEndingButton.setOnClickListener(this);
+ }
+
+ @Override
+ public void setVisibility(int visibility) {
+ if (visibility != VISIBLE) {
+ mQueryText.setText("");
+ }
+ super.setVisibility(visibility);
+ }
+
+ @Override
+ public void beforeTextChanged(CharSequence charSequence, int i, int i2, int i3) {
+ // Only care about onTextChanged
+ }
+
+ @Override
+ public void onTextChanged(CharSequence charSequence, int i, int i2, int i3) {
+ mController.onQueryTextChanged(charSequence.toString());
+ if (!mSupportVoice || charSequence.length() > 0) {
+ mShowingClose = true;
+ mEndingButton.setImageResource(R.drawable.ic_close_24dp);
+ } else {
+ mShowingClose = false;
+ mEndingButton.setImageResource(R.drawable.ic_mic_24dp);
+ }
+ }
+
+ @Override
+ public void afterTextChanged(Editable editable) {
+ // Only care about onTextChanged
+ }
+
+ @Override
+ public void onClick(View view) {
+ if (view == mBackButton) {
+ mController.onSearchCanceled();
+ mQueryText.setText("");
+ } else if (view == mEndingButton) {
+ if (mShowingClose) {
+ mQueryText.setText("");
+ mController.showSearchActionBar(
+ MaterialSearchViewController.SEARCH_VIEW_STATE_VISIBLE);
+ } else {
+ mController.onVoiceSearch();
+ }
+ } else if (view == mQueryText) {
+ mController.showSearchActionBar(MaterialSearchViewController.SEARCH_VIEW_STATE_VISIBLE);
+ }
+ }
+
+ @Override
+ public boolean onEditorAction(TextView textView, int actionId, KeyEvent keyEvent) {
+ if (actionId == EditorInfo.IME_ACTION_SEARCH) {
+ mController.onSearchPerformed(mQueryText.getText().toString());
+ }
+ return false;
+ }
+}
diff --git a/src/com/android/mail/ui/MaterialSearchSuggestionsList.java b/src/com/android/mail/ui/MaterialSearchSuggestionsList.java
new file mode 100644
index 000000000..30d469687
--- /dev/null
+++ b/src/com/android/mail/ui/MaterialSearchSuggestionsList.java
@@ -0,0 +1,214 @@
+/*
+ * Copyright (C) 2014 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.
+ */
+
+package com.android.mail.ui;
+
+import android.app.SearchManager;
+import android.content.Context;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.AsyncTask;
+import android.text.TextUtils;
+import android.util.AttributeSet;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AdapterView;
+import android.widget.ArrayAdapter;
+import android.widget.BaseAdapter;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.ListView;
+import android.widget.TextView;
+
+import com.android.mail.R;
+import com.android.mail.providers.SearchRecentSuggestionsProvider;
+import com.google.common.collect.Lists;
+
+import java.util.List;
+
+/**
+ * Custom quantum-styled search view that overlays the main activity.
+ */
+public class MaterialSearchSuggestionsList extends LinearLayout
+ implements AdapterView.OnItemClickListener, View.OnClickListener {
+ private MaterialSearchViewController mController;
+ private SearchRecentSuggestionsProvider mSuggestionsProvider;
+ private List<SuggestionItem> mSuggestions = Lists.newArrayList();
+ private String mQuery;
+
+ private View mDummyHolder;
+ private ListView mListView;
+ private QuantumSearchViewListAdapter mAdapter;
+ private QuerySuggestionsTask mQueryTask;
+
+ public MaterialSearchSuggestionsList(Context context) {
+ super(context);
+ }
+
+ public MaterialSearchSuggestionsList(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ // PUBLIC API
+ public void setController(MaterialSearchViewController controller,
+ SearchRecentSuggestionsProvider suggestionsProvider) {
+ mController = controller;
+ mSuggestionsProvider = suggestionsProvider;
+ }
+
+ public void setQuery(String query) {
+ mQuery = query;
+ if (mQueryTask != null) {
+ mQueryTask.cancel(true);
+ }
+ mQueryTask = new QuerySuggestionsTask();
+ mQueryTask.execute(query);
+ }
+
+ // PRIVATE API
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+
+ mListView = (ListView) findViewById(R.id.search_overlay_suggestion_list);
+ mListView.setOnItemClickListener(this);
+ mDummyHolder = findViewById(R.id.search_overlay_scrim);
+ mDummyHolder.setOnClickListener(this);
+
+ // set up the adapter
+ mAdapter = new QuantumSearchViewListAdapter(getContext(), R.layout.search_suggestion_item);
+ mListView.setAdapter(mAdapter);
+ }
+
+ @Override
+ public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) {
+ mController.onSearchPerformed(mSuggestions.get(position).suggestion);
+ }
+
+ @Override
+ public void onClick(View view) {
+ mController.showSearchActionBar(
+ MaterialSearchViewController.SEARCH_VIEW_STATE_ONLY_ACTIONBAR);
+ }
+
+ // Background task for querying the suggestions list
+ private class QuerySuggestionsTask extends AsyncTask<String, Void, List<SuggestionItem>> {
+ @Override
+ protected List<SuggestionItem> doInBackground(String... strings) {
+ String query = strings[0];
+ if (query == null) {
+ query = "";
+ }
+
+ Cursor c = null;
+ final List<SuggestionItem> result = Lists.newArrayList();
+ try {
+ c = mSuggestionsProvider.query(null, "query LIKE ?",
+ new String[] { query }, null);
+
+ if (c != null && c.moveToFirst()) {
+ final int textIndex = c.getColumnIndex(SearchManager.SUGGEST_COLUMN_QUERY);
+ final int iconIndex = c.getColumnIndex(SearchManager.SUGGEST_COLUMN_ICON_1);
+ do {
+ final String suggestion = c.getString(textIndex);
+ final Uri iconUri = Uri.parse(c.getString(iconIndex));
+ result.add(new SuggestionItem(suggestion, iconUri));
+ } while (c.moveToNext());
+ }
+ } finally {
+ if (c != null) {
+ c.close();
+ }
+ }
+
+ return result;
+ }
+
+ @Override
+ protected void onPostExecute(List<SuggestionItem> strings) {
+ if (!isCancelled()) {
+ // Should not have any race conditions here since we cancel the previous asynctask
+ // before starting the new one. It's unlikely that the new task finishes fast enough
+ // to get to onPostExecute when this one is in addAll.
+ mSuggestions.clear();
+ mSuggestions.addAll(strings);
+ mAdapter.notifyDataSetChanged();
+ }
+ }
+ }
+
+ private static class SuggestionItem {
+ final String suggestion;
+ final Uri icon;
+
+ public SuggestionItem(String s, Uri i) {
+ suggestion = s;
+ icon = i;
+ }
+ }
+
+ // Custom adapter to populate our list
+ private class QuantumSearchViewListAdapter extends BaseAdapter {
+ private final Context mContext;
+ private final int mResId;
+ private LayoutInflater mInflater;
+
+ public QuantumSearchViewListAdapter(Context context, int resource) {
+ super();
+ mContext = context;
+ mResId = resource;
+ }
+
+ private LayoutInflater getInflater() {
+ if (mInflater == null) {
+ mInflater = LayoutInflater.from(mContext);
+ }
+ return mInflater;
+ }
+
+ @Override
+ public int getCount() {
+ return mSuggestions.size();
+ }
+
+ @Override
+ public Object getItem(int i) {
+ return mSuggestions.get(i);
+ }
+
+ @Override
+ public long getItemId(int i) {
+ return 0;
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ if (convertView == null) {
+ convertView = getInflater().inflate(mResId, parent, false);
+ }
+
+ final SuggestionItem item = mSuggestions.get(position);
+ ((TextView) convertView.findViewById(R.id.search_overlay_item_text))
+ .setText(item.suggestion);
+ ((ImageView) convertView.findViewById(R.id.search_overlay_item_icon))
+ .setImageURI(item.icon);
+
+ return convertView;
+ }
+ }
+}
diff --git a/src/com/android/mail/ui/MaterialSearchViewController.java b/src/com/android/mail/ui/MaterialSearchViewController.java
new file mode 100644
index 000000000..d382754b7
--- /dev/null
+++ b/src/com/android/mail/ui/MaterialSearchViewController.java
@@ -0,0 +1,197 @@
+/*
+ * Copyright (C) 2014 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.
+ */
+
+package com.android.mail.ui;
+
+import android.app.Activity;
+import android.content.ActivityNotFoundException;
+import android.content.Intent;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.speech.RecognizerIntent;
+import android.view.View;
+import android.widget.Toast;
+
+import com.android.mail.ConversationListContext;
+import com.android.mail.R;
+import com.android.mail.providers.SearchRecentSuggestionsProvider;
+
+import java.util.Locale;
+
+/**
+ * Controller for interactions between ActivityController and our custom search views.
+ */
+public class MaterialSearchViewController implements ViewMode.ModeChangeListener {
+ // The controller is not in search mode. Both search action bar and the suggestion list
+ // are not visible to the user.
+ public static final int SEARCH_VIEW_STATE_GONE = 0;
+ // The controller is actively in search (as in the action bar is focused and the user can type
+ // into the search query). Both the search action bar and the suggestion list are visible.
+ public static final int SEARCH_VIEW_STATE_VISIBLE = 1;
+ // The controller is in a search ViewMode but not actively searching. This is relevant when
+ // we have to show the search actionbar on top while the user is not interacting with it.
+ public static final int SEARCH_VIEW_STATE_ONLY_ACTIONBAR = 2;
+
+ /** Code returned from voice search intent */
+ public static final int VOICE_SEARCH_REQUEST_CODE = 4;
+
+ private static final String EXTRA_VIEW_STATE = "extraSearchViewControllerViewState";
+
+ private final MailActivity mActivity;
+ private final ActivityController mController;
+
+ protected SearchRecentSuggestionsProvider mSuggestionsProvider;
+ protected View mSearchActionViewShadow;
+ protected MaterialSearchActionView mSearchActionView;
+ protected MaterialSearchSuggestionsList mSearchSuggestionList;
+
+ private int mViewMode;
+ private int mViewState;
+
+ public MaterialSearchViewController(MailActivity activity, ActivityController controller,
+ Intent intent, Bundle savedInstanceState) {
+ mActivity = activity;
+ mController = controller;
+
+ final Intent voiceIntent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
+ final boolean supportVoice =
+ voiceIntent.resolveActivity(mActivity.getPackageManager()) != null;
+
+ mSuggestionsProvider = mActivity.getSuggestionsProvider();
+ mSearchSuggestionList = (MaterialSearchSuggestionsList) mActivity.findViewById(
+ R.id.search_overlay_view);
+ mSearchSuggestionList.setController(this, mSuggestionsProvider);
+ mSearchActionView = (MaterialSearchActionView) mActivity.findViewById(
+ R.id.search_actionbar_view);
+ mSearchActionView.setController(this, intent.getStringExtra(
+ ConversationListContext.EXTRA_SEARCH_QUERY), supportVoice);
+ mSearchActionViewShadow = mActivity.findViewById(R.id.search_actionbar_shadow);
+
+ if (savedInstanceState != null && savedInstanceState.containsKey(EXTRA_VIEW_STATE)) {
+ mViewState = savedInstanceState.getInt(EXTRA_VIEW_STATE);
+ }
+
+ mActivity.getViewMode().addListener(this);
+ }
+
+ public void onDestroy() {
+ mSuggestionsProvider.cleanup();
+ mSuggestionsProvider = null;
+ mActivity.getViewMode().removeListener(this);
+ }
+
+ public void saveState(Bundle outState) {
+ outState.putInt(EXTRA_VIEW_STATE, mViewState);
+ }
+
+ @Override
+ public void onViewModeChanged(int newMode) {
+ if (mController.isSearchBarShowing()) {
+ showSearchActionBar(MaterialSearchViewController.SEARCH_VIEW_STATE_ONLY_ACTIONBAR);
+ } else if (mViewMode == 0) {
+ showSearchActionBar(mViewState);
+ } else {
+ showSearchActionBar(MaterialSearchViewController.SEARCH_VIEW_STATE_GONE);
+ }
+ mViewMode = newMode;
+ }
+
+ public boolean handleBackPress() {
+ if (mController.isSearchBarShowing() && mSearchSuggestionList.isShown()) {
+ showSearchActionBar(MaterialSearchViewController.SEARCH_VIEW_STATE_ONLY_ACTIONBAR);
+ return true;
+ } else if (mSearchActionView.isShown()) {
+ showSearchActionBar(MaterialSearchViewController.SEARCH_VIEW_STATE_GONE);
+ return true;
+ }
+ return false;
+ }
+
+ // Should use the view states specified in MaterialSearchViewController
+ public void showSearchActionBar(int state) {
+ mViewState = state;
+ switch (state) {
+ case MaterialSearchViewController.SEARCH_VIEW_STATE_ONLY_ACTIONBAR:
+ // Only actionbar is only applicable in search mode
+ if (mController.isSearchBarShowing()) {
+ mSearchActionView.setVisibility(View.VISIBLE);
+ mSearchActionViewShadow.setVisibility(View.VISIBLE);
+ mSearchSuggestionList.setVisibility(View.GONE);
+ mSearchActionView.focusSearchBar(false);
+ break;
+ }
+ // Fallthrough to setting everything invisible
+ case MaterialSearchViewController.SEARCH_VIEW_STATE_GONE:
+ mSearchActionView.setVisibility(View.GONE);
+ mSearchActionViewShadow.setVisibility(View.GONE);
+ mSearchSuggestionList.setVisibility(View.GONE);
+ mSearchActionView.focusSearchBar(false);
+ break;
+ case MaterialSearchViewController.SEARCH_VIEW_STATE_VISIBLE:
+ mSearchActionView.setVisibility(View.VISIBLE);
+ mSearchActionViewShadow.setVisibility(View.VISIBLE);
+ mSearchSuggestionList.setVisibility(View.VISIBLE);
+ mSearchActionView.focusSearchBar(true);
+ break;
+ }
+ }
+
+ public void onQueryTextChanged(String query) {
+ mSearchSuggestionList.setQuery(query);
+ }
+
+ public void onSearchCanceled() {
+ // Special case search mode
+ if (mActivity.getViewMode().isSearchMode()) {
+ mActivity.setResult(Activity.RESULT_OK);
+ mActivity.finish();
+ } else {
+ showSearchActionBar(MaterialSearchViewController.SEARCH_VIEW_STATE_GONE);
+ }
+ }
+
+ public void onSearchPerformed(String query) {
+ mSearchActionView.clearSearchQuery();
+ mController.executeSearch(query);
+ }
+
+ public void onVoiceSearch() {
+ final Intent intent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
+ intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL,
+ RecognizerIntent.LANGUAGE_MODEL_FREE_FORM);
+ intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, Locale.getDefault().getLanguage());
+
+ // Some devices do not support the voice-to-speech functionality.
+ try {
+ mActivity.startActivityForResult(intent, VOICE_SEARCH_REQUEST_CODE);
+ } catch (ActivityNotFoundException e) {
+ final String toast =
+ mActivity.getResources().getString(R.string.voice_search_not_supported);
+ Toast.makeText(mActivity, toast, Toast.LENGTH_LONG).show();
+ }
+ }
+
+ public void saveRecentQuery(final String query) {
+ new AsyncTask<Void, Void, Void>() {
+ @Override
+ protected Void doInBackground(Void... voids) {
+ mSuggestionsProvider.saveRecentQuery(query);
+ return null;
+ }
+ }.execute();
+ }
+}
diff --git a/src/com/android/mail/ui/OnePaneController.java b/src/com/android/mail/ui/OnePaneController.java
index 0d0e58dec..1030b0c11 100644
--- a/src/com/android/mail/ui/OnePaneController.java
+++ b/src/com/android/mail/ui/OnePaneController.java
@@ -174,6 +174,7 @@ public final class OnePaneController extends AbstractActivityController {
if (ViewMode.isListMode(newMode)) {
mPagerController.hide(true /* changeVisibility */);
}
+
// When we step away from the conversation mode, we don't have a current conversation
// anymore. Let's blank it out so clients calling getCurrentConversation are not misled.
if (!ViewMode.isConversationMode(newMode)) {
@@ -513,4 +514,9 @@ public final class OnePaneController extends AbstractActivityController {
public boolean isTwoPaneLandscape() {
return false;
}
+
+ @Override
+ public boolean isSearchBarShowing() {
+ return mViewMode.getMode() == ViewMode.SEARCH_RESULTS_LIST;
+ }
}
diff --git a/src/com/android/mail/ui/SearchActionBarController.java b/src/com/android/mail/ui/SearchActionBarController.java
deleted file mode 100644
index 97f1fbedc..000000000
--- a/src/com/android/mail/ui/SearchActionBarController.java
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * 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.
- */
-
-package com.android.mail.ui;
-
-import android.content.Context;
-import android.support.v4.view.MenuItemCompat;
-import android.support.v7.widget.SearchView;
-import android.text.TextUtils;
-import android.view.Menu;
-import android.view.MenuItem;
-
-import com.android.mail.ConversationListContext;
-import com.android.mail.utils.Utils;
-
-/**
- * This class is used to control the actionbar for the search activity.
- * It shows/hides various menu items based on the viewmode.
- */
-public class SearchActionBarController extends ActionBarController {
-
- public SearchActionBarController(Context context) {
- super(context);
- }
-
- @Override
- public boolean onPrepareOptionsMenu(Menu menu) {
- super.onPrepareOptionsMenu(menu);
- switch (getMode()) {
- case ViewMode.SEARCH_RESULTS_LIST:
- setSearchQueryTerm();
- mActionBar.setDisplayHomeAsUpEnabled(true);
- // And immediately give up focus to avoid keyboard popping and suggestions.
- clearSearchFocus();
- break;
- case ViewMode.SEARCH_RESULTS_CONVERSATION:
- if (mIsOnTablet) {
- setSearchQueryTerm();
- }
- mActionBar.setDisplayHomeAsUpEnabled(true);
- // And immediately give up focus to avoid keyboard popping and suggestions.
- clearSearchFocus();
- break;
- }
- return false;
- }
-
- @Override
- public void onViewModeChanged(int newMode) {
- super.onViewModeChanged(newMode);
- switch (getMode()) {
- case ViewMode.SEARCH_RESULTS_LIST:
- setEmptyMode();
- break;
- }
- }
-
- /**
- * Remove focus from the search field to avoid
- * 1. The keyboard popping in and out.
- * 2. The search suggestions shown up.
- */
- private void clearSearchFocus() {
- // Remove focus from the search action menu in search results mode so
- // the IME and the suggestions don't get in the way.
- final MenuItem search = getSearch();
- if (search != null) {
- final SearchView searchWidget = (SearchView) MenuItemCompat.getActionView(search);
- searchWidget.clearFocus();
- }
- }
-
- /**
- * Sets the query term in the text field, so the user can see what was searched for.
- */
- private void setSearchQueryTerm() {
- final MenuItem search = getSearch();
- if (search != null) {
- MenuItemCompat.expandActionView(search);
- final String query = mActivity.getIntent().getStringExtra(
- ConversationListContext.EXTRA_SEARCH_QUERY);
- final SearchView searchWidget = (SearchView) MenuItemCompat.getActionView(search);
- if (!TextUtils.isEmpty(query)) {
- searchWidget.setQuery(query, false);
- }
- }
- }
-
- @Override
- public boolean onMenuItemActionCollapse(MenuItem item) {
- // When we are in the search activity, back closes the search action mode. At that point
- // we want to quit the activity entirely.
- final int mode = getMode();
- if (mode == ViewMode.SEARCH_RESULTS_LIST
- || (Utils.showTwoPaneSearchResults(getContext())
- && mode == ViewMode.SEARCH_RESULTS_CONVERSATION)) {
-
- // When the action menu is collapsed, the search activity has finished. We should exit
- // search at this point
- mController.exitSearchMode();
- }
- // The return value here is whether we want to collapse the action mode. Since we want to
- // collapse the action mode, we should return true.
- return true;
- }
-}
diff --git a/src/com/android/mail/ui/TwoPaneController.java b/src/com/android/mail/ui/TwoPaneController.java
index 3be51ff22..bb9b4fa33 100644
--- a/src/com/android/mail/ui/TwoPaneController.java
+++ b/src/com/android/mail/ui/TwoPaneController.java
@@ -153,7 +153,7 @@ public final class TwoPaneController extends AbstractActivityController implemen
@Override
public boolean onCreate(Bundle savedState) {
mLayout = (TwoPaneLayout) mActivity.findViewById(R.id.two_pane_activity);
- if (mLayout == null) {
+ if (mLayout == null) {
// We need the layout for everything. Crash/Return early if it is null.
LogUtils.wtf(LOG_TAG, "mLayout is null!");
return false;
@@ -632,4 +632,11 @@ public final class TwoPaneController extends AbstractActivityController implemen
public boolean isTwoPaneLandscape() {
return mIsTabletLandscape;
}
+
+ @Override
+ public boolean isSearchBarShowing() {
+ final int mode = mViewMode.getMode();
+ return mode == ViewMode.SEARCH_RESULTS_LIST ||
+ (mIsTabletLandscape && mode == ViewMode.SEARCH_RESULTS_CONVERSATION);
+ }
}
diff --git a/src/com/android/mail/ui/settings/GeneralPrefsFragment.java b/src/com/android/mail/ui/settings/GeneralPrefsFragment.java
index b33ec6db7..a5e41c91e 100644
--- a/src/com/android/mail/ui/settings/GeneralPrefsFragment.java
+++ b/src/com/android/mail/ui/settings/GeneralPrefsFragment.java
@@ -27,7 +27,6 @@ import android.preference.CheckBoxPreference;
import android.preference.ListPreference;
import android.preference.Preference;
import android.preference.Preference.OnPreferenceChangeListener;
-import android.provider.SearchRecentSuggestions;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
@@ -167,12 +166,10 @@ public class GeneralPrefsFragment extends MailPreferenceFragment
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... params) {
- final String authority = context.getString(
- com.android.mail.R.string.suggestions_authority);
- final SearchRecentSuggestions suggestions =
- new SearchRecentSuggestions(context, authority,
- SuggestionsProvider.MODE);
+ final SuggestionsProvider suggestions =
+ new SuggestionsProvider(context);
suggestions.clearHistory();
+ suggestions.cleanup();
return null;
}
}.execute();
diff --git a/unified_src/com/android/mail/providers/UnifiedAccountCacheProvider.java b/unified_src/com/android/mail/providers/UnifiedAccountCacheProvider.java
index b1c131362..57f1fe8f3 100644
--- a/unified_src/com/android/mail/providers/UnifiedAccountCacheProvider.java
+++ b/unified_src/com/android/mail/providers/UnifiedAccountCacheProvider.java
@@ -24,11 +24,6 @@ public class UnifiedAccountCacheProvider extends MailAppProvider {
// The authority of our conversation provider (a forwarding provider)
// This string must match the declaration in AndroidManifest.xml
private static final String sAuthority = "com.android.mail.accountcache";
- /**
- * Authority for the suggestions provider. This is specified in AndroidManifest.xml and
- * res/xml/searchable.xml.
- */
- private static final String sSuggestionsAuthority = "com.android.mail.suggestionsprovider";
@Override
protected String getAuthority() {
@@ -36,12 +31,13 @@ public class UnifiedAccountCacheProvider extends MailAppProvider {
}
@Override
- protected Intent getNoAccountsIntent(Context context) {
+ public String getSuggestionAuthority() {
+ // UnifiedEmail does not use the default search.
return null;
}
@Override
- public String getSuggestionAuthority() {
- return sSuggestionsAuthority;
+ protected Intent getNoAccountsIntent(Context context) {
+ return null;
}
}