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; 18 19 import android.content.res.Resources; 20 import android.graphics.Typeface; 21 import android.provider.ContactsContract; 22 import android.provider.ContactsContract.CommonDataKinds.Phone; 23 import android.telephony.PhoneNumberUtils; 24 import android.text.SpannableString; 25 import android.text.Spanned; 26 import android.text.TextUtils; 27 import android.text.format.DateUtils; 28 import android.text.style.ForegroundColorSpan; 29 import android.text.style.StyleSpan; 30 import android.view.View; 31 import android.widget.TextView; 32 33 import com.android.contacts.common.test.NeededForTesting; 34 import com.android.dialer.calllog.CallTypeHelper; 35 import com.android.dialer.calllog.ContactInfo; 36 import com.android.dialer.calllog.PhoneNumberDisplayHelper; 37 import com.android.dialer.calllog.PhoneNumberUtilsWrapper; 38 39 /** 40 * Helper class to fill in the views in {@link PhoneCallDetailsViews}. 41 */ 42 public class PhoneCallDetailsHelper { 43 /** The maximum number of icons will be shown to represent the call types in a group. */ 44 private static final int MAX_CALL_TYPE_ICONS = 3; 45 46 private final Resources mResources; 47 /** The injected current time in milliseconds since the epoch. Used only by tests. */ 48 private Long mCurrentTimeMillisForTest; 49 // Helper classes. 50 private final CallTypeHelper mCallTypeHelper; 51 private final PhoneNumberDisplayHelper mPhoneNumberHelper; 52 private final PhoneNumberUtilsWrapper mPhoneNumberUtilsWrapper; 53 54 /** 55 * Creates a new instance of the helper. 56 * <p> 57 * Generally you should have a single instance of this helper in any context. 58 * 59 * @param resources used to look up strings 60 */ 61 public PhoneCallDetailsHelper(Resources resources, CallTypeHelper callTypeHelper, 62 PhoneNumberUtilsWrapper phoneUtils) { 63 mResources = resources; 64 mCallTypeHelper = callTypeHelper; 65 mPhoneNumberUtilsWrapper = phoneUtils; 66 mPhoneNumberHelper = new PhoneNumberDisplayHelper(mPhoneNumberUtilsWrapper, resources); 67 } 68 69 /** Fills the call details views with content. */ 70 public void setPhoneCallDetails(PhoneCallDetailsViews views, PhoneCallDetails details, 71 boolean isHighlighted) { 72 // Display up to a given number of icons. 73 views.callTypeIcons.clear(); 74 int count = details.callTypes.length; 75 for (int index = 0; index < count && index < MAX_CALL_TYPE_ICONS; ++index) { 76 views.callTypeIcons.add(details.callTypes[index]); 77 } 78 views.callTypeIcons.requestLayout(); 79 views.callTypeIcons.setVisibility(View.VISIBLE); 80 81 // Show the total call count only if there are more than the maximum number of icons. 82 final Integer callCount; 83 if (count > MAX_CALL_TYPE_ICONS) { 84 callCount = count; 85 } else { 86 callCount = null; 87 } 88 // The color to highlight the count and date in, if any. This is based on the first call. 89 Integer highlightColor = 90 isHighlighted ? mCallTypeHelper.getHighlightedColor(details.callTypes[0]) : null; 91 92 // The date of this call, relative to the current time. 93 CharSequence dateText = getCallDate(details); 94 95 // Set the call count and date. 96 setCallCountAndDate(views, callCount, dateText, highlightColor); 97 98 // Get type of call (ie mobile, home, etc) if known, or the caller's 99 CharSequence numberFormattedLabel = getCallTypeOrLocation(details); 100 101 final CharSequence nameText; 102 final CharSequence numberText; 103 final CharSequence labelText; 104 final CharSequence displayNumber = 105 mPhoneNumberHelper.getDisplayNumber(details.number, 106 details.numberPresentation, details.formattedNumber); 107 if (TextUtils.isEmpty(details.name)) { 108 nameText = displayNumber; 109 if (TextUtils.isEmpty(details.geocode) 110 || mPhoneNumberUtilsWrapper.isVoicemailNumber(details.number)) { 111 numberText = mResources.getString(R.string.call_log_empty_geocode); 112 } else { 113 numberText = details.geocode; 114 } 115 labelText = numberText; 116 // We have a real phone number as "nameView" so make it always LTR 117 views.nameView.setTextDirection(View.TEXT_DIRECTION_LTR); 118 } else { 119 nameText = details.name; 120 numberText = displayNumber; 121 labelText = TextUtils.isEmpty(numberFormattedLabel) ? numberText : 122 numberFormattedLabel; 123 } 124 125 views.nameView.setText(nameText); 126 views.labelView.setText(labelText); 127 views.labelView.setVisibility(TextUtils.isEmpty(labelText) ? View.GONE : View.VISIBLE); 128 } 129 130 /** 131 * For a call, if there is an associated contact for the caller, return the known call type 132 * (e.g. mobile, home, work). If there is no associated contact, attempt to use the caller's 133 * location if known. 134 * @param details Call details to use. 135 * @return Type of call (mobile/home) if known, or the location of the caller (if known). 136 */ 137 public CharSequence getCallTypeOrLocation(PhoneCallDetails details) { 138 CharSequence numberFormattedLabel = null; 139 // Only show a label if the number is shown and it is not a SIP address. 140 if (!TextUtils.isEmpty(details.number) 141 && !PhoneNumberUtils.isUriNumber(details.number.toString())) { 142 if (details.numberLabel == ContactInfo.GEOCODE_AS_LABEL) { 143 numberFormattedLabel = details.geocode; 144 } else { 145 numberFormattedLabel = Phone.getTypeLabel(mResources, details.numberType, 146 details.numberLabel); 147 } 148 } 149 return numberFormattedLabel; 150 } 151 152 /** 153 * Get the call date/time of the call, relative to the current time. 154 * e.g. 3 minutes ago 155 * @param details Call details to use. 156 * @return String representing when the call occurred. 157 */ 158 public CharSequence getCallDate(PhoneCallDetails details) { 159 return DateUtils.getRelativeTimeSpanString(details.date, 160 getCurrentTimeMillis(), 161 DateUtils.MINUTE_IN_MILLIS, 162 DateUtils.FORMAT_ABBREV_RELATIVE); 163 } 164 165 /** Sets the text of the header view for the details page of a phone call. */ 166 public void setCallDetailsHeader(TextView nameView, PhoneCallDetails details) { 167 final CharSequence nameText; 168 final CharSequence displayNumber = 169 mPhoneNumberHelper.getDisplayNumber(details.number, details.numberPresentation, 170 mResources.getString(R.string.recentCalls_addToContact)); 171 if (TextUtils.isEmpty(details.name)) { 172 nameText = displayNumber; 173 } else { 174 nameText = details.name; 175 } 176 177 nameView.setText(nameText); 178 } 179 180 @NeededForTesting 181 public void setCurrentTimeForTest(long currentTimeMillis) { 182 mCurrentTimeMillisForTest = currentTimeMillis; 183 } 184 185 /** 186 * Returns the current time in milliseconds since the epoch. 187 * <p> 188 * It can be injected in tests using {@link #setCurrentTimeForTest(long)}. 189 */ 190 private long getCurrentTimeMillis() { 191 if (mCurrentTimeMillisForTest == null) { 192 return System.currentTimeMillis(); 193 } else { 194 return mCurrentTimeMillisForTest; 195 } 196 } 197 198 /** Sets the call count and date. */ 199 private void setCallCountAndDate(PhoneCallDetailsViews views, Integer callCount, 200 CharSequence dateText, Integer highlightColor) { 201 // Combine the count (if present) and the date. 202 final CharSequence text; 203 if (callCount != null) { 204 text = mResources.getString( 205 R.string.call_log_item_count_and_date, callCount.intValue(), dateText); 206 } else { 207 text = dateText; 208 } 209 210 // Apply the highlight color if present. 211 final CharSequence formattedText; 212 if (highlightColor != null) { 213 formattedText = addBoldAndColor(text, highlightColor); 214 } else { 215 formattedText = text; 216 } 217 218 views.callTypeAndDate.setText(formattedText); 219 } 220 221 /** Creates a SpannableString for the given text which is bold and in the given color. */ 222 private CharSequence addBoldAndColor(CharSequence text, int color) { 223 int flags = Spanned.SPAN_INCLUSIVE_INCLUSIVE; 224 SpannableString result = new SpannableString(text); 225 result.setSpan(new StyleSpan(Typeface.BOLD), 0, text.length(), flags); 226 result.setSpan(new ForegroundColorSpan(color), 0, text.length(), flags); 227 return result; 228 } 229 } 230