blob: 644812f96927c6ce05cf9fbe73ff1e6c015121fa [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;
29import android.telephony.PhoneNumberUtils;
30import android.text.TextUtils;
31import android.util.Log;
32
33/**
34 * Helper class for interacting with the call log.
35 */
36class 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}