blob: ce60d0b5d58f14c0b6f202921c6442d658037f02 [file] [log] [blame]
Yorke Leef98fb572014-03-05 10:56:55 -08001/*
2 * Copyright 2014, 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
Tyler Gunn7cc70b42014-09-12 22:17:27 -070017package com.android.server.telecom;
Ben Gilad9f2bed32013-12-12 17:43:26 -080018
Ta-wei Yen982c0bd2016-04-14 13:59:54 -070019import android.annotation.Nullable;
Yorke Leef98fb572014-03-05 10:56:55 -080020import android.content.Context;
Yong Jiang271b9ae2014-10-09 12:08:54 -050021import android.content.Intent;
Brad Ebingerc6ab2cc2016-04-07 15:33:52 -070022import android.location.Country;
23import android.location.CountryDetector;
Yorke Leef98fb572014-03-05 10:56:55 -080024import android.net.Uri;
25import android.os.AsyncTask;
Brad Ebingerc6ab2cc2016-04-07 15:33:52 -070026import android.os.Looper;
Tony Mak98e6bdc2015-11-25 21:54:05 +000027import android.os.UserHandle;
Shishir Agrawala416e072016-02-17 11:14:45 -080028import android.os.PersistableBundle;
Yorke Leef98fb572014-03-05 10:56:55 -080029import android.provider.CallLog.Calls;
Andrew Lee701dc002014-09-11 21:29:12 -070030import android.telecom.DisconnectCause;
Brad Ebinger953e1af2016-10-05 15:45:22 -070031import android.telecom.Log;
Tony Mak98e6bdc2015-11-25 21:54:05 +000032import android.telecom.PhoneAccount;
Tyler Gunn7cc70b42014-09-12 22:17:27 -070033import android.telecom.PhoneAccountHandle;
34import android.telecom.VideoProfile;
Shishir Agrawala416e072016-02-17 11:14:45 -080035import android.telephony.CarrierConfigManager;
Yorke Leef98fb572014-03-05 10:56:55 -080036import android.telephony.PhoneNumberUtils;
37
Tyler Gunn91d43cf2014-09-17 12:19:39 -070038// TODO: Needed for move to system service: import com.android.internal.R;
Hall Liuada03012015-10-26 15:44:00 -070039import com.android.internal.annotations.VisibleForTesting;
Yorke Lee6f3f7af2014-07-11 10:59:46 -070040import com.android.internal.telephony.CallerInfo;
Yorke Leef98fb572014-03-05 10:56:55 -080041
Brad Ebingerc6ab2cc2016-04-07 15:33:52 -070042import java.util.Locale;
43
Yorke Leef98fb572014-03-05 10:56:55 -080044/**
45 * Helper class that provides functionality to write information about calls and their associated
46 * caller details to the call log. All logging activity will be performed asynchronously in a
47 * background thread to avoid blocking on the main thread.
48 */
Hall Liuada03012015-10-26 15:44:00 -070049@VisibleForTesting
50public final class CallLogManager extends CallsManagerListenerBase {
Ta-wei Yen982c0bd2016-04-14 13:59:54 -070051
52 public interface LogCallCompletedListener {
53 void onLogCompleted(@Nullable Uri uri);
54 }
55
Yorke Leef98fb572014-03-05 10:56:55 -080056 /**
57 * Parameter object to hold the arguments to add a call in the call log DB.
58 */
59 private static class AddCallArgs {
60 /**
Evan Charlton89176372014-07-19 18:23:09 -070061 * @param callerInfo Caller details.
Yorke Leef98fb572014-03-05 10:56:55 -080062 * @param number The phone number to be logged.
63 * @param presentation Number presentation of the phone number to be logged.
64 * @param callType The type of call (e.g INCOMING_TYPE). @see
65 * {@link android.provider.CallLog} for the list of values.
Tyler Gunn765c35c2014-07-10 08:17:53 -070066 * @param features The features of the call (e.g. FEATURES_VIDEO). @see
67 * {@link android.provider.CallLog} for the list of values.
Yorke Leef98fb572014-03-05 10:56:55 -080068 * @param creationDate Time when the call was created (milliseconds since epoch).
69 * @param durationInMillis Duration of the call (milliseconds).
Tyler Gunn765c35c2014-07-10 08:17:53 -070070 * @param dataUsage Data usage in bytes, or null if not applicable.
Ta-wei Yen982c0bd2016-04-14 13:59:54 -070071 * @param logCallCompletedListener optional callback called after the call is logged.
Yorke Leef98fb572014-03-05 10:56:55 -080072 */
Brad Ebingerbaf52ba2016-03-21 16:38:32 -070073 public AddCallArgs(Context context, CallerInfo callerInfo, String number,
74 String postDialDigits, String viaNumber, int presentation, int callType,
75 int features, PhoneAccountHandle accountHandle, long creationDate,
Ta-wei Yen982c0bd2016-04-14 13:59:54 -070076 long durationInMillis, Long dataUsage, UserHandle initiatingUser,
77 @Nullable LogCallCompletedListener logCallCompletedListener) {
Yorke Leef98fb572014-03-05 10:56:55 -080078 this.context = context;
Yorke Lee6f3f7af2014-07-11 10:59:46 -070079 this.callerInfo = callerInfo;
Yorke Leef98fb572014-03-05 10:56:55 -080080 this.number = number;
Hall Liub8ce19c2015-10-14 15:13:51 -070081 this.postDialDigits = postDialDigits;
Brad Ebingerbaf52ba2016-03-21 16:38:32 -070082 this.viaNumber = viaNumber;
Yorke Leef98fb572014-03-05 10:56:55 -080083 this.presentation = presentation;
84 this.callType = callType;
Tyler Gunn765c35c2014-07-10 08:17:53 -070085 this.features = features;
Evan Charlton89176372014-07-19 18:23:09 -070086 this.accountHandle = accountHandle;
Yorke Leef98fb572014-03-05 10:56:55 -080087 this.timestamp = creationDate;
88 this.durationInSec = (int)(durationInMillis / 1000);
Tyler Gunn765c35c2014-07-10 08:17:53 -070089 this.dataUsage = dataUsage;
Tony Mak98e6bdc2015-11-25 21:54:05 +000090 this.initiatingUser = initiatingUser;
Ta-wei Yen982c0bd2016-04-14 13:59:54 -070091 this.logCallCompletedListener = logCallCompletedListener;
Yorke Leef98fb572014-03-05 10:56:55 -080092 }
93 // Since the members are accessed directly, we don't use the
94 // mXxxx notation.
95 public final Context context;
Yorke Lee6f3f7af2014-07-11 10:59:46 -070096 public final CallerInfo callerInfo;
Yorke Leef98fb572014-03-05 10:56:55 -080097 public final String number;
Hall Liub8ce19c2015-10-14 15:13:51 -070098 public final String postDialDigits;
Brad Ebingerbaf52ba2016-03-21 16:38:32 -070099 public final String viaNumber;
Yorke Leef98fb572014-03-05 10:56:55 -0800100 public final int presentation;
101 public final int callType;
Tyler Gunn765c35c2014-07-10 08:17:53 -0700102 public final int features;
Evan Charlton89176372014-07-19 18:23:09 -0700103 public final PhoneAccountHandle accountHandle;
Yorke Leef98fb572014-03-05 10:56:55 -0800104 public final long timestamp;
105 public final int durationInSec;
Tyler Gunn765c35c2014-07-10 08:17:53 -0700106 public final Long dataUsage;
Tony Mak98e6bdc2015-11-25 21:54:05 +0000107 public final UserHandle initiatingUser;
Ta-wei Yen982c0bd2016-04-14 13:59:54 -0700108
109 @Nullable
110 public final LogCallCompletedListener logCallCompletedListener;
Yorke Leef98fb572014-03-05 10:56:55 -0800111 }
112
113 private static final String TAG = CallLogManager.class.getSimpleName();
114
115 private final Context mContext;
Tony Mak98e6bdc2015-11-25 21:54:05 +0000116 private final PhoneAccountRegistrar mPhoneAccountRegistrar;
Ta-wei Yen982c0bd2016-04-14 13:59:54 -0700117 private final MissedCallNotifier mMissedCallNotifier;
Yong Jiang271b9ae2014-10-09 12:08:54 -0500118 private static final String ACTION_CALLS_TABLE_ADD_ENTRY =
119 "com.android.server.telecom.intent.action.CALLS_ADD_ENTRY";
120 private static final String PERMISSION_PROCESS_CALLLOG_INFO =
121 "android.permission.PROCESS_CALLLOG_INFO";
122 private static final String CALL_TYPE = "callType";
123 private static final String CALL_DURATION = "duration";
Yorke Leef98fb572014-03-05 10:56:55 -0800124
Brad Ebingerc6ab2cc2016-04-07 15:33:52 -0700125 private Object mLock;
126 private String mCurrentCountryIso;
127
Ta-wei Yen982c0bd2016-04-14 13:59:54 -0700128 public CallLogManager(Context context, PhoneAccountRegistrar phoneAccountRegistrar,
129 MissedCallNotifier missedCallNotifier) {
Yorke Leef98fb572014-03-05 10:56:55 -0800130 mContext = context;
Tony Mak98e6bdc2015-11-25 21:54:05 +0000131 mPhoneAccountRegistrar = phoneAccountRegistrar;
Ta-wei Yen982c0bd2016-04-14 13:59:54 -0700132 mMissedCallNotifier = missedCallNotifier;
Brad Ebingerc6ab2cc2016-04-07 15:33:52 -0700133 mLock = new Object();
Yorke Leef98fb572014-03-05 10:56:55 -0800134 }
135
Sailesh Nepal810735e2014-03-18 18:15:46 -0700136 @Override
Ihab Awad6fb37c82014-08-07 19:48:57 -0700137 public void onCallStateChanged(Call call, int oldState, int newState) {
Nancy Chenac19f3d2014-10-22 20:09:12 -0700138 int disconnectCause = call.getDisconnectCause().getCode();
Santos Cordon672321e2014-08-21 14:38:58 -0700139 boolean isNewlyDisconnected =
140 newState == CallState.DISCONNECTED || newState == CallState.ABORTED;
Nancy Chenac19f3d2014-10-22 20:09:12 -0700141 boolean isCallCanceled = isNewlyDisconnected && disconnectCause == DisconnectCause.CANCELED;
Santos Cordon672321e2014-08-21 14:38:58 -0700142
143 // Log newly disconnected calls only if:
144 // 1) It was not in the "choose account" phase when disconnected
145 // 2) It is a conference call
146 // 3) Call was not explicitly canceled
Tyler Gunnd1660282016-05-24 18:14:03 -0700147 // 4) Call is not an external call
Tyler Gunn6f6f1c52017-04-17 18:22:04 -0700148 // 5) Call is not a self-managed call OR call is a self-managed call which has indicated it
149 // should be logged in its PhoneAccount
Santos Cordon672321e2014-08-21 14:38:58 -0700150 if (isNewlyDisconnected &&
Santos Cordon92694512015-04-23 14:47:28 -0700151 (oldState != CallState.SELECT_PHONE_ACCOUNT &&
Brad Ebinger4d85d692017-06-26 13:28:06 -0700152 !call.isConference() &&
153 !isCallCanceled) &&
Tyler Gunn9e806ee2017-02-06 20:49:24 -0800154 !call.isExternalCall() &&
Tyler Gunn6f6f1c52017-04-17 18:22:04 -0700155 (!call.isSelfManaged() ||
Brad Ebinger4d85d692017-06-26 13:28:06 -0700156 (call.isLoggedSelfManaged() &&
157 call.getHandoverState() != HandoverState.HANDOVER_FAILED))) {
Sailesh Nepal810735e2014-03-18 18:15:46 -0700158 int type;
159 if (!call.isIncoming()) {
160 type = Calls.OUTGOING_TYPE;
Nancy Chenac19f3d2014-10-22 20:09:12 -0700161 } else if (disconnectCause == DisconnectCause.MISSED) {
Sailesh Nepal810735e2014-03-18 18:15:46 -0700162 type = Calls.MISSED_TYPE;
Tyler Gunn81c7afe2016-06-09 08:08:43 -0700163 } else if (disconnectCause == DisconnectCause.ANSWERED_ELSEWHERE) {
164 type = Calls.ANSWERED_EXTERNALLY_TYPE;
Tyler Gunn21991a72016-07-28 11:33:15 -0700165 } else if (disconnectCause == DisconnectCause.REJECTED) {
166 type = Calls.REJECTED_TYPE;
Sailesh Nepal810735e2014-03-18 18:15:46 -0700167 } else {
168 type = Calls.INCOMING_TYPE;
169 }
Brad Ebinger4d85d692017-06-26 13:28:06 -0700170 // Always show the notification for managed calls. For self-managed calls, it is up to
171 // the app to show the notification, so suppress the notification when logging the call.
Brad Ebinger38141ee2017-07-05 10:09:47 -0700172 boolean showNotification = !call.isSelfManaged();
Brad Ebinger4d85d692017-06-26 13:28:06 -0700173 logCall(call, type, showNotification);
Ta-wei Yen982c0bd2016-04-14 13:59:54 -0700174 }
175 }
176
177 void logCall(Call call, int type, boolean showNotificationForMissedCall) {
178 if (type == Calls.MISSED_TYPE && showNotificationForMissedCall) {
179 logCall(call, Calls.MISSED_TYPE,
180 new LogCallCompletedListener() {
181 @Override
182 public void onLogCompleted(@Nullable Uri uri) {
Hall Liu8755e292016-09-22 14:40:03 -0700183 mMissedCallNotifier.showMissedCallNotification(
184 new MissedCallNotifier.CallInfo(call));
Ta-wei Yen982c0bd2016-04-14 13:59:54 -0700185 }
186 });
187 } else {
188 logCall(call, type, null);
Sailesh Nepal810735e2014-03-18 18:15:46 -0700189 }
Yorke Leef98fb572014-03-05 10:56:55 -0800190 }
191
192 /**
193 * Logs a call to the call log based on the {@link Call} object passed in.
194 *
195 * @param call The call object being logged
196 * @param callLogType The type of call log entry to log this call as. See:
197 * {@link android.provider.CallLog.Calls#INCOMING_TYPE}
198 * {@link android.provider.CallLog.Calls#OUTGOING_TYPE}
199 * {@link android.provider.CallLog.Calls#MISSED_TYPE}
Ta-wei Yen982c0bd2016-04-14 13:59:54 -0700200 * @param logCallCompletedListener optional callback called after the call is logged.
Yorke Leef98fb572014-03-05 10:56:55 -0800201 */
Ta-wei Yen982c0bd2016-04-14 13:59:54 -0700202 void logCall(Call call, int callLogType,
203 @Nullable LogCallCompletedListener logCallCompletedListener) {
Sailesh Nepal8c85dee2014-04-07 22:21:40 -0700204 final long creationTime = call.getCreationTimeMillis();
205 final long age = call.getAgeMillis();
Yorke Leef98fb572014-03-05 10:56:55 -0800206
Yorke Leef98fb572014-03-05 10:56:55 -0800207 final String logNumber = getLogNumber(call);
208
Yorke Lee33501632014-03-17 19:24:12 -0700209 Log.d(TAG, "logNumber set to: %s", Log.pii(logNumber));
Yorke Leef98fb572014-03-05 10:56:55 -0800210
Santos Cordon2c625f32015-03-06 18:53:01 -0800211 final PhoneAccountHandle emergencyAccountHandle =
212 TelephonyUtil.getDefaultEmergencyPhoneAccount().getAccountHandle();
213
Brad Ebingerc6ab2cc2016-04-07 15:33:52 -0700214 String formattedViaNumber = PhoneNumberUtils.formatNumber(call.getViaNumber(),
215 getCountryIso());
216 formattedViaNumber = (formattedViaNumber != null) ?
217 formattedViaNumber : call.getViaNumber();
218
Santos Cordon2c625f32015-03-06 18:53:01 -0800219 PhoneAccountHandle accountHandle = call.getTargetPhoneAccount();
220 if (emergencyAccountHandle.equals(accountHandle)) {
221 accountHandle = null;
222 }
Yorke Leef98fb572014-03-05 10:56:55 -0800223
Tyler Gunn7a1f8232015-12-03 19:52:59 -0800224 Long callDataUsage = call.getCallDataUsage() == Call.DATA_USAGE_NOT_SET ? null :
225 call.getCallDataUsage();
226
Tyler Gunn81c7afe2016-06-09 08:08:43 -0700227 int callFeatures = getCallFeatures(call.getVideoStateHistory(),
228 call.getDisconnectCause().getCode() == DisconnectCause.CALL_PULLED);
Brad Ebingerc6ab2cc2016-04-07 15:33:52 -0700229 logCall(call.getCallerInfo(), logNumber, call.getPostDialDigits(), formattedViaNumber,
Hall Liub8ce19c2015-10-14 15:13:51 -0700230 call.getHandlePresentation(), callLogType, callFeatures, accountHandle,
Ta-wei Yen982c0bd2016-04-14 13:59:54 -0700231 creationTime, age, callDataUsage, call.isEmergencyCall(), call.getInitiatingUser(),
232 logCallCompletedListener);
Yorke Leef98fb572014-03-05 10:56:55 -0800233 }
234
235 /**
236 * Inserts a call into the call log, based on the parameters passed in.
237 *
Yorke Lee6f3f7af2014-07-11 10:59:46 -0700238 * @param callerInfo Caller details.
Yorke Leef98fb572014-03-05 10:56:55 -0800239 * @param number The number the call was made to or from.
Hall Liub8ce19c2015-10-14 15:13:51 -0700240 * @param postDialDigits The post-dial digits that were dialed after the number,
241 * if it was an outgoing call. Otherwise ''.
Yorke Leef98fb572014-03-05 10:56:55 -0800242 * @param presentation
243 * @param callType The type of call.
Tyler Gunn765c35c2014-07-10 08:17:53 -0700244 * @param features The features of the call.
Yorke Leef98fb572014-03-05 10:56:55 -0800245 * @param start The start time of the call, in milliseconds.
246 * @param duration The duration of the call, in milliseconds.
Tyler Gunn765c35c2014-07-10 08:17:53 -0700247 * @param dataUsage The data usage for the call, null if not applicable.
Tyler Gunn6ffe5312015-08-12 08:19:20 -0700248 * @param isEmergency {@code true} if this is an emergency call, {@code false} otherwise.
Ta-wei Yen982c0bd2016-04-14 13:59:54 -0700249 * @param logCallCompletedListener optional callback called after the call is logged.
Yorke Leef98fb572014-03-05 10:56:55 -0800250 */
251 private void logCall(
Yorke Lee6f3f7af2014-07-11 10:59:46 -0700252 CallerInfo callerInfo,
Yorke Leef98fb572014-03-05 10:56:55 -0800253 String number,
Hall Liub8ce19c2015-10-14 15:13:51 -0700254 String postDialDigits,
Brad Ebingerbaf52ba2016-03-21 16:38:32 -0700255 String viaNumber,
Yorke Leef98fb572014-03-05 10:56:55 -0800256 int presentation,
257 int callType,
Tyler Gunn765c35c2014-07-10 08:17:53 -0700258 int features,
Evan Charlton89176372014-07-19 18:23:09 -0700259 PhoneAccountHandle accountHandle,
Yorke Leef98fb572014-03-05 10:56:55 -0800260 long start,
Tyler Gunn765c35c2014-07-10 08:17:53 -0700261 long duration,
Tyler Gunn6ffe5312015-08-12 08:19:20 -0700262 Long dataUsage,
Tony Mak98e6bdc2015-11-25 21:54:05 +0000263 boolean isEmergency,
Ta-wei Yen982c0bd2016-04-14 13:59:54 -0700264 UserHandle initiatingUser,
265 @Nullable LogCallCompletedListener logCallCompletedListener) {
Yorke Leef98fb572014-03-05 10:56:55 -0800266
267 // On some devices, to avoid accidental redialing of emergency numbers, we *never* log
268 // emergency calls to the Call Log. (This behavior is set on a per-product basis, based
269 // on carrier requirements.)
Shishir Agrawala416e072016-02-17 11:14:45 -0800270 boolean okToLogEmergencyNumber = false;
271 CarrierConfigManager configManager = (CarrierConfigManager) mContext.getSystemService(
272 Context.CARRIER_CONFIG_SERVICE);
Honggangc9724682016-07-12 17:04:58 +0800273 PersistableBundle configBundle = configManager.getConfigForSubId(
274 mPhoneAccountRegistrar.getSubscriptionIdForPhoneAccount(accountHandle));
Shishir Agrawala416e072016-02-17 11:14:45 -0800275 if (configBundle != null) {
276 okToLogEmergencyNumber = configBundle.getBoolean(
277 CarrierConfigManager.KEY_ALLOW_EMERGENCY_NUMBERS_IN_CALL_LOG_BOOL);
278 }
Yorke Leef98fb572014-03-05 10:56:55 -0800279
280 // Don't log emergency numbers if the device doesn't allow it.
Tyler Gunn6ffe5312015-08-12 08:19:20 -0700281 final boolean isOkToLogThisCall = !isEmergency || okToLogEmergencyNumber;
Yorke Leef98fb572014-03-05 10:56:55 -0800282
Yong Jiang271b9ae2014-10-09 12:08:54 -0500283 sendAddCallBroadcast(callType, duration);
284
Yorke Leef98fb572014-03-05 10:56:55 -0800285 if (isOkToLogThisCall) {
Yorke Lee6f3f7af2014-07-11 10:59:46 -0700286 Log.d(TAG, "Logging Calllog entry: " + callerInfo + ", "
Yorke Leef98fb572014-03-05 10:56:55 -0800287 + Log.pii(number) + "," + presentation + ", " + callType
288 + ", " + start + ", " + duration);
Hall Liub8ce19c2015-10-14 15:13:51 -0700289 AddCallArgs args = new AddCallArgs(mContext, callerInfo, number, postDialDigits,
Brad Ebingerbaf52ba2016-03-21 16:38:32 -0700290 viaNumber, presentation, callType, features, accountHandle, start, duration,
Ta-wei Yen982c0bd2016-04-14 13:59:54 -0700291 dataUsage, initiatingUser, logCallCompletedListener);
Yorke Leef98fb572014-03-05 10:56:55 -0800292 logCallAsync(args);
293 } else {
294 Log.d(TAG, "Not adding emergency call to call log.");
295 }
296 }
297
298 /**
Tyler Gunn0a388fc2014-07-17 12:21:17 -0700299 * Based on the video state of the call, determines the call features applicable for the call.
300 *
301 * @param videoState The video state.
Tyler Gunn81c7afe2016-06-09 08:08:43 -0700302 * @param isPulledCall {@code true} if this call was pulled to another device.
Tyler Gunn0a388fc2014-07-17 12:21:17 -0700303 * @return The call features.
304 */
Tyler Gunn81c7afe2016-06-09 08:08:43 -0700305 private static int getCallFeatures(int videoState, boolean isPulledCall) {
306 int features = 0;
Tyler Gunn5b882492015-06-03 10:03:13 -0700307 if (VideoProfile.isVideo(videoState)) {
Tyler Gunn81c7afe2016-06-09 08:08:43 -0700308 features |= Calls.FEATURES_VIDEO;
Tyler Gunn0a388fc2014-07-17 12:21:17 -0700309 }
Tyler Gunn81c7afe2016-06-09 08:08:43 -0700310 if (isPulledCall) {
311 features |= Calls.FEATURES_PULLED_EXTERNALLY;
312 }
313 return features;
Tyler Gunn0a388fc2014-07-17 12:21:17 -0700314 }
315
316 /**
Yorke Leef98fb572014-03-05 10:56:55 -0800317 * Retrieve the phone number from the call, and then process it before returning the
318 * actual number that is to be logged.
319 *
320 * @param call The phone connection.
321 * @return the phone number to be logged.
322 */
323 private String getLogNumber(Call call) {
Yorke Lee33501632014-03-17 19:24:12 -0700324 Uri handle = call.getOriginalHandle();
Yorke Leef98fb572014-03-05 10:56:55 -0800325
326 if (handle == null) {
327 return null;
328 }
329
Yorke Lee060d1d62014-03-19 13:24:15 -0700330 String handleString = handle.getSchemeSpecificPart();
Sailesh Nepalce704b92014-03-17 18:31:43 -0700331 if (!PhoneNumberUtils.isUriNumber(handleString)) {
332 handleString = PhoneNumberUtils.stripSeparators(handleString);
Yorke Leef98fb572014-03-05 10:56:55 -0800333 }
Sailesh Nepalce704b92014-03-17 18:31:43 -0700334 return handleString;
Yorke Leef98fb572014-03-05 10:56:55 -0800335 }
336
337 /**
Yorke Leef98fb572014-03-05 10:56:55 -0800338 * Adds the call defined by the parameters in the provided AddCallArgs to the CallLogProvider
339 * using an AsyncTask to avoid blocking the main thread.
340 *
341 * @param args Prepopulated call details.
342 * @return A handle to the AsyncTask that will add the call to the call log asynchronously.
343 */
344 public AsyncTask<AddCallArgs, Void, Uri[]> logCallAsync(AddCallArgs args) {
345 return new LogCallAsyncTask().execute(args);
346 }
347
348 /**
349 * Helper AsyncTask to access the call logs database asynchronously since database operations
350 * can take a long time depending on the system's load. Since it extends AsyncTask, it uses
351 * its own thread pool.
352 */
353 private class LogCallAsyncTask extends AsyncTask<AddCallArgs, Void, Uri[]> {
Ta-wei Yen982c0bd2016-04-14 13:59:54 -0700354
355 private LogCallCompletedListener[] mListeners;
356
Yorke Leef98fb572014-03-05 10:56:55 -0800357 @Override
358 protected Uri[] doInBackground(AddCallArgs... callList) {
359 int count = callList.length;
360 Uri[] result = new Uri[count];
Ta-wei Yen982c0bd2016-04-14 13:59:54 -0700361 mListeners = new LogCallCompletedListener[count];
Yorke Leef98fb572014-03-05 10:56:55 -0800362 for (int i = 0; i < count; i++) {
363 AddCallArgs c = callList[i];
Ta-wei Yen982c0bd2016-04-14 13:59:54 -0700364 mListeners[i] = c.logCallCompletedListener;
Yorke Leef98fb572014-03-05 10:56:55 -0800365 try {
366 // May block.
Tony Mak98e6bdc2015-11-25 21:54:05 +0000367 result[i] = addCall(c);
Yorke Leef98fb572014-03-05 10:56:55 -0800368 } catch (Exception e) {
369 // This is very rare but may happen in legitimate cases.
370 // E.g. If the phone is encrypted and thus write request fails, it may cause
371 // some kind of Exception (right now it is IllegalArgumentException, but this
372 // might change).
373 //
374 // We don't want to crash the whole process just because of that, so just log
375 // it instead.
376 Log.e(TAG, e, "Exception raised during adding CallLog entry.");
377 result[i] = null;
378 }
379 }
380 return result;
381 }
382
Tony Mak98e6bdc2015-11-25 21:54:05 +0000383 private Uri addCall(AddCallArgs c) {
384 PhoneAccount phoneAccount = mPhoneAccountRegistrar
385 .getPhoneAccountUnchecked(c.accountHandle);
Hall Liu71280ff2016-04-11 16:13:48 -0700386 if (phoneAccount != null &&
387 phoneAccount.hasCapabilities(PhoneAccount.CAPABILITY_MULTI_USER)) {
Tony Mak98e6bdc2015-11-25 21:54:05 +0000388 if (c.initiatingUser != null &&
389 UserUtil.isManagedProfile(mContext, c.initiatingUser)) {
390 return addCall(c, c.initiatingUser);
391 } else {
392 return addCall(c, null);
393 }
394 } else {
Hall Liu71280ff2016-04-11 16:13:48 -0700395 return addCall(c, c.accountHandle == null ? null : c.accountHandle.getUserHandle());
Tony Mak98e6bdc2015-11-25 21:54:05 +0000396 }
397 }
398
399 /**
400 * Insert the call to a specific user or all users except managed profile.
401 * @param c context
402 * @param userToBeInserted user handle of user that the call going be inserted to. null
403 * if insert to all users except managed profile.
404 */
405 private Uri addCall(AddCallArgs c, UserHandle userToBeInserted) {
Brad Ebingerbaf52ba2016-03-21 16:38:32 -0700406 return Calls.addCall(c.callerInfo, c.context, c.number, c.postDialDigits, c.viaNumber,
Tony Mak98e6bdc2015-11-25 21:54:05 +0000407 c.presentation, c.callType, c.features, c.accountHandle, c.timestamp,
408 c.durationInSec, c.dataUsage, userToBeInserted == null,
409 userToBeInserted);
410 }
411
Ta-wei Yen982c0bd2016-04-14 13:59:54 -0700412
Yorke Leef98fb572014-03-05 10:56:55 -0800413 @Override
414 protected void onPostExecute(Uri[] result) {
Ta-wei Yen982c0bd2016-04-14 13:59:54 -0700415 for (int i = 0; i < result.length; i++) {
416 Uri uri = result[i];
417 /*
418 Performs a simple sanity check to make sure the call was written in the database.
419 Typically there is only one result per call so it is easy to identify which one
420 failed.
421 */
Yorke Leef98fb572014-03-05 10:56:55 -0800422 if (uri == null) {
423 Log.w(TAG, "Failed to write call to the log.");
424 }
Ta-wei Yen982c0bd2016-04-14 13:59:54 -0700425 if (mListeners[i] != null) {
426 mListeners[i].onLogCompleted(uri);
427 }
Yorke Leef98fb572014-03-05 10:56:55 -0800428 }
429 }
430 }
Yong Jiang271b9ae2014-10-09 12:08:54 -0500431
432 private void sendAddCallBroadcast(int callType, long duration) {
433 Intent callAddIntent = new Intent(ACTION_CALLS_TABLE_ADD_ENTRY);
434 callAddIntent.putExtra(CALL_TYPE, callType);
435 callAddIntent.putExtra(CALL_DURATION, duration);
436 mContext.sendBroadcast(callAddIntent, PERMISSION_PROCESS_CALLLOG_INFO);
437 }
Brad Ebingerc6ab2cc2016-04-07 15:33:52 -0700438
439 private String getCountryIsoFromCountry(Country country) {
440 if(country == null) {
441 // Fallback to Locale if there are issues with CountryDetector
442 Log.w(TAG, "Value for country was null. Falling back to Locale.");
443 return Locale.getDefault().getCountry();
444 }
445
446 return country.getCountryIso();
447 }
448
449 /**
450 * Get the current country code
451 *
452 * @return the ISO 3166-1 two letters country code of current country.
453 */
454 public String getCountryIso() {
455 synchronized (mLock) {
456 if (mCurrentCountryIso == null) {
457 Log.i(TAG, "Country cache is null. Detecting Country and Setting Cache...");
458 final CountryDetector countryDetector =
459 (CountryDetector) mContext.getSystemService(Context.COUNTRY_DETECTOR);
460 Country country = null;
461 if (countryDetector != null) {
462 country = countryDetector.detectCountry();
463
464 countryDetector.addCountryListener((newCountry) -> {
465 Log.startSession("CLM.oCD");
466 try {
467 synchronized (mLock) {
468 Log.i(TAG, "Country ISO changed. Retrieving new ISO...");
469 mCurrentCountryIso = getCountryIsoFromCountry(newCountry);
470 }
471 } finally {
472 Log.endSession();
473 }
474 }, Looper.getMainLooper());
475 }
476 mCurrentCountryIso = getCountryIsoFromCountry(country);
477 }
478 return mCurrentCountryIso;
479 }
480 }
Ben Gilad9f2bed32013-12-12 17:43:26 -0800481}