1 /* 2 * Copyright (C) 2015 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.android.messaging.ui.contact; 17 18 import android.content.Context; 19 import android.graphics.drawable.StateListDrawable; 20 import android.net.Uri; 21 import androidx.core.text.BidiFormatter; 22 import androidx.core.text.TextDirectionHeuristicsCompat; 23 import android.view.LayoutInflater; 24 import android.view.View; 25 import android.view.ViewGroup; 26 import android.widget.ImageView; 27 28 import com.android.ex.chips.DropdownChipLayouter; 29 import com.android.ex.chips.RecipientEntry; 30 import com.android.messaging.R; 31 import com.android.messaging.datamodel.data.ContactListItemData; 32 import com.android.messaging.datamodel.data.ParticipantData; 33 import com.android.messaging.ui.ContactIconView; 34 import com.android.messaging.util.Assert; 35 import com.android.messaging.util.AvatarUriUtil; 36 import com.android.messaging.util.ContactRecipientEntryUtils; 37 import com.android.messaging.util.ContactUtil; 38 39 /** 40 * An implementation for {@link DropdownChipLayouter}. Layouts the dropdown 41 * list in the ContactRecipientAutoCompleteView in Material style. 42 */ 43 public class ContactDropdownLayouter extends DropdownChipLayouter { 44 private final ContactListItemView.HostInterface mClivHostInterface; 45 ContactDropdownLayouter(final LayoutInflater inflater, final Context context, final ContactListItemView.HostInterface clivHostInterface)46 public ContactDropdownLayouter(final LayoutInflater inflater, final Context context, 47 final ContactListItemView.HostInterface clivHostInterface) { 48 super(inflater, context); 49 mClivHostInterface = new ContactListItemView.HostInterface() { 50 51 @Override 52 public void onContactListItemClicked(final ContactListItemData item, 53 final ContactListItemView view) { 54 // The chips UI will handle auto-complete item click events, so No-op here. 55 } 56 57 @Override 58 public boolean isContactSelected(final ContactListItemData item) { 59 // In chips drop down we don't show any selected checkmark per design. 60 return false; 61 } 62 }; 63 } 64 65 /** 66 * Bind a drop down view to a RecipientEntry. We'd like regular dropdown items (BASE_RECIPIENT) 67 * to behave the same as regular ContactListItemViews, while using the chips library's 68 * item styling for alternates dropdown items (happens when you click on a chip). 69 */ 70 @Override bindView(final View convertView, final ViewGroup parent, final RecipientEntry entry, final int position, AdapterType type, final String substring, final StateListDrawable deleteDrawable)71 public View bindView(final View convertView, final ViewGroup parent, final RecipientEntry entry, 72 final int position, AdapterType type, final String substring, 73 final StateListDrawable deleteDrawable) { 74 if (type != AdapterType.BASE_RECIPIENT) { 75 if (type == AdapterType.SINGLE_RECIPIENT) { 76 // Treat single recipients the same way as alternates. The base implementation of 77 // single recipients would try to simplify the destination by tokenizing. We'd 78 // like to always show the full destination address per design request. 79 type = AdapterType.RECIPIENT_ALTERNATES; 80 } 81 return super.bindView(convertView, parent, entry, position, type, substring, 82 deleteDrawable); 83 } 84 85 // Default to show all the information 86 // RTL : To format contact name and detail if they happen to be phone numbers. 87 final BidiFormatter bidiFormatter = BidiFormatter.getInstance(); 88 final String displayName = bidiFormatter.unicodeWrap( 89 ContactRecipientEntryUtils.getDisplayNameForContactList(entry), 90 TextDirectionHeuristicsCompat.LTR); 91 final String destination = bidiFormatter.unicodeWrap( 92 ContactRecipientEntryUtils.formatDestination(entry), 93 TextDirectionHeuristicsCompat.LTR); 94 final View itemView = reuseOrInflateView(convertView, parent, type); 95 96 // Bold the string that is matched. 97 final CharSequence[] styledResults = 98 getStyledResults(substring, displayName, destination); 99 100 Assert.isTrue(itemView instanceof ContactListItemView); 101 final ContactListItemView contactListItemView = (ContactListItemView) itemView; 102 contactListItemView.setImageClickHandlerDisabled(true); 103 boolean isWorkContact = ContactUtil.isEnterpriseContactId(entry.getContactId()); 104 contactListItemView.bind(entry, styledResults[0], styledResults[1], 105 mClivHostInterface, (type == AdapterType.SINGLE_RECIPIENT), isWorkContact); 106 return itemView; 107 } 108 109 @Override bindIconToView(boolean showImage, RecipientEntry entry, ImageView view, AdapterType type)110 protected void bindIconToView(boolean showImage, RecipientEntry entry, ImageView view, 111 AdapterType type) { 112 if (showImage && view instanceof ContactIconView) { 113 final ContactIconView contactView = (ContactIconView) view; 114 // These show contact cards by default, but that isn't what we want here 115 contactView.setImageClickHandlerDisabled(true); 116 final Uri avatarUri = AvatarUriUtil.createAvatarUri( 117 ParticipantData.getFromRecipientEntry(entry)); 118 contactView.setImageResourceUri(avatarUri); 119 } else { 120 super.bindIconToView(showImage, entry, view, type); 121 } 122 } 123 124 @Override getItemLayoutResId(AdapterType type)125 protected int getItemLayoutResId(AdapterType type) { 126 switch (type) { 127 case BASE_RECIPIENT: 128 return R.layout.contact_list_item_view; 129 case RECIPIENT_ALTERNATES: 130 return R.layout.chips_alternates_dropdown_item; 131 default: 132 return R.layout.chips_alternates_dropdown_item; 133 } 134 } 135 136 @Override getAlternateItemLayoutResId(AdapterType type)137 protected int getAlternateItemLayoutResId(AdapterType type) { 138 return getItemLayoutResId(type); 139 } 140 } 141