Home | History | Annotate | Download | only in phone
      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 
     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 }
    238