1 /* 2 * Copyright (C) 2011 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.calllog; 18 19 import android.content.Context; 20 import android.content.res.Resources; 21 import android.provider.CallLog.Calls; 22 import android.text.SpannableStringBuilder; 23 import android.text.TextUtils; 24 import android.util.Log; 25 26 import com.android.dialer.PhoneCallDetails; 27 import com.android.dialer.R; 28 29 /** 30 * Helper class to fill in the views of a call log entry. 31 */ 32 /* package */class CallLogListItemHelper { 33 private static final String TAG = "CallLogListItemHelper"; 34 35 /** Helper for populating the details of a phone call. */ 36 private final PhoneCallDetailsHelper mPhoneCallDetailsHelper; 37 /** Resources to look up strings. */ 38 private final Resources mResources; 39 private final TelecomCallLogCache mTelecomCallLogCache; 40 41 /** 42 * Creates a new helper instance. 43 * 44 * @param phoneCallDetailsHelper used to set the details of a phone call 45 * @param phoneNumberHelper used to process phone number 46 */ 47 public CallLogListItemHelper( 48 PhoneCallDetailsHelper phoneCallDetailsHelper, 49 Resources resources, 50 TelecomCallLogCache telecomCallLogCache) { 51 mPhoneCallDetailsHelper = phoneCallDetailsHelper; 52 mResources = resources; 53 mTelecomCallLogCache = telecomCallLogCache; 54 } 55 56 /** 57 * Sets the name, label, and number for a contact. 58 * 59 * @param context The application context. 60 * @param views the views to populate 61 * @param details the details of a phone call needed to fill in the data 62 */ 63 public void setPhoneCallDetails( 64 CallLogListItemViewHolder views, 65 PhoneCallDetails details) { 66 mPhoneCallDetailsHelper.setPhoneCallDetails(views.phoneCallDetailsViews, details); 67 68 // Set the accessibility text for the contact badge 69 views.quickContactView.setContentDescription(getContactBadgeDescription(details)); 70 71 // Set the primary action accessibility description 72 views.primaryActionView.setContentDescription(getCallDescription(details)); 73 74 // Cache name or number of caller. Used when setting the content descriptions of buttons 75 // when the actions ViewStub is inflated. 76 views.nameOrNumber = getNameOrNumber(details); 77 } 78 79 /** 80 * Sets the accessibility descriptions for the action buttons in the action button ViewStub. 81 * 82 * @param views The views associated with the current call log entry. 83 */ 84 public void setActionContentDescriptions(CallLogListItemViewHolder views) { 85 if (views.nameOrNumber == null) { 86 Log.e(TAG, "setActionContentDescriptions; name or number is null."); 87 } 88 89 // Calling expandTemplate with a null parameter will cause a NullPointerException. 90 // Although we don't expect a null name or number, it is best to protect against it. 91 CharSequence nameOrNumber = views.nameOrNumber == null ? "" : views.nameOrNumber; 92 93 views.videoCallButtonView.setContentDescription( 94 TextUtils.expandTemplate( 95 mResources.getString(R.string.description_video_call_action), 96 nameOrNumber)); 97 98 views.createNewContactButtonView.setContentDescription( 99 TextUtils.expandTemplate( 100 mResources.getString(R.string.description_create_new_contact_action), 101 nameOrNumber)); 102 103 views.addToExistingContactButtonView.setContentDescription( 104 TextUtils.expandTemplate( 105 mResources.getString(R.string.description_add_to_existing_contact_action), 106 nameOrNumber)); 107 108 views.detailsButtonView.setContentDescription( 109 TextUtils.expandTemplate( 110 mResources.getString(R.string.description_details_action), nameOrNumber)); 111 } 112 113 /** 114 * Returns the accessibility description for the contact badge for a call log entry. 115 * 116 * @param details Details of call. 117 * @return Accessibility description. 118 */ 119 private CharSequence getContactBadgeDescription(PhoneCallDetails details) { 120 return mResources.getString(R.string.description_contact_details, getNameOrNumber(details)); 121 } 122 123 /** 124 * Returns the accessibility description of the "return call/call" action for a call log 125 * entry. 126 * Accessibility text is a combination of: 127 * {Voicemail Prefix}. {Number of Calls}. {Caller information} {Phone Account}. 128 * If most recent call is a voicemail, {Voicemail Prefix} is "New Voicemail.", otherwise "". 129 * 130 * If more than one call for the caller, {Number of Calls} is: 131 * "{number of calls} calls.", otherwise "". 132 * 133 * The {Caller Information} references the most recent call associated with the caller. 134 * For incoming calls: 135 * If missed call: Missed call from {Name/Number} {Call Type} {Call Time}. 136 * If answered call: Answered call from {Name/Number} {Call Type} {Call Time}. 137 * 138 * For outgoing calls: 139 * If outgoing: Call to {Name/Number] {Call Type} {Call Time}. 140 * 141 * Where: 142 * {Name/Number} is the name or number of the caller (as shown in call log). 143 * {Call type} is the contact phone number type (eg mobile) or location. 144 * {Call Time} is the time since the last call for the contact occurred. 145 * 146 * The {Phone Account} refers to the account/SIM through which the call was placed or received 147 * in multi-SIM devices. 148 * 149 * Examples: 150 * 3 calls. New Voicemail. Missed call from Joe Smith mobile 2 hours ago on SIM 1. 151 * 152 * 2 calls. Answered call from John Doe mobile 1 hour ago. 153 * 154 * @param context The application context. 155 * @param details Details of call. 156 * @return Return call action description. 157 */ 158 public CharSequence getCallDescription(PhoneCallDetails details) { 159 int lastCallType = getLastCallType(details.callTypes); 160 boolean isVoiceMail = lastCallType == Calls.VOICEMAIL_TYPE; 161 162 // Get the name or number of the caller. 163 final CharSequence nameOrNumber = getNameOrNumber(details); 164 165 // Get the call type or location of the caller; null if not applicable 166 final CharSequence typeOrLocation = mPhoneCallDetailsHelper.getCallTypeOrLocation(details); 167 168 // Get the time/date of the call 169 final CharSequence timeOfCall = mPhoneCallDetailsHelper.getCallDate(details); 170 171 SpannableStringBuilder callDescription = new SpannableStringBuilder(); 172 173 // Prepend the voicemail indication. 174 if (isVoiceMail) { 175 callDescription.append(mResources.getString(R.string.description_new_voicemail)); 176 } 177 178 // Add number of calls if more than one. 179 if (details.callTypes.length > 1) { 180 callDescription.append(mResources.getString(R.string.description_num_calls, 181 details.callTypes.length)); 182 } 183 184 // If call had video capabilities, add the "Video Call" string. 185 if ((details.features & Calls.FEATURES_VIDEO) == Calls.FEATURES_VIDEO) { 186 callDescription.append(mResources.getString(R.string.description_video_call)); 187 } 188 189 int stringID = getCallDescriptionStringID(details.callTypes); 190 String accountLabel = mTelecomCallLogCache.getAccountLabel(details.accountHandle); 191 192 // Use chosen string resource to build up the message. 193 CharSequence onAccountLabel = accountLabel == null 194 ? "" 195 : TextUtils.expandTemplate( 196 mResources.getString(R.string.description_phone_account), 197 accountLabel); 198 callDescription.append( 199 TextUtils.expandTemplate( 200 mResources.getString(stringID), 201 nameOrNumber, 202 // If no type or location can be determined, sub in empty string. 203 typeOrLocation == null ? "" : typeOrLocation, 204 timeOfCall, 205 onAccountLabel)); 206 207 return callDescription; 208 } 209 210 /** 211 * Determine the appropriate string ID to describe a call for accessibility purposes. 212 * 213 * @param details Call details. 214 * @return String resource ID to use. 215 */ 216 public int getCallDescriptionStringID(int[] callTypes) { 217 int lastCallType = getLastCallType(callTypes); 218 int stringID; 219 220 if (lastCallType == Calls.VOICEMAIL_TYPE || lastCallType == Calls.MISSED_TYPE) { 221 //Message: Missed call from <NameOrNumber>, <TypeOrLocation>, <TimeOfCall>, 222 //<PhoneAccount>. 223 stringID = R.string.description_incoming_missed_call; 224 } else if (lastCallType == Calls.INCOMING_TYPE) { 225 //Message: Answered call from <NameOrNumber>, <TypeOrLocation>, <TimeOfCall>, 226 //<PhoneAccount>. 227 stringID = R.string.description_incoming_answered_call; 228 } else { 229 //Message: Call to <NameOrNumber>, <TypeOrLocation>, <TimeOfCall>, <PhoneAccount>. 230 stringID = R.string.description_outgoing_call; 231 } 232 return stringID; 233 } 234 235 /** 236 * Determine the call type for the most recent call. 237 * @param callTypes Call types to check. 238 * @return Call type. 239 */ 240 private int getLastCallType(int[] callTypes) { 241 if (callTypes.length > 0) { 242 return callTypes[0]; 243 } else { 244 return Calls.MISSED_TYPE; 245 } 246 } 247 248 /** 249 * Return the name or number of the caller specified by the details. 250 * @param details Call details 251 * @return the name (if known) of the caller, otherwise the formatted number. 252 */ 253 private CharSequence getNameOrNumber(PhoneCallDetails details) { 254 final CharSequence recipient; 255 if (!TextUtils.isEmpty(details.name)) { 256 recipient = details.name; 257 } else { 258 recipient = details.displayNumber; 259 } 260 return recipient; 261 } 262 } 263