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.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 
     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      */
     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      */
     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      */
    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      */
    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      */
    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      */
    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 
    231     private void log(String msg) {
    232         Log.d(LOG_TAG, msg);
    233     }
    234 }
    235