blob: 9e76db4f2ff611b4bb61e4be81bacbfa1389bea2 [file] [log] [blame]
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001/*
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;
Anders Kristensen0b35f042014-02-27 14:31:07 -080029import android.telephony.DisconnectCause;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070030import 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) {
Anders Kristensen0b35f042014-02-27 14:31:07 -080091 final int cause = c.getDisconnectCause();
Santos Cordon7d4ddf62013-07-10 11:58:08 -070092
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()) {
Anders Kristensen0b35f042014-02-27 14:31:07 -080097 callLogType = (cause == DisconnectCause.INCOMING_MISSED ?
Santos Cordon7d4ddf62013-07-10 11:58:08 -070098 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 final boolean isEmergencyNumber = PhoneNumberUtils.isLocalEmergencyNumber(number,
113 mApplication);
114
115 // On some devices, to avoid accidental redialing of
116 // emergency numbers, we *never* log emergency calls to
117 // the Call Log. (This behavior is set on a per-product
118 // basis, based on carrier requirements.)
119 final boolean okToLogEmergencyNumber =
120 mApplication.getResources().getBoolean(
121 R.bool.allow_emergency_numbers_in_call_log);
122
123 // Don't log emergency numbers if the device doesn't allow it,
124 boolean isOkToLogThisCall = !isEmergencyNumber || okToLogEmergencyNumber;
125
126 if (isOkToLogThisCall) {
127 if (DBG) {
128 log("sending Calllog entry: " + ci + ", " + PhoneUtils.toLogSafePhoneNumber(number)
129 + "," + presentation + ", " + callType + ", " + start + ", " + duration);
130 }
131
132 CallLogAsync.AddCallArgs args = new CallLogAsync.AddCallArgs(mApplication, ci, number,
133 presentation, callType, start, duration);
134 mCallLog.addCall(args);
135 }
136 }
137
138 /**
139 * Get the caller info.
140 *
141 * @param conn The phone connection.
142 * @return The CallerInfo associated with the connection. Maybe null.
143 */
144 private CallerInfo getCallerInfoFromConnection(Connection conn) {
145 CallerInfo ci = null;
146 Object o = conn.getUserData();
147
148 if ((o == null) || (o instanceof CallerInfo)) {
149 ci = (CallerInfo) o;
150 } else if (o instanceof Uri) {
151 ci = CallerInfo.getCallerInfo(mApplication.getApplicationContext(), (Uri) o);
152 } else {
153 ci = ((PhoneUtils.CallerInfoToken) o).currentInfo;
154 }
155 return ci;
156 }
157
158 /**
159 * Retrieve the phone number from the caller info or the connection.
160 *
161 * For incoming call the number is in the Connection object. For
162 * outgoing call we use the CallerInfo phoneNumber field if
163 * present. All the processing should have been done already (CDMA vs GSM numbers).
164 *
165 * If CallerInfo is missing the phone number, get it from the connection.
166 * Apply the Call Name Presentation (CNAP) transform in the connection on the number.
167 *
168 * @param conn The phone connection.
169 * @param callerInfo The CallerInfo. Maybe null.
170 * @return the phone number.
171 */
172 private String getLogNumber(Connection conn, CallerInfo callerInfo) {
173 String number = null;
174
175 if (conn.isIncoming()) {
176 number = conn.getAddress();
177 } else {
178 // For emergency and voicemail calls,
179 // CallerInfo.phoneNumber does *not* contain a valid phone
180 // number. Instead it contains an I18N'd string such as
181 // "Emergency Number" or "Voice Mail" so we get the number
182 // from the connection.
183 if (null == callerInfo || TextUtils.isEmpty(callerInfo.phoneNumber) ||
184 callerInfo.isEmergencyNumber() || callerInfo.isVoiceMailNumber()) {
185 if (conn.getCall().getPhone().getPhoneType() == PhoneConstants.PHONE_TYPE_CDMA) {
186 // In cdma getAddress() is not always equals to getOrigDialString().
187 number = conn.getOrigDialString();
188 } else {
189 number = conn.getAddress();
190 }
191 } else {
192 number = callerInfo.phoneNumber;
193 }
194 }
195
196 if (null == number) {
197 return null;
198 } else {
199 int presentation = conn.getNumberPresentation();
200
201 // Do final CNAP modifications.
202 String newNumber = PhoneUtils.modifyForSpecialCnapCases(mApplication, callerInfo,
203 number, presentation);
204
205 if (!PhoneNumberUtils.isUriNumber(number)) {
206 number = PhoneNumberUtils.stripSeparators(number);
207 }
208 if (VDBG) log("getLogNumber: " + number);
209 return number;
210 }
211 }
212
213 /**
214 * Get the presentation from the callerinfo if not null otherwise,
215 * get it from the connection.
216 *
217 * @param conn The phone connection.
218 * @param callerInfo The CallerInfo. Maybe null.
219 * @return The presentation to use in the logs.
220 */
221 private int getPresentation(Connection conn, CallerInfo callerInfo) {
222 int presentation;
223
224 if (null == callerInfo) {
225 presentation = conn.getNumberPresentation();
226 } else {
227 presentation = callerInfo.numberPresentation;
228 if (DBG) log("- getPresentation(): ignoring connection's presentation: " +
229 conn.getNumberPresentation());
230 }
231 if (DBG) log("- getPresentation: presentation: " + presentation);
232 return presentation;
233 }
234
235 private void log(String msg) {
236 Log.d(LOG_TAG, msg);
237 }
238}