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
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.DisconnectCause;
30import 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) {
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     */
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     */
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     */
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     */
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
212    private void log(String msg) {
213        Log.d(LOG_TAG, msg);
214    }
215}
216