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.DisconnectCause;
30 import android.telephony.PhoneNumberUtils;
31 import android.text.TextUtils;
32 import android.util.Log;
33 
34 /**
35  * Helper class for interacting with the call log.
36  */
37 class 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 
CallLogger(PhoneGlobals application, CallLogAsync callLogAsync)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      */
logCall(Connection c, int callLogType)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      */
logCall(Connection c)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      */
logCall(CallerInfo ci, String number, int presentation, int callType, long start, long duration)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      */
getCallerInfoFromConnection(Connection conn)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      */
getLogNumber(Connection conn, CallerInfo callerInfo)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      */
getPresentation(Connection conn, CallerInfo callerInfo)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 
log(String msg)212     private void log(String msg) {
213         Log.d(LOG_TAG, msg);
214     }
215 }
216