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