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