1 /* 2 * Copyright (C) 2016 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 17 package com.android.dialer.app.list; 18 19 import android.content.Context; 20 import android.content.res.Resources; 21 import android.database.Cursor; 22 import android.graphics.drawable.Drawable; 23 import android.support.v4.content.ContextCompat; 24 import android.telephony.PhoneNumberUtils; 25 import android.text.BidiFormatter; 26 import android.text.TextDirectionHeuristics; 27 import android.view.View; 28 import android.view.ViewGroup; 29 import com.android.contacts.common.list.ContactListItemView; 30 import com.android.contacts.common.list.PhoneNumberListAdapter; 31 import com.android.contacts.common.util.ContactDisplayUtils; 32 import com.android.dialer.app.R; 33 import com.android.dialer.location.GeoUtil; 34 import com.android.dialer.phonenumberutil.PhoneNumberHelper; 35 36 /** 37 * {@link PhoneNumberListAdapter} with the following added shortcuts, that are displayed as list 38 * items: 1) Directly calling the phone number query 2) Adding the phone number query to a contact 39 * 40 * <p>These shortcuts can be enabled or disabled to toggle whether or not they show up in the list. 41 */ 42 public class DialerPhoneNumberListAdapter extends PhoneNumberListAdapter { 43 44 public static final int SHORTCUT_INVALID = -1; 45 public static final int SHORTCUT_DIRECT_CALL = 0; 46 public static final int SHORTCUT_CREATE_NEW_CONTACT = 1; 47 public static final int SHORTCUT_ADD_TO_EXISTING_CONTACT = 2; 48 public static final int SHORTCUT_SEND_SMS_MESSAGE = 3; 49 public static final int SHORTCUT_MAKE_VIDEO_CALL = 4; 50 public static final int SHORTCUT_BLOCK_NUMBER = 5; 51 public static final int SHORTCUT_COUNT = 6; 52 53 private final boolean[] shortcutEnabled = new boolean[SHORTCUT_COUNT]; 54 private final BidiFormatter bidiFormatter = BidiFormatter.getInstance(); 55 private final String countryIso; 56 57 private String formattedQueryString; 58 59 public DialerPhoneNumberListAdapter(Context context) { 60 super(context); 61 62 countryIso = GeoUtil.getCurrentCountryIso(context); 63 } 64 65 @Override 66 public int getCount() { 67 return super.getCount() + getShortcutCount(); 68 } 69 70 /** @return The number of enabled shortcuts. Ranges from 0 to a maximum of SHORTCUT_COUNT */ 71 public int getShortcutCount() { 72 int count = 0; 73 for (int i = 0; i < shortcutEnabled.length; i++) { 74 if (shortcutEnabled[i]) { 75 count++; 76 } 77 } 78 return count; 79 } 80 81 public void disableAllShortcuts() { 82 for (int i = 0; i < shortcutEnabled.length; i++) { 83 shortcutEnabled[i] = false; 84 } 85 } 86 87 @Override 88 public int getItemViewType(int position) { 89 final int shortcut = getShortcutTypeFromPosition(position); 90 if (shortcut >= 0) { 91 // shortcutPos should always range from 1 to SHORTCUT_COUNT 92 return super.getViewTypeCount() + shortcut; 93 } else { 94 return super.getItemViewType(position); 95 } 96 } 97 98 @Override 99 public int getViewTypeCount() { 100 // Number of item view types in the super implementation + 2 for the 2 new shortcuts 101 return super.getViewTypeCount() + SHORTCUT_COUNT; 102 } 103 104 @Override 105 public View getView(int position, View convertView, ViewGroup parent) { 106 final int shortcutType = getShortcutTypeFromPosition(position); 107 if (shortcutType >= 0) { 108 if (convertView != null) { 109 assignShortcutToView((ContactListItemView) convertView, shortcutType); 110 return convertView; 111 } else { 112 final ContactListItemView v = 113 new ContactListItemView(getContext(), null, mIsImsVideoEnabled); 114 assignShortcutToView(v, shortcutType); 115 return v; 116 } 117 } else { 118 return super.getView(position, convertView, parent); 119 } 120 } 121 122 @Override 123 protected ContactListItemView newView( 124 Context context, int partition, Cursor cursor, int position, ViewGroup parent) { 125 final ContactListItemView view = super.newView(context, partition, cursor, position, parent); 126 127 view.setSupportVideoCallIcon(mIsImsVideoEnabled); 128 return view; 129 } 130 131 /** 132 * @param position The position of the item 133 * @return The enabled shortcut type matching the given position if the item is a shortcut, -1 134 * otherwise 135 */ 136 public int getShortcutTypeFromPosition(int position) { 137 int shortcutCount = position - super.getCount(); 138 if (shortcutCount >= 0) { 139 // Iterate through the array of shortcuts, looking only for shortcuts where 140 // mShortcutEnabled[i] is true 141 for (int i = 0; shortcutCount >= 0 && i < shortcutEnabled.length; i++) { 142 if (shortcutEnabled[i]) { 143 shortcutCount--; 144 if (shortcutCount < 0) { 145 return i; 146 } 147 } 148 } 149 throw new IllegalArgumentException( 150 "Invalid position - greater than cursor count " + " but not a shortcut."); 151 } 152 return SHORTCUT_INVALID; 153 } 154 155 @Override 156 public boolean isEmpty() { 157 return getShortcutCount() == 0 && super.isEmpty(); 158 } 159 160 @Override 161 public boolean isEnabled(int position) { 162 final int shortcutType = getShortcutTypeFromPosition(position); 163 if (shortcutType >= 0) { 164 return true; 165 } else { 166 return super.isEnabled(position); 167 } 168 } 169 170 private void assignShortcutToView(ContactListItemView v, int shortcutType) { 171 final CharSequence text; 172 final Drawable drawable; 173 final Resources resources = getContext().getResources(); 174 final String number = getFormattedQueryString(); 175 switch (shortcutType) { 176 case SHORTCUT_DIRECT_CALL: 177 text = 178 ContactDisplayUtils.getTtsSpannedPhoneNumber( 179 resources, 180 R.string.search_shortcut_call_number, 181 bidiFormatter.unicodeWrap(number, TextDirectionHeuristics.LTR)); 182 drawable = ContextCompat.getDrawable(getContext(), R.drawable.quantum_ic_call_vd_theme_24); 183 break; 184 case SHORTCUT_CREATE_NEW_CONTACT: 185 text = resources.getString(R.string.search_shortcut_create_new_contact); 186 drawable = 187 ContextCompat.getDrawable(getContext(), R.drawable.quantum_ic_person_add_vd_theme_24); 188 drawable.setAutoMirrored(true); 189 break; 190 case SHORTCUT_ADD_TO_EXISTING_CONTACT: 191 text = resources.getString(R.string.search_shortcut_add_to_contact); 192 drawable = 193 ContextCompat.getDrawable(getContext(), R.drawable.quantum_ic_person_add_vd_theme_24); 194 break; 195 case SHORTCUT_SEND_SMS_MESSAGE: 196 text = resources.getString(R.string.search_shortcut_send_sms_message); 197 drawable = 198 ContextCompat.getDrawable(getContext(), R.drawable.quantum_ic_message_vd_theme_24); 199 break; 200 case SHORTCUT_MAKE_VIDEO_CALL: 201 text = resources.getString(R.string.search_shortcut_make_video_call); 202 drawable = 203 ContextCompat.getDrawable(getContext(), R.drawable.quantum_ic_videocam_vd_theme_24); 204 break; 205 case SHORTCUT_BLOCK_NUMBER: 206 text = resources.getString(R.string.search_shortcut_block_number); 207 drawable = 208 ContextCompat.getDrawable(getContext(), R.drawable.ic_not_interested_googblue_24dp); 209 break; 210 default: 211 throw new IllegalArgumentException("Invalid shortcut type"); 212 } 213 v.setDrawable(drawable); 214 v.setDisplayName(text); 215 v.setAdjustSelectionBoundsEnabled(false); 216 } 217 218 /** @return True if the shortcut state (disabled vs enabled) was changed by this operation */ 219 public boolean setShortcutEnabled(int shortcutType, boolean visible) { 220 final boolean changed = shortcutEnabled[shortcutType] != visible; 221 shortcutEnabled[shortcutType] = visible; 222 return changed; 223 } 224 225 public String getFormattedQueryString() { 226 return formattedQueryString; 227 } 228 229 @Override 230 public void setQueryString(String queryString) { 231 formattedQueryString = 232 PhoneNumberHelper.formatNumber( 233 getContext(), PhoneNumberUtils.normalizeNumber(queryString), countryIso); 234 super.setQueryString(queryString); 235 } 236 } 237