• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
CallLogger(PhoneGlobals application, CallLogAsync callLogAsync)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      */
logCall(Connection c, int callLogType)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      */
logCall(Connection c)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      */
logCall(CallerInfo ci, String number, int presentation, int callType, long start, long duration)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      */
getCallerInfoFromConnection(Connection conn)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      */
getLogNumber(Connection conn, CallerInfo callerInfo)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      */
getPresentation(Connection conn, CallerInfo callerInfo)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 
log(String msg)234     private void log(String msg) {
235         Log.d(LOG_TAG, msg);
236     }
237 }
238