Adding contact search snippets to the basic search UI
Bug: 2447965
Change-Id: I86455eabcc5153ace2eef9dd8afa5b5dc4da849d
diff --git a/res/layout-finger/contacts_list_item.xml b/res/layout-finger/contacts_list_item.xml
index 7520334..67de04d 100644
--- a/res/layout-finger/contacts_list_item.xml
+++ b/res/layout-finger/contacts_list_item.xml
@@ -33,50 +33,10 @@
android:paddingLeft="14dip"
>
- <LinearLayout android:id="@+id/right_side"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:orientation="horizontal"
- android:layout_marginLeft="11dip"
- android:layout_alignParentRight="true">
-
- <ImageView android:id="@+id/presence"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginLeft="5dip"
- android:layout_marginRight="5dip"
- android:padding="7dip"
- android:layout_gravity="center_vertical"
- android:scaleType="centerInside"
- />
-
- <LinearLayout android:id="@+id/call_view"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:orientation="horizontal">
-
- <View android:id="@+id/divider"
- android:layout_width="1px"
- android:layout_height="match_parent"
- android:layout_marginTop="5dip"
- android:layout_marginBottom="5dip"
- android:background="@drawable/divider_vertical_dark"
- />
-
- <com.android.contacts.ui.widget.DontPressWithParentImageView android:id="@+id/call_button"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:paddingLeft="14dip"
- android:paddingRight="14dip"
- android:layout_centerVertical="true"
- android:gravity="center"
- android:src="@android:drawable/sym_action_call"
- android:background="@drawable/call_background"
- />
-
- </LinearLayout>
-
- </LinearLayout>
+ <include
+ android:id="@+id/right_side"
+ layout="@layout/contacts_list_item_presence_and_action"
+ />
<TextView android:id="@+id/label"
android:layout_width="wrap_content"
@@ -97,8 +57,8 @@
android:layout_height="wrap_content"
android:layout_marginLeft="5dip"
android:layout_toRightOf="@id/label"
- android:layout_alignBaseline="@id/label"
android:layout_toLeftOf="@id/right_side"
+ android:layout_alignBaseline="@id/label"
android:layout_alignWithParentIfMissing="true"
android:singleLine="true"
@@ -109,12 +69,12 @@
<TextView android:id="@+id/name"
android:layout_width="0dip"
android:layout_height="0dip"
+ android:layout_alignParentLeft="true"
+ android:layout_marginBottom="1dip"
+ android:layout_toLeftOf="@id/right_side"
+ android:layout_alignParentTop="true"
android:layout_above="@id/label"
android:layout_alignWithParentIfMissing="true"
- android:layout_alignParentTop="true"
- android:layout_alignParentLeft="true"
- android:layout_toLeftOf="@id/right_side"
- android:layout_marginBottom="1dip"
android:singleLine="true"
android:ellipsize="marquee"
diff --git a/res/layout-finger/contacts_list_item_photo.xml b/res/layout-finger/contacts_list_item_photo.xml
index 9dfeb80..cad1bb9 100644
--- a/res/layout-finger/contacts_list_item_photo.xml
+++ b/res/layout-finger/contacts_list_item_photo.xml
@@ -33,49 +33,10 @@
android:paddingLeft="4dip"
>
- <LinearLayout android:id="@+id/right_side"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:orientation="horizontal"
- android:layout_marginLeft="11dip"
- android:layout_alignParentRight="true">
-
- <ImageView android:id="@+id/presence"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginLeft="5dip"
- android:layout_marginRight="5dip"
- android:padding="7dip"
- android:layout_gravity="center_vertical"
- android:scaleType="centerInside"
- />
-
- <LinearLayout android:id="@+id/call_view"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:orientation="horizontal">
-
- <View android:id="@+id/divider"
- android:layout_width="1px"
- android:layout_height="match_parent"
- android:layout_marginTop="5dip"
- android:layout_marginBottom="5dip"
- android:background="@drawable/divider_vertical_dark"
- />
-
- <com.android.contacts.ui.widget.DontPressWithParentImageView android:id="@+id/call_button"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:paddingLeft="14dip"
- android:paddingRight="14dip"
- android:layout_centerVertical="true"
- android:gravity="center"
- android:src="@android:drawable/sym_action_call"
- android:background="@drawable/call_background"
- />
-
- </LinearLayout>
- </LinearLayout>
+ <include
+ android:id="@+id/right_side"
+ layout="@layout/contacts_list_item_presence_and_action"
+ />
<android.widget.QuickContactBadge android:id="@+id/photo"
android:layout_alignParentLeft="true"
@@ -134,7 +95,6 @@
android:gravity="center_vertical|left"
android:textAppearance="?android:attr/textAppearanceLarge"
/>
-
</RelativeLayout>
<View android:id="@+id/list_divider"
diff --git a/res/layout-finger/contacts_list_item_photo_and_snippet.xml b/res/layout-finger/contacts_list_item_photo_and_snippet.xml
new file mode 100644
index 0000000..981b956
--- /dev/null
+++ b/res/layout-finger/contacts_list_item_photo_and_snippet.xml
@@ -0,0 +1,140 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright 2009, 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="wrap_content"
+ android:orientation="vertical"
+>
+ <include
+ android:id="@+id/header"
+ layout="@layout/list_section"
+ />
+
+ <RelativeLayout
+ android:layout_width="match_parent"
+ android:layout_height="?android:attr/listPreferredItemHeight"
+ android:paddingLeft="4dip"
+ >
+
+ <include
+ android:id="@+id/right_side"
+ layout="@layout/contacts_list_item_presence_and_action"
+ />
+
+ <android.widget.QuickContactBadge android:id="@+id/photo"
+ android:layout_alignParentLeft="true"
+ android:layout_centerVertical="true"
+ android:layout_marginRight="8dip"
+ style="?android:attr/quickContactBadgeStyleWindowMedium"
+ />
+
+ <ImageView android:id="@+id/noQuickContactPhoto"
+ android:layout_alignParentLeft="true"
+ android:layout_centerVertical="true"
+ android:layout_marginRight="8dip"
+ android:background="@null"
+ style="?android:attr/quickContactBadgeStyleWindowMedium"
+ />
+
+ <TextView android:id="@+id/label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_toRightOf="@id/photo"
+ android:layout_alignParentBottom="true"
+ android:layout_marginBottom="3dip"
+ android:layout_marginTop="-7dip"
+
+ android:singleLine="true"
+ android:ellipsize="marquee"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textStyle="bold"
+ />
+
+ <TextView android:id="@+id/data"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="5dip"
+ android:layout_toRightOf="@id/label"
+ android:layout_toLeftOf="@id/right_side"
+ android:layout_alignBaseline="@id/label"
+ android:layout_alignWithParentIfMissing="true"
+
+ android:singleLine="true"
+ android:ellipsize="marquee"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ />
+
+ <RelativeLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_toRightOf="@id/photo"
+ android:layout_toLeftOf="@id/right_side"
+ android:layout_above="@id/label"
+ android:layout_alignParentTop="true"
+ android:layout_alignWithParentIfMissing="true"
+ android:gravity="center_vertical|left"
+ >
+
+ <TextView android:id="@+id/name"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentTop="true"
+
+ android:singleLine="true"
+ android:ellipsize="marquee"
+ android:textAppearance="?android:attr/textAppearanceLarge"
+ />
+
+ <TextView android:id="@+id/snippet_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/name"
+ android:layout_alignWithParentIfMissing="true"
+ android:layout_marginTop="-5dip"
+ android:layout_marginBottom="3dip"
+
+ android:singleLine="true"
+ android:ellipsize="marquee"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ />
+
+ <TextView android:id="@+id/snippet_data"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_toRightOf="@id/snippet_label"
+ android:layout_alignBaseline="@id/snippet_label"
+ android:layout_marginLeft="5dip"
+ android:layout_alignWithParentIfMissing="true"
+
+ android:singleLine="true"
+ android:ellipsize="marquee"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textStyle="bold"
+ />
+
+ </RelativeLayout>
+ </RelativeLayout>
+
+ <View android:id="@+id/list_divider"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:background="@*android:drawable/divider_horizontal_dark_opaque"
+ />
+</LinearLayout>
diff --git a/res/layout-finger/contacts_list_item_presence_and_action.xml b/res/layout-finger/contacts_list_item_presence_and_action.xml
new file mode 100644
index 0000000..80b275f
--- /dev/null
+++ b/res/layout-finger/contacts_list_item_presence_and_action.xml
@@ -0,0 +1,64 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright 2010, 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="wrap_content"
+ android:layout_height="match_parent"
+ android:orientation="horizontal"
+ android:layout_marginLeft="11dip"
+ android:layout_alignParentRight="true">
+
+ <ImageView android:id="@+id/presence"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="5dip"
+ android:layout_marginRight="5dip"
+ android:padding="7dip"
+ android:layout_gravity="center_vertical"
+ android:scaleType="centerInside"
+ />
+
+ <LinearLayout android:id="@+id/call_view"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:orientation="horizontal">
+
+ <View android:id="@+id/divider"
+ android:layout_width="1px"
+ android:layout_height="match_parent"
+ android:layout_marginTop="5dip"
+ android:layout_marginBottom="5dip"
+ android:background="@drawable/divider_vertical_dark"
+ />
+
+ <view
+ class="com.android.contacts.ui.widget.DontPressWithParentImageView"
+ android:id="@+id/call_button"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:paddingLeft="14dip"
+ android:paddingRight="14dip"
+ android:layout_centerVertical="true"
+ android:gravity="center"
+ android:src="@android:drawable/sym_action_call"
+ android:background="@drawable/call_background"
+ />
+
+ </LinearLayout>
+</LinearLayout>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index d4b093a..a53edb7 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -1100,4 +1100,10 @@
<!-- Button displayed underneath the list of filtered visible contacts -->
<string name="search_for_all_contacts">Search for all contacts</string>
+ <!-- Data type: organization -->
+ <string name="organization">Company</string>
+
+ <!-- Data type: nickname -->
+ <string name="nickname">Nickname</string>
+
</resources>
diff --git a/src/com/android/contacts/ContactsListActivity.java b/src/com/android/contacts/ContactsListActivity.java
index 9dae6c8..8ca53cb 100644
--- a/src/com/android/contacts/ContactsListActivity.java
+++ b/src/com/android/contacts/ContactsListActivity.java
@@ -44,6 +44,7 @@
import android.content.res.Resources;
import android.database.CharArrayBuffer;
import android.database.Cursor;
+import android.database.DatabaseUtils;
import android.database.MatrixCursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
@@ -71,7 +72,10 @@
import android.provider.ContactsContract.Intents;
import android.provider.ContactsContract.Presence;
import android.provider.ContactsContract.RawContacts;
+import android.provider.ContactsContract.SearchSnippetColumns;
import android.provider.ContactsContract.CommonDataKinds.Email;
+import android.provider.ContactsContract.CommonDataKinds.Nickname;
+import android.provider.ContactsContract.CommonDataKinds.Organization;
import android.provider.ContactsContract.CommonDataKinds.Phone;
import android.provider.ContactsContract.CommonDataKinds.Photo;
import android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
@@ -295,8 +299,24 @@
Contacts.CONTACT_PRESENCE, // 6
Contacts.PHOTO_ID, // 7
Contacts.LOOKUP_KEY, // 8
- // email lookup doesn't included HAS_PHONE_NUMBER OR LOOKUP_KEY in projection
+ // email lookup doesn't included HAS_PHONE_NUMBER in projection
};
+
+ static final String[] CONTACTS_SUMMARY_FILTER_PROJECTION = new String[] {
+ Contacts._ID, // 0
+ Contacts.DISPLAY_NAME_PRIMARY, // 1
+ Contacts.DISPLAY_NAME_ALTERNATIVE, // 2
+ Contacts.SORT_KEY_PRIMARY, // 3
+ Contacts.STARRED, // 4
+ Contacts.TIMES_CONTACTED, // 5
+ Contacts.CONTACT_PRESENCE, // 6
+ Contacts.PHOTO_ID, // 7
+ Contacts.LOOKUP_KEY, // 8
+ Contacts.HAS_PHONE_NUMBER, // 9
+ SearchSnippetColumns.SNIPPET_MIMETYPE, // 10
+ SearchSnippetColumns.SNIPPET_DATA, // 11
+ };
+
static final String[] LEGACY_PEOPLE_PROJECTION = new String[] {
People._ID, // 0
People.DISPLAY_NAME, // 1
@@ -316,6 +336,8 @@
static final int SUMMARY_PHOTO_ID_COLUMN_INDEX = 7;
static final int SUMMARY_LOOKUP_KEY_COLUMN_INDEX = 8;
static final int SUMMARY_HAS_PHONE_COLUMN_INDEX = 9;
+ static final int SUMMARY_SNIPPET_MIMETYPE_COLUMN_INDEX = 10;
+ static final int SUMMARY_SNIPPET_DATA_COLUMN_INDEX = 11;
static final String[] PHONES_PROJECTION = new String[] {
Phone._ID, //0
@@ -408,6 +430,8 @@
private boolean mSearchMode;
private boolean mShowNumberOfContacts;
+ private boolean mShowSearchSnippets;
+
private String mInitialFilter;
private static final String CLAUSE_ONLY_VISIBLE = Contacts.IN_VISIBLE_GROUP + "=1";
@@ -526,6 +550,7 @@
// context for the search queries.
if (UI.FILTER_CONTACTS_ACTION.equals(action)) {
mSearchMode = true;
+ mShowSearchSnippets = true;
Bundle extras = intent.getExtras();
if (extras != null) {
mInitialFilter = extras.getString(UI.FILTER_TEXT_EXTRA_KEY);
@@ -656,6 +681,7 @@
} else {
// Otherwise handle the more normal search case
mMode = MODE_QUERY;
+ mShowSearchSnippets = true;
mInitialFilter = getIntent().getStringExtra(SearchManager.QUERY);
}
} else if (ACTION_SEARCH_FOR_SHORTCUT.equals(action)) {
@@ -1980,14 +2006,18 @@
case MODE_STREQUENT:
case MODE_FREQUENT:
case MODE_STARRED:
- case MODE_QUERY:
- case MODE_QUERY_PICK:
case MODE_DEFAULT:
case MODE_INSERT_OR_EDIT_CONTACT:
case MODE_GROUP:
case MODE_PICK_CONTACT:
case MODE_PICK_OR_CREATE_CONTACT: {
- return CONTACTS_SUMMARY_PROJECTION;
+ return mSearchMode
+ ? CONTACTS_SUMMARY_FILTER_PROJECTION
+ : CONTACTS_SUMMARY_PROJECTION;
+ }
+ case MODE_QUERY:
+ case MODE_QUERY_PICK: {
+ return CONTACTS_SUMMARY_FILTER_PROJECTION;
}
case MODE_LEGACY_PICK_PERSON:
case MODE_LEGACY_PICK_OR_CREATE_PERSON: {
@@ -2065,11 +2095,17 @@
}
private Uri getContactFilterUri(String filter) {
+ Uri baseUri;
if (!TextUtils.isEmpty(filter)) {
- return buildSectionIndexerUri(
- Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI, Uri.encode(filter)));
+ baseUri = Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI, Uri.encode(filter));
} else {
- return CONTACTS_CONTENT_URI_WITH_LETTER_COUNTS;
+ baseUri = Contacts.CONTENT_URI;
+ }
+
+ if (mAdapter.getDisplaySectionHeadersEnabled()) {
+ return buildSectionIndexerUri(baseUri);
+ } else {
+ return baseUri;
}
}
@@ -2443,7 +2479,6 @@
cursor = activity.getShowAllContactsLabelCursor(CONTACTS_SUMMARY_PROJECTION);
}
-// activity.setTextFilter(null);
activity.mAdapter.changeCursor(cursor);
// Now that the cursor is populated again, it's possible to restore the list state
@@ -2467,6 +2502,8 @@
public CharArrayBuffer nameBuffer = new CharArrayBuffer(128);
public TextView labelView;
public TextView dataView;
+ public TextView snippetLabelView;
+ public TextView snippetDataView;
public CharArrayBuffer dataBuffer = new CharArrayBuffer(128);
public ImageView presenceView;
public QuickContactBadge photoView;
@@ -2531,7 +2568,11 @@
if ((mMode & MODE_MASK_SHOW_PHOTOS) == MODE_MASK_SHOW_PHOTOS) {
mDisplayPhotos = true;
- setViewResource(R.layout.contacts_list_item_photo);
+ if (mShowSearchSnippets) {
+ setViewResource(R.layout.contacts_list_item_photo_and_snippet);
+ } else {
+ setViewResource(R.layout.contacts_list_item_photo);
+ }
}
}
@@ -2757,6 +2798,9 @@
}
cache.nonQuickContactPhotoView = (ImageView) view.findViewById(R.id.noQuickContactPhoto);
cache.textWithHighlighting = mHighlightingAnimation.createTextWithHighlighting();
+ cache.snippetLabelView = (TextView)view.findViewById(R.id.snippet_label);
+ cache.snippetDataView = (TextView)view.findViewById(R.id.snippet_data);
+
view.setTag(cache);
return view;
}
@@ -2876,6 +2920,29 @@
presenceView.setVisibility(View.GONE);
}
+ if (mShowSearchSnippets) {
+ boolean showSnippet = false;
+ String snippetMimeType = cursor.getString(SUMMARY_SNIPPET_MIMETYPE_COLUMN_INDEX);
+ String snippetValue = cursor.getString(SUMMARY_SNIPPET_DATA_COLUMN_INDEX);
+ if (!TextUtils.isEmpty(snippetValue)) {
+ if (Email.CONTENT_ITEM_TYPE.equals(snippetMimeType)) {
+ cache.snippetLabelView.setText(R.string.email);
+ cache.snippetDataView.setText(snippetValue);
+ showSnippet = true;
+ } else if (Organization.CONTENT_ITEM_TYPE.equals(snippetMimeType)) {
+ cache.snippetLabelView.setText(R.string.organization);
+ cache.snippetDataView.setText(snippetValue);
+ showSnippet = true;
+ } else if (Nickname.CONTENT_ITEM_TYPE.equals(snippetMimeType)) {
+ cache.snippetLabelView.setText(R.string.nickname);
+ cache.snippetDataView.setText(snippetValue);
+ showSnippet = true;
+ }
+ }
+ cache.snippetLabelView.setVisibility(showSnippet ? View.VISIBLE : View.GONE);
+ cache.snippetDataView.setVisibility(showSnippet ? View.VISIBLE : View.GONE);
+ }
+
if (!displayAdditionalData) {
cache.dataView.setVisibility(View.GONE);
cache.labelView.setVisibility(View.GONE);