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