1 /* 2 * Copyright (C) 2013 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.phone; 18 19 import com.android.internal.telephony.CallerInfo; 20 import com.android.internal.telephony.Connection; 21 import com.android.internal.telephony.Phone; 22 import com.android.internal.telephony.PhoneConstants; 23 import com.android.internal.telephony.TelephonyCapabilities; 24 import com.android.phone.common.CallLogAsync; 25 26 import android.net.Uri; 27 import android.os.SystemProperties; 28 import android.provider.CallLog.Calls; 29 import android.telephony.PhoneNumberUtils; 30 import android.text.TextUtils; 31 import android.util.Log; 32 33 /** 34 * Helper class for interacting with the call log. 35 */ 36 class CallLogger { 37 private static final String LOG_TAG = CallLogger.class.getSimpleName(); 38 private static final boolean DBG = (PhoneGlobals.DBG_LEVEL >= 1) && 39 (SystemProperties.getInt("ro.debuggable", 0) == 1); 40 private static final boolean VDBG = (PhoneGlobals.DBG_LEVEL >= 2); 41 42 private PhoneGlobals mApplication; 43 private CallLogAsync mCallLog; 44 45 public CallLogger(PhoneGlobals application, CallLogAsync callLogAsync) { 46 mApplication = application; 47 mCallLog = callLogAsync; 48 } 49 50 /** 51 * Logs a call to the call log based on the connection object passed in. 52 * 53 * @param c The connection object for the call being logged. 54 * @param callLogType The type of call log entry. 55 */ 56 public void logCall(Connection c, int callLogType) { 57 final String number = c.getAddress(); 58 final long date = c.getCreateTime(); 59 final long duration = c.getDurationMillis(); 60 final Phone phone = c.getCall().getPhone(); 61 62 final CallerInfo ci = getCallerInfoFromConnection(c); // May be null. 63 final String logNumber = getLogNumber(c, ci); 64 65 if (DBG) { 66 log("- onDisconnect(): logNumber set to:" + PhoneUtils.toLogSafePhoneNumber(logNumber) + 67 ", number set to: " + PhoneUtils.toLogSafePhoneNumber(number)); 68 } 69 70 // TODO: In getLogNumber we use the presentation from 71 // the connection for the CNAP. Should we use the one 72 // below instead? (comes from caller info) 73 74 // For international calls, 011 needs to be logged as + 75 final int presentation = getPresentation(c, ci); 76 77 final boolean isOtaspNumber = TelephonyCapabilities.supportsOtasp(phone) 78 && phone.isOtaSpNumber(number); 79 80 // Don't log OTASP calls. 81 if (!isOtaspNumber) { 82 logCall(ci, logNumber, presentation, callLogType, date, duration); 83 } 84 } 85 86 /** 87 * Came as logCall(Connection,int) but calculates the call type from the connection object. 88 */ 89 public void logCall(Connection c) { 90 final Connection.DisconnectCause cause = c.getDisconnectCause(); 91 92 // Set the "type" to be displayed in the call log (see constants in CallLog.Calls) 93 final int callLogType; 94 95 if (c.isIncoming()) { 96 callLogType = (cause == Connection.DisconnectCause.INCOMING_MISSED ? 97 Calls.MISSED_TYPE : Calls.INCOMING_TYPE); 98 } else { 99 callLogType = Calls.OUTGOING_TYPE; 100 } 101 if (VDBG) log("- callLogType: " + callLogType + ", UserData: " + c.getUserData()); 102 103 logCall(c, callLogType); 104 } 105 106 /** 107 * Logs a call to the call from the parameters passed in. 108 */ 109 public void logCall(CallerInfo ci, String number, int presentation, int callType, long start, 110 long duration) { 111 final boolean isEmergencyNumber = PhoneNumberUtils.isLocalEmergencyNumber(number, 112 mApplication); 113 114 // On some devices, to avoid accidental redialing of 115 // emergency numbers, we *never* log emergency calls to 116 // the Call Log. (This behavior is set on a per-product 117 // basis, based on carrier requirements.) 118 final boolean okToLogEmergencyNumber = 119 mApplication.getResources().getBoolean( 120 R.bool.allow_emergency_numbers_in_call_log); 121 122 // Don't log emergency numbers if the device doesn't allow it, 123 boolean isOkToLogThisCall = !isEmergencyNumber || okToLogEmergencyNumber; 124 125 if (isOkToLogThisCall) { 126 if (DBG) { 127 log("sending Calllog entry: " + ci + ", " + PhoneUtils.toLogSafePhoneNumber(number) 128 + "," + presentation + ", " + callType + ", " + start + ", " + duration); 129 } 130 131 CallLogAsync.AddCallArgs args = new CallLogAsync.AddCallArgs(mApplication, ci, number, 132 presentation, callType, start, duration); 133 mCallLog.addCall(args); 134 } 135 } 136 137 /** 138 * Get the caller info. 139 * 140 * @param conn The phone connection. 141 * @return The CallerInfo associated with the connection. Maybe null. 142 */ 143 private CallerInfo getCallerInfoFromConnection(Connection conn) { 144 CallerInfo ci = null; 145 Object o = conn.getUserData(); 146 147 if ((o == null) || (o instanceof CallerInfo)) { 148 ci = (CallerInfo) o; 149 } else if (o instanceof Uri) { 150 ci = CallerInfo.getCallerInfo(mApplication.getApplicationContext(), (Uri) o); 151 } else { 152 ci = ((PhoneUtils.CallerInfoToken) o).currentInfo; 153 } 154 return ci; 155 } 156 157 /** 158 * Retrieve the phone number from the caller info or the connection. 159 * 160 * For incoming call the number is in the Connection object. For 161 * outgoing call we use the CallerInfo phoneNumber field if 162 * present. All the processing should have been done already (CDMA vs GSM numbers). 163 * 164 * If CallerInfo is missing the phone number, get it from the connection. 165 * Apply the Call Name Presentation (CNAP) transform in the connection on the number. 166 * 167 * @param conn The phone connection. 168 * @param callerInfo The CallerInfo. Maybe null. 169 * @return the phone number. 170 */ 171 private String getLogNumber(Connection conn, CallerInfo callerInfo) { 172 String number = null; 173 174 if (conn.isIncoming()) { 175 number = conn.getAddress(); 176 } else { 177 // For emergency and voicemail calls, 178 // CallerInfo.phoneNumber does *not* contain a valid phone 179 // number. Instead it contains an I18N'd string such as 180 // "Emergency Number" or "Voice Mail" so we get the number 181 // from the connection. 182 if (null == callerInfo || TextUtils.isEmpty(callerInfo.phoneNumber) || 183 callerInfo.isEmergencyNumber() || callerInfo.isVoiceMailNumber()) { 184 if (conn.getCall().getPhone().getPhoneType() == PhoneConstants.PHONE_TYPE_CDMA) { 185 // In cdma getAddress() is not always equals to getOrigDialString(). 186 number = conn.getOrigDialString(); 187 } else { 188 number = conn.getAddress(); 189 } 190 } else { 191 number = callerInfo.phoneNumber; 192 } 193 } 194 195 if (null == number) { 196 return null; 197 } else { 198 int presentation = conn.getNumberPresentation(); 199 200 // Do final CNAP modifications. 201 String newNumber = PhoneUtils.modifyForSpecialCnapCases(mApplication, callerInfo, 202 number, presentation); 203 204 if (!PhoneNumberUtils.isUriNumber(number)) { 205 number = PhoneNumberUtils.stripSeparators(number); 206 } 207 if (VDBG) log("getLogNumber: " + number); 208 return number; 209 } 210 } 211 212 /** 213 * Get the presentation from the callerinfo if not null otherwise, 214 * get it from the connection. 215 * 216 * @param conn The phone connection. 217 * @param callerInfo The CallerInfo. Maybe null. 218 * @return The presentation to use in the logs. 219 */ 220 private int getPresentation(Connection conn, CallerInfo callerInfo) { 221 int presentation; 222 223 if (null == callerInfo) { 224 presentation = conn.getNumberPresentation(); 225 } else { 226 presentation = callerInfo.numberPresentation; 227 if (DBG) log("- getPresentation(): ignoring connection's presentation: " + 228 conn.getNumberPresentation()); 229 } 230 if (DBG) log("- getPresentation: presentation: " + presentation); 231 return presentation; 232 } 233 234 private void log(String msg) { 235 Log.d(LOG_TAG, msg); 236 } 237 } 238