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