1/* 2 * Copyright (C) 2014 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 */ 16package com.android.contacts.interactions; 17 18import android.content.ContentValues; 19import android.content.Context; 20import android.content.Intent; 21import android.content.res.Resources; 22import android.graphics.PorterDuff; 23import android.graphics.drawable.Drawable; 24import android.net.Uri; 25import android.provider.CallLog.Calls; 26import android.provider.ContactsContract.CommonDataKinds.Phone; 27import android.text.BidiFormatter; 28import android.text.Spannable; 29import android.text.TextDirectionHeuristics; 30 31import com.android.contacts.GeoUtil; 32import com.android.contacts.R; 33import com.android.contacts.compat.PhoneNumberUtilsCompat; 34import com.android.contacts.util.BitmapUtil; 35import com.android.contacts.util.ContactDisplayUtils; 36 37/** 38 * Represents a call log event interaction, wrapping the columns in 39 * {@link android.provider.CallLog.Calls}. 40 * 41 * This class does not return log entries related to voicemail or SIP calls. Additionally, 42 * this class ignores number presentation. Number presentation affects how to identify phone 43 * numbers. Since, we already know the identity of the phone number owner we can ignore number 44 * presentation. 45 * 46 * As a result of ignoring voicemail and number presentation, we don't need to worry about API 47 * version. 48 */ 49public class CallLogInteraction implements ContactInteraction { 50 51 private static final String URI_TARGET_PREFIX = "tel:"; 52 private static final int CALL_LOG_ICON_RES = R.drawable.quantum_ic_phone_vd_theme_24; 53 private static final int CALL_ARROW_ICON_RES = R.drawable.ic_call_arrow; 54 private static BidiFormatter sBidiFormatter = BidiFormatter.getInstance(); 55 56 private ContentValues mValues; 57 58 public CallLogInteraction(ContentValues values) { 59 mValues = values; 60 } 61 62 @Override 63 public Intent getIntent() { 64 String number = getNumber(); 65 return number == null ? null : new Intent(Intent.ACTION_CALL).setData( 66 Uri.parse(URI_TARGET_PREFIX + number)); 67 } 68 69 @Override 70 public String getViewHeader(Context context) { 71 String number = mValues.getAsString(Calls.NUMBER); 72 if (number != null) { 73 number = PhoneNumberUtilsCompat.formatNumber(number, 74 PhoneNumberUtilsCompat.normalizeNumber(number), 75 GeoUtil.getCurrentCountryIso(context)); 76 return sBidiFormatter.unicodeWrap(number, TextDirectionHeuristics.LTR); 77 } 78 return null; 79 } 80 81 @Override 82 public long getInteractionDate() { 83 Long date = getDate(); 84 return date == null ? -1 : date; 85 } 86 87 @Override 88 public String getViewBody(Context context) { 89 Integer numberType = getCachedNumberType(); 90 if (numberType == null) { 91 return null; 92 } 93 return Phone.getTypeLabel(context.getResources(), getCachedNumberType(), 94 getCachedNumberLabel()).toString(); 95 } 96 97 @Override 98 public String getViewFooter(Context context) { 99 final Long date = getDate(); 100 if (date != null) { 101 final StringBuilder callDetail = new StringBuilder(); 102 callDetail.append(ContactInteractionUtil.formatDateStringFromTimestamp(date, context)); 103 final Long duration = getDuration(); 104 if (duration != null) { 105 callDetail.append("\n"); 106 callDetail.append(ContactInteractionUtil.formatDuration(duration, context)); 107 } 108 return callDetail.toString(); 109 } 110 return null; 111 } 112 113 @Override 114 public Drawable getIcon(Context context) { 115 return context.getResources().getDrawable(CALL_LOG_ICON_RES); 116 } 117 118 @Override 119 public Drawable getBodyIcon(Context context) { 120 return null; 121 } 122 123 @Override 124 public Drawable getFooterIcon(Context context) { 125 Drawable callArrow = null; 126 Resources res = context.getResources(); 127 Integer type = getType(); 128 if (type == null) { 129 return null; 130 } 131 switch (type) { 132 case Calls.INCOMING_TYPE: 133 callArrow = res.getDrawable(CALL_ARROW_ICON_RES); 134 callArrow.mutate().setColorFilter(res.getColor(R.color.call_arrow_green), 135 PorterDuff.Mode.MULTIPLY); 136 break; 137 case Calls.MISSED_TYPE: 138 callArrow = res.getDrawable(CALL_ARROW_ICON_RES); 139 callArrow.mutate().setColorFilter(res.getColor(R.color.call_arrow_red), 140 PorterDuff.Mode.MULTIPLY); 141 break; 142 case Calls.OUTGOING_TYPE: 143 callArrow = BitmapUtil.getRotatedDrawable(res, CALL_ARROW_ICON_RES, 180f); 144 callArrow.setColorFilter(res.getColor(R.color.call_arrow_green), 145 PorterDuff.Mode.MULTIPLY); 146 break; 147 } 148 return callArrow; 149 } 150 151 public String getCachedName() { 152 return mValues.getAsString(Calls.CACHED_NAME); 153 } 154 155 public String getCachedNumberLabel() { 156 return mValues.getAsString(Calls.CACHED_NUMBER_LABEL); 157 } 158 159 public Integer getCachedNumberType() { 160 return mValues.getAsInteger(Calls.CACHED_NUMBER_TYPE); 161 } 162 163 public Long getDate() { 164 return mValues.getAsLong(Calls.DATE); 165 } 166 167 public Long getDuration() { 168 return mValues.getAsLong(Calls.DURATION); 169 } 170 171 public Boolean getIsRead() { 172 return mValues.getAsBoolean(Calls.IS_READ); 173 } 174 175 public Integer getLimitParamKey() { 176 return mValues.getAsInteger(Calls.LIMIT_PARAM_KEY); 177 } 178 179 public Boolean getNew() { 180 return mValues.getAsBoolean(Calls.NEW); 181 } 182 183 public String getNumber() { 184 final String number = mValues.getAsString(Calls.NUMBER); 185 return number == null ? null : 186 sBidiFormatter.unicodeWrap(number, TextDirectionHeuristics.LTR); 187 } 188 189 public Integer getNumberPresentation() { 190 return mValues.getAsInteger(Calls.NUMBER_PRESENTATION); 191 } 192 193 public Integer getOffsetParamKey() { 194 return mValues.getAsInteger(Calls.OFFSET_PARAM_KEY); 195 } 196 197 public Integer getType() { 198 return mValues.getAsInteger(Calls.TYPE); 199 } 200 201 @Override 202 public Spannable getContentDescription(Context context) { 203 final String phoneNumber = getViewHeader(context); 204 final String contentDescription = context.getResources().getString( 205 R.string.content_description_recent_call, 206 getCallTypeString(context), phoneNumber, getViewFooter(context)); 207 return ContactDisplayUtils.getTelephoneTtsSpannable(contentDescription, phoneNumber); 208 } 209 210 private String getCallTypeString(Context context) { 211 String callType = ""; 212 Resources res = context.getResources(); 213 Integer type = getType(); 214 if (type == null) { 215 return callType; 216 } 217 switch (type) { 218 case Calls.INCOMING_TYPE: 219 callType = res.getString(R.string.content_description_recent_call_type_incoming); 220 break; 221 case Calls.MISSED_TYPE: 222 callType = res.getString(R.string.content_description_recent_call_type_missed); 223 break; 224 case Calls.OUTGOING_TYPE: 225 callType = res.getString(R.string.content_description_recent_call_type_outgoing); 226 break; 227 } 228 return callType; 229 } 230 231 @Override 232 public int getIconResourceId() { 233 return CALL_LOG_ICON_RES; 234 } 235} 236