diff options
author | Tony Mak <tonymak@google.com> | 2016-05-16 15:43:54 +0000 |
---|---|---|
committer | android-build-merger <android-build-merger@google.com> | 2016-05-16 15:43:54 +0000 |
commit | 47037f9fef1abf08c513983e9f73e39d82bcd32d (patch) | |
tree | b669f6cf8e5e7f0b58e50abbff18f4bbca802d76 | |
parent | 3a1468db129425744078f6267d7f10ad1c13641f (diff) | |
parent | 904516077182cce4ce71a51b27a3ab418ed0f225 (diff) | |
download | android_packages_apps_Messaging-47037f9fef1abf08c513983e9f73e39d82bcd32d.tar.gz android_packages_apps_Messaging-47037f9fef1abf08c513983e9f73e39d82bcd32d.tar.bz2 android_packages_apps_Messaging-47037f9fef1abf08c513983e9f73e39d82bcd32d.zip |
Separate work and personal contacts search result
am: 9045160771
* commit '904516077182cce4ce71a51b27a3ab418ed0f225':
Separate work and personal contacts search result
Change-Id: I302cac2ded10c1945fb708996809a15cc8cebd28
-rw-r--r-- | res/layout/work_directory_header.xml | 24 | ||||
-rw-r--r-- | res/values/dimens.xml | 6 | ||||
-rw-r--r-- | res/values/strings.xml | 2 | ||||
-rw-r--r-- | res/values/styles.xml | 10 | ||||
-rw-r--r-- | src/com/android/messaging/ui/contact/ContactRecipientAdapter.java | 257 |
5 files changed, 238 insertions, 61 deletions
diff --git a/res/layout/work_directory_header.xml b/res/layout/work_directory_header.xml new file mode 100644 index 0000000..3c882f5 --- /dev/null +++ b/res/layout/work_directory_header.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 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 A`NY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<!-- Layout used for list section separators. --> +<TextView + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_height="wrap_content" + android:layout_width="match_parent" + android:text="@string/work_directory_display_name" + style="@style/DirectoryHeaderStyle" + /> diff --git a/res/values/dimens.xml b/res/values/dimens.xml index 270ea9e..5ff0eb7 100644 --- a/res/values/dimens.xml +++ b/res/values/dimens.xml @@ -188,4 +188,10 @@ <dimen name="fastscroll_preview_margin_left_right">8dp</dimen> <dimen name="fastscroll_preview_text_size">24sp</dimen> + <dimen name="directory_header_padding_start">16dp</dimen> + <dimen name="directory_header_padding_end">32dp</dimen> + <dimen name="directory_header_padding_top">18dp</dimen> + <dimen name="directory_header_padding_bottom">8dp</dimen> + <dimen name="directory_header_text_size">14sp</dimen> + </resources> diff --git a/res/values/strings.xml b/res/values/strings.xml index 58af39b..012d87f 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -973,4 +973,6 @@ <!-- The accessibility text read when the sim chooser pops up to read the current selected sim --> <string name="selected_sim_content_message"><xliff:g id="selected_sim">%s</xliff:g> selected</string> + + <string name="work_directory_display_name">Work Profile contacts</string> </resources> diff --git a/res/values/styles.xml b/res/values/styles.xml index d45f2e1..582c755 100644 --- a/res/values/styles.xml +++ b/res/values/styles.xml @@ -623,4 +623,14 @@ <item name="android:textColor">@android:color/white</item> <item name="android:gravity">center</item> </style> + <style name="DirectoryHeaderStyle"> + <item name="android:paddingLeft">@dimen/directory_header_padding_start</item> + <item name="android:paddingStart">@dimen/directory_header_padding_start</item> + <item name="android:paddingRight">@dimen/directory_header_padding_end</item> + <item name="android:paddingEnd">@dimen/directory_header_padding_end</item> + <item name="android:paddingTop">@dimen/directory_header_padding_top</item> + <item name="android:paddingBottom">@dimen/directory_header_padding_bottom</item> + <item name="android:textSize">@dimen/directory_header_text_size</item> + <item name="android:textStyle">bold</item> + </style> </resources> diff --git a/src/com/android/messaging/ui/contact/ContactRecipientAdapter.java b/src/com/android/messaging/ui/contact/ContactRecipientAdapter.java index 240f281..1d91241 100644 --- a/src/com/android/messaging/ui/contact/ContactRecipientAdapter.java +++ b/src/com/android/messaging/ui/contact/ContactRecipientAdapter.java @@ -22,12 +22,17 @@ import android.support.v4.util.Pair; import android.text.TextUtils; import android.text.util.Rfc822Token; import android.text.util.Rfc822Tokenizer; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; import android.widget.Filter; +import android.widget.TextView; import com.android.ex.chips.BaseRecipientAdapter; import com.android.ex.chips.RecipientAlternatesAdapter; import com.android.ex.chips.RecipientAlternatesAdapter.RecipientMatchCallback; import com.android.ex.chips.RecipientEntry; +import com.android.messaging.R; import com.android.messaging.util.Assert; import com.android.messaging.util.Assert.DoesNotRunOnMainThread; import com.android.messaging.util.BugleGservices; @@ -54,6 +59,18 @@ import java.util.Map; * for {@link ContactRecipientAutoCompleteView} */ public final class ContactRecipientAdapter extends BaseRecipientAdapter { + private static final int WORD_DIRECTORY_HEADER_POS_NONE = -1; + /** + * Stores the index of work directory header. + */ + private int mWorkDirectoryHeaderPos = WORD_DIRECTORY_HEADER_POS_NONE; + private final LayoutInflater mInflater; + + /** + * Type of directory entry. + */ + private static final int ENTRY_TYPE_DIRECTORY = RecipientEntry.ENTRY_TYPE_SIZE; + public ContactRecipientAdapter(final Context context, final ContactListItemView.HostInterface clivHost) { this(context, Integer.MAX_VALUE, QUERY_TYPE_PHONE, clivHost); @@ -63,6 +80,7 @@ public final class ContactRecipientAdapter extends BaseRecipientAdapter { final int queryMode, final ContactListItemView.HostInterface clivHost) { super(context, preferredMaxResultCount, queryMode); setPhotoManager(new ContactRecipientPhotoManager(context, clivHost)); + mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); } @Override @@ -82,6 +100,7 @@ public final class ContactRecipientAdapter extends BaseRecipientAdapter { * results. */ public class ContactFilter extends Filter { + // Used to sort filtered contacts when it has combined results from email and phone. private final RecipientEntryComparator mComparator = new RecipientEntryComparator(); @@ -96,8 +115,7 @@ public final class ContactRecipientAdapter extends BaseRecipientAdapter { * return the merged results. */ @DoesNotRunOnMainThread - private Pair<Cursor, Boolean> getFilteredResultsCursor(final Context context, - final String searchText) { + private CursorResult getFilteredResultsCursor(final String searchText) { Assert.isNotMainThread(); if (BugleGservices.get().getBoolean( BugleGservicesKeys.ALWAYS_AUTOCOMPLETE_EMAIL_ADDRESS, @@ -107,44 +125,35 @@ public final class ContactRecipientAdapter extends BaseRecipientAdapter { .filterPhones(getContext(), searchText).performSynchronousQuery(); final Cursor personalFilterEmailsCursor = ContactUtil .filterEmails(getContext(), searchText).performSynchronousQuery(); - Cursor resultCursor; + final Cursor personalCursor = new MergeCursor( + new Cursor[]{personalFilterEmailsCursor, personalFilterPhonesCursor}); + final CursorResult cursorResult = + new CursorResult(personalCursor, false /* sorted */); if (OsUtil.isAtLeastN()) { // Including enterprise result starting from N. final Cursor enterpriseFilterPhonesCursor = ContactUtil.filterPhonesEnterprise( getContext(), searchText).performSynchronousQuery(); final Cursor enterpriseFilterEmailsCursor = ContactUtil.filterEmailsEnterprise( getContext(), searchText).performSynchronousQuery(); - // TODO: Separating enterprise result from personal result (b/26021888) - resultCursor = new MergeCursor( - new Cursor[]{personalFilterEmailsCursor, enterpriseFilterEmailsCursor, - personalFilterPhonesCursor, enterpriseFilterPhonesCursor}); - } else { - resultCursor = new MergeCursor( - new Cursor[]{personalFilterEmailsCursor, personalFilterPhonesCursor}); + final Cursor enterpriseCursor = new MergeCursor( + new Cursor[]{enterpriseFilterEmailsCursor, + enterpriseFilterPhonesCursor}); + cursorResult.enterpriseCursor = enterpriseCursor; } - return Pair.create( - resultCursor, - false /* the merged cursor is not sorted */ - ); + return cursorResult; } else { final Cursor personalFilterDestinationCursor = ContactUtil .filterDestination(getContext(), searchText).performSynchronousQuery(); - Cursor resultCursor; - boolean sorted; + final CursorResult cursorResult = new CursorResult(personalFilterDestinationCursor, + true); if (OsUtil.isAtLeastN()) { // Including enterprise result starting from N. final Cursor enterpriseFilterDestinationCursor = ContactUtil .filterDestinationEnterprise(getContext(), searchText) .performSynchronousQuery(); - // TODO: Separating enterprise result from personal result (b/26021888) - resultCursor = new MergeCursor(new Cursor[]{personalFilterDestinationCursor, - enterpriseFilterDestinationCursor}); - sorted = false; - } else { - resultCursor = personalFilterDestinationCursor; - sorted = true; + cursorResult.enterpriseCursor = enterpriseFilterDestinationCursor; } - return Pair.create(resultCursor, sorted); + return cursorResult; } } @@ -163,44 +172,57 @@ public final class ContactRecipientAdapter extends BaseRecipientAdapter { // Query for auto-complete results, since performFiltering() is not done on the // main thread, perform the cursor loader queries directly. - final Pair<Cursor, Boolean> filteredResults = getFilteredResultsCursor(getContext(), - searchText); - final Cursor cursor = filteredResults.first; - final boolean sorted = filteredResults.second; - if (cursor != null) { - try { - final List<RecipientEntry> entries = new ArrayList<RecipientEntry>(); - // First check if the constraint is a valid SMS destination. If so, add the - // destination as a suggestion item to the drop down. - if (PhoneUtils.isValidSmsMmsDestination(searchText)) { - entries.add(ContactRecipientEntryUtils - .constructSendToDestinationEntry(searchText)); - } + final CursorResult cursorResult = getFilteredResultsCursor(searchText); + final List<RecipientEntry> entries = new ArrayList<>(); + + // First check if the constraint is a valid SMS destination. If so, add the + // destination as a suggestion item to the drop down. + if (PhoneUtils.isValidSmsMmsDestination(searchText)) { + entries.add(ContactRecipientEntryUtils + .constructSendToDestinationEntry(searchText)); + } + + // Only show work directory header if more than one result in work directory. + int workDirectoryHeaderPos = WORD_DIRECTORY_HEADER_POS_NONE; + if (cursorResult.enterpriseCursor != null + && cursorResult.enterpriseCursor.getCount() > 0) { + if (cursorResult.personalCursor != null) { + workDirectoryHeaderPos = entries.size(); + workDirectoryHeaderPos += cursorResult.personalCursor.getCount(); + } + } - HashSet<Long> existingContactIds = new HashSet<Long>(); - while (cursor.moveToNext()) { - // Make sure there's only one first-level contact (i.e. contact for which - // we show the avatar picture and name) for every contact id. - final long contactId = cursor.getLong(ContactUtil.INDEX_CONTACT_ID); - final boolean isFirstLevel = !existingContactIds.contains(contactId); - if (isFirstLevel) { - existingContactIds.add(contactId); + final Cursor[] cursors = new Cursor[]{cursorResult.personalCursor, + cursorResult.enterpriseCursor}; + for (Cursor cursor : cursors) { + if (cursor != null) { + try { + final List<RecipientEntry> tempEntries = new ArrayList<>(); + HashSet<Long> existingContactIds = new HashSet<>(); + while (cursor.moveToNext()) { + // Make sure there's only one first-level contact (i.e. contact for + // which we show the avatar picture and name) for every contact id. + final long contactId = cursor.getLong(ContactUtil.INDEX_CONTACT_ID); + final boolean isFirstLevel = !existingContactIds.contains(contactId); + if (isFirstLevel) { + existingContactIds.add(contactId); + } + tempEntries.add(ContactUtil.createRecipientEntryForPhoneQuery(cursor, + isFirstLevel)); } - entries.add(ContactUtil.createRecipientEntryForPhoneQuery(cursor, - isFirstLevel)); - } - if (!sorted) { - Collections.sort(entries, mComparator); + if (!cursorResult.isSorted) { + Collections.sort(tempEntries, mComparator); + } + entries.addAll(tempEntries); + } finally { + cursor.close(); } - results.values = entries; - results.count = 1; - - } finally { - cursor.close(); } } + results.values = new ContactReceipientFilterResult(entries, workDirectoryHeaderPos); + results.count = 1; return results; } @@ -209,16 +231,20 @@ public final class ContactRecipientAdapter extends BaseRecipientAdapter { mCurrentConstraint = constraint; clearTempEntries(); - if (results.values != null) { - @SuppressWarnings("unchecked") - final List<RecipientEntry> entries = (List<RecipientEntry>) results.values; - updateEntries(entries); - } else { - updateEntries(Collections.<RecipientEntry>emptyList()); + final ContactReceipientFilterResult contactReceipientFilterResult + = (ContactReceipientFilterResult) results.values; + if (contactReceipientFilterResult != null) { + mWorkDirectoryHeaderPos = contactReceipientFilterResult.workDirectoryPos; + if (contactReceipientFilterResult.recipientEntries != null) { + updateEntries(contactReceipientFilterResult.recipientEntries); + } else { + updateEntries(Collections.<RecipientEntry>emptyList()); + } } } private class RecipientEntryComparator implements Comparator<RecipientEntry> { + private final Collator mCollator; public RecipientEntryComparator() { @@ -272,6 +298,38 @@ public final class ContactRecipientAdapter extends BaseRecipientAdapter { } } } + + private class CursorResult { + + public final Cursor personalCursor; + + public Cursor enterpriseCursor; + + public final boolean isSorted; + + public CursorResult(Cursor personalCursor, boolean isSorted) { + this.personalCursor = personalCursor; + this.isSorted = isSorted; + } + } + + private class ContactReceipientFilterResult { + /** + * Recipient entries in all directories. + */ + public final List<RecipientEntry> recipientEntries; + + /** + * Index of row that showing work directory header. + */ + public final int workDirectoryPos; + + public ContactReceipientFilterResult(List<RecipientEntry> recipientEntries, + int workDirectoryPos) { + this.recipientEntries = recipientEntries; + this.workDirectoryPos = workDirectoryPos; + } + } } /** @@ -318,4 +376,81 @@ public final class ContactRecipientAdapter extends BaseRecipientAdapter { // report matches callback.matchesFound(recipientEntries); } + + /** + * We handle directory header here and then delegate the work of creating recipient views to + * the {@link BaseRecipientAdapter}. Please notice that we need to fix the position + * before passing to {@link BaseRecipientAdapter} because it is not aware of the existence of + * directory headers. + */ + @Override + public View getView(int position, View convertView, ViewGroup parent) { + TextView textView; + if (isDirectoryEntry(position)) { + if (convertView == null) { + textView = (TextView) mInflater.inflate(R.layout.work_directory_header, parent, + false); + } else { + textView = (TextView) convertView; + } + return textView; + } + return super.getView(fixPosition(position), convertView, parent); + } + + @Override + public RecipientEntry getItem(int position) { + if (isDirectoryEntry(position)) { + return null; + } + return super.getItem(fixPosition(position)); + } + + @Override + public int getViewTypeCount() { + return RecipientEntry.ENTRY_TYPE_SIZE + 1; + } + + @Override + public int getItemViewType(int position) { + if (isDirectoryEntry(position)) { + return ENTRY_TYPE_DIRECTORY; + } + return super.getItemViewType(fixPosition(position)); + } + + @Override + public boolean isEnabled(int position) { + if (isDirectoryEntry(position)) { + return false; + } + return super.isEnabled(fixPosition(position)); + } + + @Override + public int getCount() { + return super.getCount() + ((hasWorkDirectoryHeader()) ? 1 : 0); + } + + private boolean isDirectoryEntry(int position) { + return position == mWorkDirectoryHeaderPos; + } + + /** + * @return the position of items without counting directory headers. + */ + private int fixPosition(int position) { + if (hasWorkDirectoryHeader()) { + Assert.isTrue(position != mWorkDirectoryHeaderPos); + if (position > mWorkDirectoryHeaderPos) { + return position - 1; + } + } + return position; + } + + private boolean hasWorkDirectoryHeader() { + return mWorkDirectoryHeaderPos != WORD_DIRECTORY_HEADER_POS_NONE; + } + } |