blob: 35f9481c5f708aeea049d5963a5b2bb0feed6367 [file] [log] [blame]
Eric Erfanianccca3152017-02-22 16:32:36 -08001/*
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.incallui.call;
18
wangqi9982f0d2017-10-11 17:46:07 -070019import android.Manifest.permission;
wangqida410d32018-03-06 16:51:38 -080020import android.annotation.SuppressLint;
wangqi8d407a02018-02-15 15:32:52 -080021import android.annotation.TargetApi;
Eric Erfanianccca3152017-02-22 16:32:36 -080022import android.content.Context;
23import android.hardware.camera2.CameraCharacteristics;
24import android.net.Uri;
erfanian2cf2c342017-12-21 12:01:33 -080025import android.os.Build;
Eric Erfanianccca3152017-02-22 16:32:36 -080026import android.os.Build.VERSION;
27import android.os.Build.VERSION_CODES;
28import android.os.Bundle;
wangqida410d32018-03-06 16:51:38 -080029import android.os.PersistableBundle;
Eric Erfanianccca3152017-02-22 16:32:36 -080030import android.os.Trace;
31import android.support.annotation.IntDef;
Eric Erfaniand5e47f62017-03-15 14:41:07 -070032import android.support.annotation.NonNull;
Eric Erfanianccca3152017-02-22 16:32:36 -080033import android.support.annotation.Nullable;
twyendde01c52017-09-22 10:07:31 -070034import android.support.annotation.VisibleForTesting;
wangqif4ba3452018-01-09 11:26:29 -080035import android.support.v4.os.BuildCompat;
Eric Erfanianccca3152017-02-22 16:32:36 -080036import android.telecom.Call;
37import android.telecom.Call.Details;
wangqi219b8702018-02-13 09:34:41 -080038import android.telecom.Call.RttCall;
Eric Erfanian8369df02017-05-03 10:27:13 -070039import android.telecom.CallAudioState;
Eric Erfanianccca3152017-02-22 16:32:36 -080040import android.telecom.Connection;
41import android.telecom.DisconnectCause;
42import android.telecom.GatewayInfo;
43import android.telecom.InCallService.VideoCall;
44import android.telecom.PhoneAccount;
45import android.telecom.PhoneAccountHandle;
46import android.telecom.StatusHints;
47import android.telecom.TelecomManager;
48import android.telecom.VideoProfile;
Eric Erfanianccca3152017-02-22 16:32:36 -080049import android.text.TextUtils;
roldenburg08424ee2018-03-28 17:02:46 -070050import android.widget.Toast;
Eric Erfanianccca3152017-02-22 16:32:36 -080051import com.android.contacts.common.compat.CallCompat;
Eric Erfanianccca3152017-02-22 16:32:36 -080052import com.android.contacts.common.compat.telecom.TelecomManagerCompat;
erfanian2cf2c342017-12-21 12:01:33 -080053import com.android.dialer.assisteddialing.ConcreteCreator;
erfaniand0f207f2017-10-11 12:23:29 -070054import com.android.dialer.assisteddialing.TransformationInfo;
Eric Erfanian8369df02017-05-03 10:27:13 -070055import com.android.dialer.callintent.CallInitiationType;
Eric Erfanianccca3152017-02-22 16:32:36 -080056import com.android.dialer.callintent.CallIntentParser;
Eric Erfanian8369df02017-05-03 10:27:13 -070057import com.android.dialer.callintent.CallSpecificAppData;
Eric Erfanianccca3152017-02-22 16:32:36 -080058import com.android.dialer.common.Assert;
Eric Erfanianccca3152017-02-22 16:32:36 -080059import com.android.dialer.common.LogUtil;
Eric Erfanian2ca43182017-08-31 06:57:16 -070060import com.android.dialer.compat.telephony.TelephonyManagerCompat;
61import com.android.dialer.configprovider.ConfigProviderBindings;
roldenburg4f026392017-10-13 18:42:20 -070062import com.android.dialer.duo.DuoComponent;
Eric Erfanian8369df02017-05-03 10:27:13 -070063import com.android.dialer.enrichedcall.EnrichedCallCapabilities;
Eric Erfaniand5e47f62017-03-15 14:41:07 -070064import com.android.dialer.enrichedcall.EnrichedCallComponent;
Eric Erfanian2ca43182017-08-31 06:57:16 -070065import com.android.dialer.enrichedcall.EnrichedCallManager;
66import com.android.dialer.enrichedcall.EnrichedCallManager.CapabilitiesListener;
67import com.android.dialer.enrichedcall.EnrichedCallManager.Filter;
68import com.android.dialer.enrichedcall.EnrichedCallManager.StateChangedListener;
Eric Erfanian8369df02017-05-03 10:27:13 -070069import com.android.dialer.enrichedcall.Session;
wangqi9982f0d2017-10-11 17:46:07 -070070import com.android.dialer.location.GeoUtil;
Eric Erfanian8369df02017-05-03 10:27:13 -070071import com.android.dialer.logging.ContactLookupResult;
twyendde01c52017-09-22 10:07:31 -070072import com.android.dialer.logging.ContactLookupResult.Type;
Eric Erfanian8369df02017-05-03 10:27:13 -070073import com.android.dialer.logging.DialerImpression;
74import com.android.dialer.logging.Logger;
twyen73a74c32018-03-07 12:12:24 -080075import com.android.dialer.preferredsim.PreferredAccountRecorder;
twyena4745bd2017-12-12 18:40:11 -080076import com.android.dialer.telecom.TelecomCallUtil;
wangqi9982f0d2017-10-11 17:46:07 -070077import com.android.dialer.telecom.TelecomUtil;
Eric Erfanianc857f902017-05-15 14:05:33 -070078import com.android.dialer.theme.R;
wangqi9982f0d2017-10-11 17:46:07 -070079import com.android.dialer.util.PermissionsUtil;
Eric Erfanian8369df02017-05-03 10:27:13 -070080import com.android.incallui.audiomode.AudioModeProvider;
Eric Erfanianccca3152017-02-22 16:32:36 -080081import com.android.incallui.latencyreport.LatencyReport;
Eric Erfaniand5e47f62017-03-15 14:41:07 -070082import com.android.incallui.videotech.VideoTech;
83import com.android.incallui.videotech.VideoTech.VideoTechListener;
roldenburg4f026392017-10-13 18:42:20 -070084import com.android.incallui.videotech.duo.DuoVideoTech;
Eric Erfaniand5e47f62017-03-15 14:41:07 -070085import com.android.incallui.videotech.empty.EmptyVideoTech;
86import com.android.incallui.videotech.ims.ImsVideoTech;
Eric Erfanian90508232017-03-24 09:31:16 -070087import com.android.incallui.videotech.utils.VideoUtils;
Eric Erfanianccca3152017-02-22 16:32:36 -080088import java.lang.annotation.Retention;
89import java.lang.annotation.RetentionPolicy;
90import java.util.ArrayList;
91import java.util.List;
92import java.util.Locale;
93import java.util.Objects;
94import java.util.UUID;
95import java.util.concurrent.CopyOnWriteArrayList;
96import java.util.concurrent.TimeUnit;
97
98/** Describes a single call and its state. */
Eric Erfanian2ca43182017-08-31 06:57:16 -070099public class DialerCall implements VideoTechListener, StateChangedListener, CapabilitiesListener {
Eric Erfanianccca3152017-02-22 16:32:36 -0800100
101 public static final int CALL_HISTORY_STATUS_UNKNOWN = 0;
102 public static final int CALL_HISTORY_STATUS_PRESENT = 1;
103 public static final int CALL_HISTORY_STATUS_NOT_PRESENT = 2;
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700104
105 // Hard coded property for {@code Call}. Upstreamed change from Motorola.
Eric Erfanian938468d2017-10-24 14:05:52 -0700106 // TODO(a bug): Move it to Telecom in framework.
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700107 public static final int PROPERTY_CODEC_KNOWN = 0x04000000;
108
Eric Erfanianccca3152017-02-22 16:32:36 -0800109 private static final String ID_PREFIX = "DialerCall_";
110 private static final String CONFIG_EMERGENCY_CALLBACK_WINDOW_MILLIS =
111 "emergency_callback_window_millis";
linyuh183cb712017-12-27 17:02:37 -0800112 private static int idCounter = 0;
Eric Erfanianccca3152017-02-22 16:32:36 -0800113
114 /**
Eric Erfanianc857f902017-05-15 14:05:33 -0700115 * A counter used to append to restricted/private/hidden calls so that users can identify them in
116 * a conversation. This value is reset in {@link CallList#onCallRemoved(Context, Call)} when there
117 * are no live calls.
118 */
linyuh183cb712017-12-27 17:02:37 -0800119 private static int hiddenCounter;
Eric Erfanianc857f902017-05-15 14:05:33 -0700120
121 /**
Eric Erfanianccca3152017-02-22 16:32:36 -0800122 * The unique call ID for every call. This will help us to identify each call and allow us the
123 * ability to stitch impressions to calls if needed.
124 */
125 private final String uniqueCallId = UUID.randomUUID().toString();
126
linyuh183cb712017-12-27 17:02:37 -0800127 private final Call telecomCall;
128 private final LatencyReport latencyReport;
129 private final String id;
130 private final int hiddenId;
131 private final List<String> childCallIds = new ArrayList<>();
132 private final LogState logState = new LogState();
133 private final Context context;
134 private final DialerCallDelegate dialerCallDelegate;
135 private final List<DialerCallListener> listeners = new CopyOnWriteArrayList<>();
136 private final List<CannedTextResponsesLoadedListener> cannedTextResponsesLoadedListeners =
Eric Erfanianccca3152017-02-22 16:32:36 -0800137 new CopyOnWriteArrayList<>();
linyuh183cb712017-12-27 17:02:37 -0800138 private final VideoTechManager videoTechManager;
Eric Erfanianccca3152017-02-22 16:32:36 -0800139
erfaniand05d8992018-03-20 19:42:26 -0700140 private boolean isSpeakEasyCall;
linyuh183cb712017-12-27 17:02:37 -0800141 private boolean isEmergencyCall;
142 private Uri handle;
143 private int state = State.INVALID;
144 private DisconnectCause disconnectCause;
Eric Erfanianccca3152017-02-22 16:32:36 -0800145
roldenburg08424ee2018-03-28 17:02:46 -0700146 private boolean hasShownLteToWiFiHandoverToast;
Eric Erfanianccca3152017-02-22 16:32:36 -0800147 private boolean hasShownWiFiToLteHandoverToast;
148 private boolean doNotShowDialogForHandoffToWifiFailure;
149
linyuh183cb712017-12-27 17:02:37 -0800150 private String childNumber;
151 private String lastForwardedNumber;
wangqif4ba3452018-01-09 11:26:29 -0800152 private boolean isCallForwarded;
linyuh183cb712017-12-27 17:02:37 -0800153 private String callSubject;
154 private PhoneAccountHandle phoneAccountHandle;
155 @CallHistoryStatus private int callHistoryStatus = CALL_HISTORY_STATUS_UNKNOWN;
156 private boolean isSpam;
157 private boolean isBlocked;
Eric Erfanian938468d2017-10-24 14:05:52 -0700158
159 @Nullable private Boolean isInUserSpamList;
160
161 @Nullable private Boolean isInUserWhiteList;
162
163 @Nullable private Boolean isInGlobalSpamList;
Eric Erfanianccca3152017-02-22 16:32:36 -0800164 private boolean didShowCameraPermission;
wangqida410d32018-03-06 16:51:38 -0800165 private boolean didDismissVideoChargesAlertDialog;
166 private PersistableBundle carrierConfig;
Eric Erfanianccca3152017-02-22 16:32:36 -0800167 private String callProviderLabel;
168 private String callbackNumber;
linyuh183cb712017-12-27 17:02:37 -0800169 private int cameraDirection = CameraDirection.CAMERA_DIRECTION_UNKNOWN;
170 private EnrichedCallCapabilities enrichedCallCapabilities;
171 private Session enrichedCallSession;
Eric Erfanianccca3152017-02-22 16:32:36 -0800172
Eric Erfanian2ca43182017-08-31 06:57:16 -0700173 private int answerAndReleaseButtonDisplayedTimes = 0;
174 private boolean releasedByAnsweringSecondCall = false;
175 // Times when a second call is received but AnswerAndRelease button is not shown
176 // since it's not supported.
177 private int secondCallWithoutAnswerAndReleasedButtonTimes = 0;
roldenburg7bb96232017-10-09 10:32:05 -0700178 private VideoTech videoTech;
Eric Erfanian2ca43182017-08-31 06:57:16 -0700179
wangqi4d705e52017-09-28 12:23:35 -0700180 private com.android.dialer.logging.VideoTech.Type selectedAvailableVideoTechType =
181 com.android.dialer.logging.VideoTech.Type.NONE;
wangqi9982f0d2017-10-11 17:46:07 -0700182 private boolean isVoicemailNumber;
183 private List<PhoneAccountHandle> callCapableAccounts;
184 private String countryIso;
yueg457b3972017-09-18 15:11:47 -0700185
Android Dialer974fc292018-02-01 16:12:25 -0800186 private volatile boolean feedbackRequested = false;
187
twyen73a74c32018-03-07 12:12:24 -0800188 @Nullable private PreferredAccountRecorder preferredAccountRecorder;
189
Eric Erfanianccca3152017-02-22 16:32:36 -0800190 public static String getNumberFromHandle(Uri handle) {
191 return handle == null ? "" : handle.getSchemeSpecificPart();
192 }
193
194 /**
195 * Whether the call is put on hold by remote party. This is different than the {@link
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700196 * State#ONHOLD} state which indicates that the call is being held locally on the device.
Eric Erfanianccca3152017-02-22 16:32:36 -0800197 */
198 private boolean isRemotelyHeld;
199
Eric Erfanian2ca43182017-08-31 06:57:16 -0700200 /** Indicates whether this call is currently in the process of being merged into a conference. */
201 private boolean isMergeInProcess;
202
Eric Erfanianccca3152017-02-22 16:32:36 -0800203 /**
204 * Indicates whether the phone account associated with this call supports specifying a call
205 * subject.
206 */
linyuh183cb712017-12-27 17:02:37 -0800207 private boolean isCallSubjectSupported;
Eric Erfanianccca3152017-02-22 16:32:36 -0800208
linyuh183cb712017-12-27 17:02:37 -0800209 private final Call.Callback telecomCallCallback =
Eric Erfanianccca3152017-02-22 16:32:36 -0800210 new Call.Callback() {
211 @Override
212 public void onStateChanged(Call call, int newState) {
213 LogUtil.v("TelecomCallCallback.onStateChanged", "call=" + call + " newState=" + newState);
214 update();
215 }
216
217 @Override
218 public void onParentChanged(Call call, Call newParent) {
219 LogUtil.v(
220 "TelecomCallCallback.onParentChanged", "call=" + call + " newParent=" + newParent);
221 update();
222 }
223
224 @Override
225 public void onChildrenChanged(Call call, List<Call> children) {
226 update();
227 }
228
229 @Override
230 public void onDetailsChanged(Call call, Call.Details details) {
Eric Erfanian2ca43182017-08-31 06:57:16 -0700231 LogUtil.v(
232 "TelecomCallCallback.onDetailsChanged", " call=" + call + " details=" + details);
Eric Erfanianccca3152017-02-22 16:32:36 -0800233 update();
234 }
235
236 @Override
237 public void onCannedTextResponsesLoaded(Call call, List<String> cannedTextResponses) {
238 LogUtil.v(
Eric Erfanian2ca43182017-08-31 06:57:16 -0700239 "TelecomCallCallback.onCannedTextResponsesLoaded",
Eric Erfanianccca3152017-02-22 16:32:36 -0800240 "call=" + call + " cannedTextResponses=" + cannedTextResponses);
linyuh183cb712017-12-27 17:02:37 -0800241 for (CannedTextResponsesLoadedListener listener : cannedTextResponsesLoadedListeners) {
Eric Erfanianccca3152017-02-22 16:32:36 -0800242 listener.onCannedTextResponsesLoaded(DialerCall.this);
243 }
244 }
245
246 @Override
247 public void onPostDialWait(Call call, String remainingPostDialSequence) {
248 LogUtil.v(
Eric Erfanian2ca43182017-08-31 06:57:16 -0700249 "TelecomCallCallback.onPostDialWait",
Eric Erfanianccca3152017-02-22 16:32:36 -0800250 "call=" + call + " remainingPostDialSequence=" + remainingPostDialSequence);
251 update();
252 }
253
254 @Override
255 public void onVideoCallChanged(Call call, VideoCall videoCall) {
256 LogUtil.v(
Eric Erfanian2ca43182017-08-31 06:57:16 -0700257 "TelecomCallCallback.onVideoCallChanged", "call=" + call + " videoCall=" + videoCall);
Eric Erfanianccca3152017-02-22 16:32:36 -0800258 update();
259 }
260
261 @Override
262 public void onCallDestroyed(Call call) {
Eric Erfanian2ca43182017-08-31 06:57:16 -0700263 LogUtil.v("TelecomCallCallback.onCallDestroyed", "call=" + call);
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700264 unregisterCallback();
Eric Erfanianccca3152017-02-22 16:32:36 -0800265 }
266
267 @Override
268 public void onConferenceableCallsChanged(Call call, List<Call> conferenceableCalls) {
269 LogUtil.v(
Eric Erfanian2ca43182017-08-31 06:57:16 -0700270 "TelecomCallCallback.onConferenceableCallsChanged",
Eric Erfanianccca3152017-02-22 16:32:36 -0800271 "call %s, conferenceable calls: %d",
272 call,
273 conferenceableCalls.size());
274 update();
275 }
276
277 @Override
wangqi219b8702018-02-13 09:34:41 -0800278 public void onRttModeChanged(Call call, int mode) {
279 LogUtil.v("TelecomCallCallback.onRttModeChanged", "mode=%d", mode);
280 }
281
282 @Override
283 public void onRttRequest(Call call, int id) {
284 LogUtil.v("TelecomCallCallback.onRttRequest", "id=%d", id);
wangqibc28ea72018-04-02 16:23:00 -0700285 for (DialerCallListener listener : listeners) {
286 listener.onDialerCallUpgradeToRtt(id);
287 }
wangqi219b8702018-02-13 09:34:41 -0800288 }
289
290 @Override
291 public void onRttInitiationFailure(Call call, int reason) {
292 LogUtil.v("TelecomCallCallback.onRttInitiationFailure", "reason=%d", reason);
293 update();
294 }
295
296 @Override
297 public void onRttStatusChanged(Call call, boolean enabled, RttCall rttCall) {
298 LogUtil.v("TelecomCallCallback.onRttStatusChanged", "enabled=%b", enabled);
299 update();
300 }
301
302 @Override
Eric Erfanianccca3152017-02-22 16:32:36 -0800303 public void onConnectionEvent(android.telecom.Call call, String event, Bundle extras) {
304 LogUtil.v(
Eric Erfanian2ca43182017-08-31 06:57:16 -0700305 "TelecomCallCallback.onConnectionEvent",
Eric Erfanianccca3152017-02-22 16:32:36 -0800306 "Call: " + call + ", Event: " + event + ", Extras: " + extras);
307 switch (event) {
308 // The Previous attempt to Merge two calls together has failed in Telecom. We must
309 // now update the UI to possibly re-enable the Merge button based on the number of
310 // currently conferenceable calls available or Connection Capabilities.
311 case android.telecom.Connection.EVENT_CALL_MERGE_FAILED:
312 update();
313 break;
314 case TelephonyManagerCompat.EVENT_HANDOVER_VIDEO_FROM_WIFI_TO_LTE:
315 notifyWiFiToLteHandover();
316 break;
roldenburg08424ee2018-03-28 17:02:46 -0700317 case TelephonyManagerCompat.EVENT_HANDOVER_VIDEO_FROM_LTE_TO_WIFI:
318 onLteToWifiHandover();
319 break;
Eric Erfanianccca3152017-02-22 16:32:36 -0800320 case TelephonyManagerCompat.EVENT_HANDOVER_TO_WIFI_FAILED:
321 notifyHandoverToWifiFailed();
322 break;
323 case TelephonyManagerCompat.EVENT_CALL_REMOTELY_HELD:
324 isRemotelyHeld = true;
325 update();
326 break;
327 case TelephonyManagerCompat.EVENT_CALL_REMOTELY_UNHELD:
328 isRemotelyHeld = false;
329 update();
330 break;
Eric Erfanianc857f902017-05-15 14:05:33 -0700331 case TelephonyManagerCompat.EVENT_NOTIFY_INTERNATIONAL_CALL_ON_WFC:
332 notifyInternationalCallOnWifi();
333 break;
Eric Erfanian2ca43182017-08-31 06:57:16 -0700334 case TelephonyManagerCompat.EVENT_MERGE_START:
335 LogUtil.i("DialerCall.onConnectionEvent", "merge start");
336 isMergeInProcess = true;
337 break;
338 case TelephonyManagerCompat.EVENT_MERGE_COMPLETE:
339 LogUtil.i("DialerCall.onConnectionEvent", "merge complete");
340 isMergeInProcess = false;
341 break;
wangqif4ba3452018-01-09 11:26:29 -0800342 case TelephonyManagerCompat.EVENT_CALL_FORWARDED:
343 // Only handle this event for P+ since it's unreliable pre-P.
344 if (BuildCompat.isAtLeastP()) {
345 isCallForwarded = true;
346 update();
347 }
348 break;
Eric Erfanianccca3152017-02-22 16:32:36 -0800349 default:
350 break;
351 }
352 }
353 };
Eric Erfanianc857f902017-05-15 14:05:33 -0700354
linyuh183cb712017-12-27 17:02:37 -0800355 private long timeAddedMs;
Eric Erfanianccca3152017-02-22 16:32:36 -0800356
357 public DialerCall(
358 Context context,
359 DialerCallDelegate dialerCallDelegate,
360 Call telecomCall,
361 LatencyReport latencyReport,
362 boolean registerCallback) {
363 Assert.isNotNull(context);
linyuh183cb712017-12-27 17:02:37 -0800364 this.context = context;
365 this.dialerCallDelegate = dialerCallDelegate;
366 this.telecomCall = telecomCall;
367 this.latencyReport = latencyReport;
368 id = ID_PREFIX + Integer.toString(idCounter++);
Eric Erfanianccca3152017-02-22 16:32:36 -0800369
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700370 // Must be after assigning mTelecomCall
linyuh183cb712017-12-27 17:02:37 -0800371 videoTechManager = new VideoTechManager(this);
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700372
373 updateFromTelecomCall();
Eric Erfanianc857f902017-05-15 14:05:33 -0700374 if (isHiddenNumber() && TextUtils.isEmpty(getNumber())) {
linyuh183cb712017-12-27 17:02:37 -0800375 hiddenId = ++hiddenCounter;
Eric Erfanianc857f902017-05-15 14:05:33 -0700376 } else {
linyuh183cb712017-12-27 17:02:37 -0800377 hiddenId = 0;
Eric Erfanianc857f902017-05-15 14:05:33 -0700378 }
Eric Erfanianccca3152017-02-22 16:32:36 -0800379
380 if (registerCallback) {
linyuh183cb712017-12-27 17:02:37 -0800381 this.telecomCall.registerCallback(telecomCallCallback);
Eric Erfanianccca3152017-02-22 16:32:36 -0800382 }
383
linyuh183cb712017-12-27 17:02:37 -0800384 timeAddedMs = System.currentTimeMillis();
Eric Erfanianccca3152017-02-22 16:32:36 -0800385 parseCallSpecificAppData();
Eric Erfanian2ca43182017-08-31 06:57:16 -0700386
387 updateEnrichedCallSession();
Eric Erfanianccca3152017-02-22 16:32:36 -0800388 }
389
twyendde01c52017-09-22 10:07:31 -0700390 /** Test only constructor to avoid initializing dependencies. */
391 @VisibleForTesting
392 DialerCall(Context context) {
linyuh183cb712017-12-27 17:02:37 -0800393 this.context = context;
394 telecomCall = null;
395 latencyReport = null;
396 id = null;
397 hiddenId = 0;
398 dialerCallDelegate = null;
399 videoTechManager = null;
twyendde01c52017-09-22 10:07:31 -0700400 }
401
Eric Erfanianccca3152017-02-22 16:32:36 -0800402 private static int translateState(int state) {
403 switch (state) {
404 case Call.STATE_NEW:
405 case Call.STATE_CONNECTING:
406 return DialerCall.State.CONNECTING;
407 case Call.STATE_SELECT_PHONE_ACCOUNT:
408 return DialerCall.State.SELECT_PHONE_ACCOUNT;
409 case Call.STATE_DIALING:
410 return DialerCall.State.DIALING;
411 case Call.STATE_PULLING_CALL:
412 return DialerCall.State.PULLING;
413 case Call.STATE_RINGING:
414 return DialerCall.State.INCOMING;
415 case Call.STATE_ACTIVE:
416 return DialerCall.State.ACTIVE;
417 case Call.STATE_HOLDING:
418 return DialerCall.State.ONHOLD;
419 case Call.STATE_DISCONNECTED:
420 return DialerCall.State.DISCONNECTED;
421 case Call.STATE_DISCONNECTING:
422 return DialerCall.State.DISCONNECTING;
423 default:
424 return DialerCall.State.INVALID;
425 }
426 }
427
428 public static boolean areSame(DialerCall call1, DialerCall call2) {
429 if (call1 == null && call2 == null) {
430 return true;
431 } else if (call1 == null || call2 == null) {
432 return false;
433 }
434
435 // otherwise compare call Ids
436 return call1.getId().equals(call2.getId());
437 }
438
Eric Erfanianccca3152017-02-22 16:32:36 -0800439 public void addListener(DialerCallListener listener) {
440 Assert.isMainThread();
linyuh183cb712017-12-27 17:02:37 -0800441 listeners.add(listener);
Eric Erfanianccca3152017-02-22 16:32:36 -0800442 }
443
444 public void removeListener(DialerCallListener listener) {
445 Assert.isMainThread();
linyuh183cb712017-12-27 17:02:37 -0800446 listeners.remove(listener);
Eric Erfanianccca3152017-02-22 16:32:36 -0800447 }
448
449 public void addCannedTextResponsesLoadedListener(CannedTextResponsesLoadedListener listener) {
450 Assert.isMainThread();
linyuh183cb712017-12-27 17:02:37 -0800451 cannedTextResponsesLoadedListeners.add(listener);
Eric Erfanianccca3152017-02-22 16:32:36 -0800452 }
453
454 public void removeCannedTextResponsesLoadedListener(CannedTextResponsesLoadedListener listener) {
455 Assert.isMainThread();
linyuh183cb712017-12-27 17:02:37 -0800456 cannedTextResponsesLoadedListeners.remove(listener);
Eric Erfanianccca3152017-02-22 16:32:36 -0800457 }
458
roldenburg08424ee2018-03-28 17:02:46 -0700459 private void onLteToWifiHandover() {
460 LogUtil.enterBlock("DialerCall.onLteToWifiHandover");
461 if (hasShownLteToWiFiHandoverToast) {
462 return;
463 }
464
465 Toast.makeText(context, R.string.video_call_lte_to_wifi_handover_toast, Toast.LENGTH_LONG)
466 .show();
467 hasShownLteToWiFiHandoverToast = true;
468 }
469
Eric Erfanianccca3152017-02-22 16:32:36 -0800470 public void notifyWiFiToLteHandover() {
471 LogUtil.i("DialerCall.notifyWiFiToLteHandover", "");
linyuh183cb712017-12-27 17:02:37 -0800472 for (DialerCallListener listener : listeners) {
Eric Erfanianccca3152017-02-22 16:32:36 -0800473 listener.onWiFiToLteHandover();
474 }
475 }
476
477 public void notifyHandoverToWifiFailed() {
478 LogUtil.i("DialerCall.notifyHandoverToWifiFailed", "");
linyuh183cb712017-12-27 17:02:37 -0800479 for (DialerCallListener listener : listeners) {
Eric Erfanianccca3152017-02-22 16:32:36 -0800480 listener.onHandoverToWifiFailure();
481 }
482 }
483
Eric Erfanianc857f902017-05-15 14:05:33 -0700484 public void notifyInternationalCallOnWifi() {
485 LogUtil.enterBlock("DialerCall.notifyInternationalCallOnWifi");
linyuh183cb712017-12-27 17:02:37 -0800486 for (DialerCallListener dialerCallListener : listeners) {
Eric Erfanianc857f902017-05-15 14:05:33 -0700487 dialerCallListener.onInternationalCallOnWifi();
488 }
489 }
490
Eric Erfanianccca3152017-02-22 16:32:36 -0800491 /* package-private */ Call getTelecomCall() {
linyuh183cb712017-12-27 17:02:37 -0800492 return telecomCall;
Eric Erfanianccca3152017-02-22 16:32:36 -0800493 }
wangqida410d32018-03-06 16:51:38 -0800494
Eric Erfanianccca3152017-02-22 16:32:36 -0800495 public StatusHints getStatusHints() {
linyuh183cb712017-12-27 17:02:37 -0800496 return telecomCall.getDetails().getStatusHints();
Eric Erfanianccca3152017-02-22 16:32:36 -0800497 }
498
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700499 public int getCameraDir() {
linyuh183cb712017-12-27 17:02:37 -0800500 return cameraDirection;
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700501 }
502
503 public void setCameraDir(int cameraDir) {
504 if (cameraDir == CameraDirection.CAMERA_DIRECTION_FRONT_FACING
505 || cameraDir == CameraDirection.CAMERA_DIRECTION_BACK_FACING) {
linyuh183cb712017-12-27 17:02:37 -0800506 cameraDirection = cameraDir;
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700507 } else {
linyuh183cb712017-12-27 17:02:37 -0800508 cameraDirection = CameraDirection.CAMERA_DIRECTION_UNKNOWN;
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700509 }
Eric Erfanianccca3152017-02-22 16:32:36 -0800510 }
511
Eric Erfanian2ca43182017-08-31 06:57:16 -0700512 public boolean wasParentCall() {
linyuh183cb712017-12-27 17:02:37 -0800513 return logState.conferencedCalls != 0;
Eric Erfanian2ca43182017-08-31 06:57:16 -0700514 }
515
wangqi9982f0d2017-10-11 17:46:07 -0700516 public boolean isVoiceMailNumber() {
517 return isVoicemailNumber;
518 }
519
520 public List<PhoneAccountHandle> getCallCapableAccounts() {
521 return callCapableAccounts;
522 }
523
524 public String getCountryIso() {
525 return countryIso;
526 }
527
528 private void updateIsVoiceMailNumber() {
529 if (getHandle() != null && PhoneAccount.SCHEME_VOICEMAIL.equals(getHandle().getScheme())) {
530 isVoicemailNumber = true;
roldenburg37a969d2018-02-22 14:46:44 -0800531 return;
wangqi9982f0d2017-10-11 17:46:07 -0700532 }
533
linyuh183cb712017-12-27 17:02:37 -0800534 if (!PermissionsUtil.hasPermission(context, permission.READ_PHONE_STATE)) {
wangqi9982f0d2017-10-11 17:46:07 -0700535 isVoicemailNumber = false;
roldenburg37a969d2018-02-22 14:46:44 -0800536 return;
wangqi9982f0d2017-10-11 17:46:07 -0700537 }
538
linyuh183cb712017-12-27 17:02:37 -0800539 isVoicemailNumber = TelecomUtil.isVoicemailNumber(context, getAccountHandle(), getNumber());
wangqi9982f0d2017-10-11 17:46:07 -0700540 }
541
Eric Erfanianccca3152017-02-22 16:32:36 -0800542 private void update() {
Eric Erfanian2ca43182017-08-31 06:57:16 -0700543 Trace.beginSection("DialerCall.update");
Eric Erfanianccca3152017-02-22 16:32:36 -0800544 int oldState = getState();
roldenburg7bb96232017-10-09 10:32:05 -0700545 // Clear any cache here that could potentially change on update.
546 videoTech = null;
Eric Erfanianccca3152017-02-22 16:32:36 -0800547 // We want to potentially register a video call callback here.
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700548 updateFromTelecomCall();
Eric Erfanianccca3152017-02-22 16:32:36 -0800549 if (oldState != getState() && getState() == DialerCall.State.DISCONNECTED) {
linyuh183cb712017-12-27 17:02:37 -0800550 for (DialerCallListener listener : listeners) {
Eric Erfanianccca3152017-02-22 16:32:36 -0800551 listener.onDialerCallDisconnect();
552 }
linyuh183cb712017-12-27 17:02:37 -0800553 EnrichedCallComponent.get(context)
Eric Erfanian2ca43182017-08-31 06:57:16 -0700554 .getEnrichedCallManager()
555 .unregisterCapabilitiesListener(this);
linyuh183cb712017-12-27 17:02:37 -0800556 EnrichedCallComponent.get(context)
Eric Erfanian2ca43182017-08-31 06:57:16 -0700557 .getEnrichedCallManager()
558 .unregisterStateChangedListener(this);
Eric Erfanianccca3152017-02-22 16:32:36 -0800559 } else {
linyuh183cb712017-12-27 17:02:37 -0800560 for (DialerCallListener listener : listeners) {
Eric Erfanianccca3152017-02-22 16:32:36 -0800561 listener.onDialerCallUpdate();
562 }
563 }
564 Trace.endSection();
565 }
566
wangqi9982f0d2017-10-11 17:46:07 -0700567 @SuppressWarnings("MissingPermission")
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700568 private void updateFromTelecomCall() {
Eric Erfanian2ca43182017-08-31 06:57:16 -0700569 Trace.beginSection("DialerCall.updateFromTelecomCall");
linyuh183cb712017-12-27 17:02:37 -0800570 LogUtil.v("DialerCall.updateFromTelecomCall", telecomCall.toString());
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700571
roldenburg6bd612f2018-01-18 12:57:19 -0800572 videoTechManager.dispatchCallStateChanged(telecomCall.getState(), getAccountHandle());
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700573
linyuh183cb712017-12-27 17:02:37 -0800574 final int translatedState = translateState(telecomCall.getState());
575 if (state != State.BLOCKED) {
Eric Erfanianccca3152017-02-22 16:32:36 -0800576 setState(translatedState);
linyuh183cb712017-12-27 17:02:37 -0800577 setDisconnectCause(telecomCall.getDetails().getDisconnectCause());
Eric Erfanianccca3152017-02-22 16:32:36 -0800578 }
579
linyuh183cb712017-12-27 17:02:37 -0800580 childCallIds.clear();
581 final int numChildCalls = telecomCall.getChildren().size();
Eric Erfanianccca3152017-02-22 16:32:36 -0800582 for (int i = 0; i < numChildCalls; i++) {
linyuh183cb712017-12-27 17:02:37 -0800583 childCallIds.add(
584 dialerCallDelegate
585 .getDialerCallFromTelecomCall(telecomCall.getChildren().get(i))
Eric Erfanianccca3152017-02-22 16:32:36 -0800586 .getId());
587 }
588
589 // The number of conferenced calls can change over the course of the call, so use the
590 // maximum number of conferenced child calls as the metric for conference call usage.
linyuh183cb712017-12-27 17:02:37 -0800591 logState.conferencedCalls = Math.max(numChildCalls, logState.conferencedCalls);
Eric Erfanianccca3152017-02-22 16:32:36 -0800592
linyuh183cb712017-12-27 17:02:37 -0800593 updateFromCallExtras(telecomCall.getDetails().getExtras());
Eric Erfanianccca3152017-02-22 16:32:36 -0800594
595 // If the handle of the call has changed, update state for the call determining if it is an
596 // emergency call.
linyuh183cb712017-12-27 17:02:37 -0800597 Uri newHandle = telecomCall.getDetails().getHandle();
598 if (!Objects.equals(handle, newHandle)) {
599 handle = newHandle;
Eric Erfanianccca3152017-02-22 16:32:36 -0800600 updateEmergencyCallState();
601 }
602
linyuh183cb712017-12-27 17:02:37 -0800603 TelecomManager telecomManager = context.getSystemService(TelecomManager.class);
Eric Erfanianccca3152017-02-22 16:32:36 -0800604 // If the phone account handle of the call is set, cache capability bit indicating whether
605 // the phone account supports call subjects.
linyuh183cb712017-12-27 17:02:37 -0800606 PhoneAccountHandle newPhoneAccountHandle = telecomCall.getDetails().getAccountHandle();
607 if (!Objects.equals(phoneAccountHandle, newPhoneAccountHandle)) {
608 phoneAccountHandle = newPhoneAccountHandle;
Eric Erfanianccca3152017-02-22 16:32:36 -0800609
linyuh183cb712017-12-27 17:02:37 -0800610 if (phoneAccountHandle != null) {
611 PhoneAccount phoneAccount = telecomManager.getPhoneAccount(phoneAccountHandle);
Eric Erfanianccca3152017-02-22 16:32:36 -0800612 if (phoneAccount != null) {
linyuh183cb712017-12-27 17:02:37 -0800613 isCallSubjectSupported =
Eric Erfanianccca3152017-02-22 16:32:36 -0800614 phoneAccount.hasCapabilities(PhoneAccount.CAPABILITY_CALL_SUBJECT);
wangqida410d32018-03-06 16:51:38 -0800615 if (phoneAccount.hasCapabilities(PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION)) {
616 cacheCarrierConfiguration(phoneAccountHandle);
617 }
Eric Erfanianccca3152017-02-22 16:32:36 -0800618 }
619 }
620 }
linyuh183cb712017-12-27 17:02:37 -0800621 if (PermissionsUtil.hasPermission(context, permission.READ_PHONE_STATE)) {
wangqi9982f0d2017-10-11 17:46:07 -0700622 updateIsVoiceMailNumber();
623 callCapableAccounts = telecomManager.getCallCapablePhoneAccounts();
linyuh183cb712017-12-27 17:02:37 -0800624 countryIso = GeoUtil.getCurrentCountryIso(context);
wangqi9982f0d2017-10-11 17:46:07 -0700625 }
Eric Erfanian2ca43182017-08-31 06:57:16 -0700626 Trace.endSection();
Eric Erfanianccca3152017-02-22 16:32:36 -0800627 }
628
629 /**
wangqida410d32018-03-06 16:51:38 -0800630 * Caches frequently used carrier configuration locally.
631 *
632 * @param accountHandle The PhoneAccount handle.
633 */
634 @SuppressLint("MissingPermission")
635 private void cacheCarrierConfiguration(PhoneAccountHandle accountHandle) {
636 if (!PermissionsUtil.hasPermission(context, permission.READ_PHONE_STATE)) {
637 return;
638 }
639 if (VERSION.SDK_INT < VERSION_CODES.O) {
640 return;
641 }
642 // TODO(a bug): This may take several seconds to complete, revisit it to move it to worker
643 // thread.
644 carrierConfig =
645 TelephonyManagerCompat.getTelephonyManagerForPhoneAccountHandle(context, accountHandle)
646 .getCarrierConfig();
647 }
648
649 /**
Eric Erfanianccca3152017-02-22 16:32:36 -0800650 * Tests corruption of the {@code callExtras} bundle by calling {@link
651 * Bundle#containsKey(String)}. If the bundle is corrupted a {@link IllegalArgumentException} will
652 * be thrown and caught by this function.
653 *
654 * @param callExtras the bundle to verify
655 * @return {@code true} if the bundle is corrupted, {@code false} otherwise.
656 */
657 protected boolean areCallExtrasCorrupted(Bundle callExtras) {
658 /**
Eric Erfanian938468d2017-10-24 14:05:52 -0700659 * There's currently a bug in Telephony service (a bug) that could corrupt the extras
Eric Erfanianccca3152017-02-22 16:32:36 -0800660 * bundle, resulting in a IllegalArgumentException while validating data under {@link
661 * Bundle#containsKey(String)}.
662 */
663 try {
664 callExtras.containsKey(Connection.EXTRA_CHILD_ADDRESS);
665 return false;
666 } catch (IllegalArgumentException e) {
667 LogUtil.e(
668 "DialerCall.areCallExtrasCorrupted", "callExtras is corrupted, ignoring exception", e);
669 return true;
670 }
671 }
672
673 protected void updateFromCallExtras(Bundle callExtras) {
674 if (callExtras == null || areCallExtrasCorrupted(callExtras)) {
675 /**
676 * If the bundle is corrupted, abandon information update as a work around. These are not
677 * critical for the dialer to function.
678 */
679 return;
680 }
681 // Check for a change in the child address and notify any listeners.
682 if (callExtras.containsKey(Connection.EXTRA_CHILD_ADDRESS)) {
683 String childNumber = callExtras.getString(Connection.EXTRA_CHILD_ADDRESS);
linyuh183cb712017-12-27 17:02:37 -0800684 if (!Objects.equals(childNumber, this.childNumber)) {
685 this.childNumber = childNumber;
686 for (DialerCallListener listener : listeners) {
Eric Erfanianccca3152017-02-22 16:32:36 -0800687 listener.onDialerCallChildNumberChange();
688 }
689 }
690 }
691
692 // Last forwarded number comes in as an array of strings. We want to choose the
693 // last item in the array. The forwarding numbers arrive independently of when the
694 // call is originally set up, so we need to notify the the UI of the change.
695 if (callExtras.containsKey(Connection.EXTRA_LAST_FORWARDED_NUMBER)) {
696 ArrayList<String> lastForwardedNumbers =
697 callExtras.getStringArrayList(Connection.EXTRA_LAST_FORWARDED_NUMBER);
698
699 if (lastForwardedNumbers != null) {
700 String lastForwardedNumber = null;
701 if (!lastForwardedNumbers.isEmpty()) {
702 lastForwardedNumber = lastForwardedNumbers.get(lastForwardedNumbers.size() - 1);
703 }
704
linyuh183cb712017-12-27 17:02:37 -0800705 if (!Objects.equals(lastForwardedNumber, this.lastForwardedNumber)) {
706 this.lastForwardedNumber = lastForwardedNumber;
707 for (DialerCallListener listener : listeners) {
Eric Erfanianccca3152017-02-22 16:32:36 -0800708 listener.onDialerCallLastForwardedNumberChange();
709 }
710 }
711 }
712 }
713
714 // DialerCall subject is present in the extras at the start of call, so we do not need to
715 // notify any other listeners of this.
716 if (callExtras.containsKey(Connection.EXTRA_CALL_SUBJECT)) {
717 String callSubject = callExtras.getString(Connection.EXTRA_CALL_SUBJECT);
linyuh183cb712017-12-27 17:02:37 -0800718 if (!Objects.equals(this.callSubject, callSubject)) {
719 this.callSubject = callSubject;
Eric Erfanianccca3152017-02-22 16:32:36 -0800720 }
721 }
722 }
723
Eric Erfanianccca3152017-02-22 16:32:36 -0800724 public String getId() {
linyuh183cb712017-12-27 17:02:37 -0800725 return id;
Eric Erfanianccca3152017-02-22 16:32:36 -0800726 }
727
Eric Erfanianc857f902017-05-15 14:05:33 -0700728 /**
729 * @return name appended with a number if the number is restricted/unknown and the user has
730 * received more than one restricted/unknown call.
731 */
732 @Nullable
733 public String updateNameIfRestricted(@Nullable String name) {
linyuh183cb712017-12-27 17:02:37 -0800734 if (name != null && isHiddenNumber() && hiddenId != 0 && hiddenCounter > 1) {
735 return context.getString(R.string.unknown_counter, name, hiddenId);
Eric Erfanianc857f902017-05-15 14:05:33 -0700736 }
737 return name;
738 }
739
740 public static void clearRestrictedCount() {
linyuh183cb712017-12-27 17:02:37 -0800741 hiddenCounter = 0;
Eric Erfanianc857f902017-05-15 14:05:33 -0700742 }
743
744 private boolean isHiddenNumber() {
745 return getNumberPresentation() == TelecomManager.PRESENTATION_RESTRICTED
746 || getNumberPresentation() == TelecomManager.PRESENTATION_UNKNOWN;
747 }
748
Eric Erfanianccca3152017-02-22 16:32:36 -0800749 public boolean hasShownWiFiToLteHandoverToast() {
750 return hasShownWiFiToLteHandoverToast;
751 }
752
753 public void setHasShownWiFiToLteHandoverToast() {
754 hasShownWiFiToLteHandoverToast = true;
755 }
756
757 public boolean showWifiHandoverAlertAsToast() {
758 return doNotShowDialogForHandoffToWifiFailure;
759 }
760
761 public void setDoNotShowDialogForHandoffToWifiFailure(boolean bool) {
762 doNotShowDialogForHandoffToWifiFailure = bool;
763 }
764
wangqida410d32018-03-06 16:51:38 -0800765 public boolean showVideoChargesAlertDialog() {
766 if (carrierConfig == null) {
767 return false;
768 }
769 return carrierConfig.getBoolean(
770 TelephonyManagerCompat.CARRIER_CONFIG_KEY_SHOW_VIDEO_CALL_CHARGES_ALERT_DIALOG_BOOL);
771 }
772
Eric Erfanianccca3152017-02-22 16:32:36 -0800773 public long getTimeAddedMs() {
linyuh183cb712017-12-27 17:02:37 -0800774 return timeAddedMs;
Eric Erfanianccca3152017-02-22 16:32:36 -0800775 }
776
777 @Nullable
778 public String getNumber() {
linyuh183cb712017-12-27 17:02:37 -0800779 return TelecomCallUtil.getNumber(telecomCall);
Eric Erfanianccca3152017-02-22 16:32:36 -0800780 }
781
782 public void blockCall() {
linyuh183cb712017-12-27 17:02:37 -0800783 telecomCall.reject(false, null);
Eric Erfanianccca3152017-02-22 16:32:36 -0800784 setState(State.BLOCKED);
785 }
786
787 @Nullable
788 public Uri getHandle() {
linyuh183cb712017-12-27 17:02:37 -0800789 return telecomCall == null ? null : telecomCall.getDetails().getHandle();
Eric Erfanianccca3152017-02-22 16:32:36 -0800790 }
791
792 public boolean isEmergencyCall() {
linyuh183cb712017-12-27 17:02:37 -0800793 return isEmergencyCall;
Eric Erfanianccca3152017-02-22 16:32:36 -0800794 }
795
796 public boolean isPotentialEmergencyCallback() {
797 // The property PROPERTY_EMERGENCY_CALLBACK_MODE is only set for CDMA calls when the system
798 // is actually in emergency callback mode (ie data is disabled).
799 if (hasProperty(Details.PROPERTY_EMERGENCY_CALLBACK_MODE)) {
800 return true;
801 }
802 // We want to treat any incoming call that arrives a short time after an outgoing emergency call
803 // as a potential emergency callback.
804 if (getExtras() != null
805 && getExtras().getLong(TelecomManagerCompat.EXTRA_LAST_EMERGENCY_CALLBACK_TIME_MILLIS, 0)
806 > 0) {
807 long lastEmergencyCallMillis =
808 getExtras().getLong(TelecomManagerCompat.EXTRA_LAST_EMERGENCY_CALLBACK_TIME_MILLIS, 0);
809 if (isInEmergencyCallbackWindow(lastEmergencyCallMillis)) {
810 return true;
811 }
812 }
813 return false;
814 }
815
816 boolean isInEmergencyCallbackWindow(long timestampMillis) {
817 long emergencyCallbackWindowMillis =
linyuh183cb712017-12-27 17:02:37 -0800818 ConfigProviderBindings.get(context)
Eric Erfanianccca3152017-02-22 16:32:36 -0800819 .getLong(CONFIG_EMERGENCY_CALLBACK_WINDOW_MILLIS, TimeUnit.MINUTES.toMillis(5));
820 return System.currentTimeMillis() - timestampMillis < emergencyCallbackWindowMillis;
821 }
822
823 public int getState() {
linyuh183cb712017-12-27 17:02:37 -0800824 if (telecomCall != null && telecomCall.getParent() != null) {
Eric Erfanianccca3152017-02-22 16:32:36 -0800825 return State.CONFERENCED;
826 } else {
linyuh183cb712017-12-27 17:02:37 -0800827 return state;
Eric Erfanianccca3152017-02-22 16:32:36 -0800828 }
829 }
830
yueg265089a2017-10-06 14:35:15 -0700831 public int getNonConferenceState() {
linyuh183cb712017-12-27 17:02:37 -0800832 return state;
yueg265089a2017-10-06 14:35:15 -0700833 }
834
Eric Erfanianccca3152017-02-22 16:32:36 -0800835 public void setState(int state) {
Eric Erfanian2ca43182017-08-31 06:57:16 -0700836 if (state == State.INCOMING) {
linyuh183cb712017-12-27 17:02:37 -0800837 logState.isIncoming = true;
Eric Erfanian2ca43182017-08-31 06:57:16 -0700838 } else if (state == State.DISCONNECTED) {
839 long newDuration =
Eric Erfanianccca3152017-02-22 16:32:36 -0800840 getConnectTimeMillis() == 0 ? 0 : System.currentTimeMillis() - getConnectTimeMillis();
linyuh183cb712017-12-27 17:02:37 -0800841 if (this.state != state) {
842 logState.duration = newDuration;
Eric Erfanian2ca43182017-08-31 06:57:16 -0700843 } else {
844 LogUtil.i(
845 "DialerCall.setState",
846 "ignoring state transition from DISCONNECTED to DISCONNECTED."
847 + " Duration would have changed from %s to %s",
linyuh183cb712017-12-27 17:02:37 -0800848 logState.duration,
Eric Erfanian2ca43182017-08-31 06:57:16 -0700849 newDuration);
850 }
Eric Erfanianccca3152017-02-22 16:32:36 -0800851 }
linyuh183cb712017-12-27 17:02:37 -0800852 this.state = state;
Eric Erfanianccca3152017-02-22 16:32:36 -0800853 }
854
855 public int getNumberPresentation() {
linyuh183cb712017-12-27 17:02:37 -0800856 return telecomCall == null ? -1 : telecomCall.getDetails().getHandlePresentation();
Eric Erfanianccca3152017-02-22 16:32:36 -0800857 }
858
859 public int getCnapNamePresentation() {
linyuh183cb712017-12-27 17:02:37 -0800860 return telecomCall == null ? -1 : telecomCall.getDetails().getCallerDisplayNamePresentation();
Eric Erfanianccca3152017-02-22 16:32:36 -0800861 }
862
863 @Nullable
864 public String getCnapName() {
linyuh183cb712017-12-27 17:02:37 -0800865 return telecomCall == null ? null : getTelecomCall().getDetails().getCallerDisplayName();
Eric Erfanianccca3152017-02-22 16:32:36 -0800866 }
867
868 public Bundle getIntentExtras() {
linyuh183cb712017-12-27 17:02:37 -0800869 return telecomCall.getDetails().getIntentExtras();
Eric Erfanianccca3152017-02-22 16:32:36 -0800870 }
871
872 @Nullable
873 public Bundle getExtras() {
linyuh183cb712017-12-27 17:02:37 -0800874 return telecomCall == null ? null : telecomCall.getDetails().getExtras();
Eric Erfanianccca3152017-02-22 16:32:36 -0800875 }
876
877 /** @return The child number for the call, or {@code null} if none specified. */
878 public String getChildNumber() {
linyuh183cb712017-12-27 17:02:37 -0800879 return childNumber;
Eric Erfanianccca3152017-02-22 16:32:36 -0800880 }
881
882 /** @return The last forwarded number for the call, or {@code null} if none specified. */
883 public String getLastForwardedNumber() {
linyuh183cb712017-12-27 17:02:37 -0800884 return lastForwardedNumber;
Eric Erfanianccca3152017-02-22 16:32:36 -0800885 }
886
wangqif4ba3452018-01-09 11:26:29 -0800887 public boolean isCallForwarded() {
888 return isCallForwarded;
889 }
890
Eric Erfanianccca3152017-02-22 16:32:36 -0800891 /** @return The call subject, or {@code null} if none specified. */
892 public String getCallSubject() {
linyuh183cb712017-12-27 17:02:37 -0800893 return callSubject;
Eric Erfanianccca3152017-02-22 16:32:36 -0800894 }
895
896 /**
897 * @return {@code true} if the call's phone account supports call subjects, {@code false}
898 * otherwise.
899 */
900 public boolean isCallSubjectSupported() {
linyuh183cb712017-12-27 17:02:37 -0800901 return isCallSubjectSupported;
Eric Erfanianccca3152017-02-22 16:32:36 -0800902 }
903
904 /** Returns call disconnect cause, defined by {@link DisconnectCause}. */
905 public DisconnectCause getDisconnectCause() {
linyuh183cb712017-12-27 17:02:37 -0800906 if (state == State.DISCONNECTED || state == State.IDLE) {
907 return disconnectCause;
Eric Erfanianccca3152017-02-22 16:32:36 -0800908 }
909
910 return new DisconnectCause(DisconnectCause.UNKNOWN);
911 }
912
913 public void setDisconnectCause(DisconnectCause disconnectCause) {
linyuh183cb712017-12-27 17:02:37 -0800914 this.disconnectCause = disconnectCause;
915 logState.disconnectCause = this.disconnectCause;
Eric Erfanianccca3152017-02-22 16:32:36 -0800916 }
917
918 /** Returns the possible text message responses. */
919 public List<String> getCannedSmsResponses() {
linyuh183cb712017-12-27 17:02:37 -0800920 return telecomCall.getCannedTextResponses();
Eric Erfanianccca3152017-02-22 16:32:36 -0800921 }
922
923 /** Checks if the call supports the given set of capabilities supplied as a bit mask. */
924 public boolean can(int capabilities) {
linyuh183cb712017-12-27 17:02:37 -0800925 int supportedCapabilities = telecomCall.getDetails().getCallCapabilities();
Eric Erfanianccca3152017-02-22 16:32:36 -0800926
927 if ((capabilities & Call.Details.CAPABILITY_MERGE_CONFERENCE) != 0) {
928 // We allow you to merge if the capabilities allow it or if it is a call with
929 // conferenceable calls.
linyuh183cb712017-12-27 17:02:37 -0800930 if (telecomCall.getConferenceableCalls().isEmpty()
Eric Erfanianccca3152017-02-22 16:32:36 -0800931 && ((Call.Details.CAPABILITY_MERGE_CONFERENCE & supportedCapabilities) == 0)) {
932 // Cannot merge calls if there are no calls to merge with.
933 return false;
934 }
935 capabilities &= ~Call.Details.CAPABILITY_MERGE_CONFERENCE;
936 }
937 return (capabilities == (capabilities & supportedCapabilities));
938 }
939
940 public boolean hasProperty(int property) {
linyuh183cb712017-12-27 17:02:37 -0800941 return telecomCall.getDetails().hasProperty(property);
Eric Erfanianccca3152017-02-22 16:32:36 -0800942 }
943
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700944 @NonNull
Eric Erfanianccca3152017-02-22 16:32:36 -0800945 public String getUniqueCallId() {
946 return uniqueCallId;
947 }
948
949 /** Gets the time when the call first became active. */
950 public long getConnectTimeMillis() {
linyuh183cb712017-12-27 17:02:37 -0800951 return telecomCall.getDetails().getConnectTimeMillis();
Eric Erfanianccca3152017-02-22 16:32:36 -0800952 }
953
954 public boolean isConferenceCall() {
955 return hasProperty(Call.Details.PROPERTY_CONFERENCE);
956 }
957
958 @Nullable
959 public GatewayInfo getGatewayInfo() {
linyuh183cb712017-12-27 17:02:37 -0800960 return telecomCall == null ? null : telecomCall.getDetails().getGatewayInfo();
Eric Erfanianccca3152017-02-22 16:32:36 -0800961 }
962
963 @Nullable
964 public PhoneAccountHandle getAccountHandle() {
linyuh183cb712017-12-27 17:02:37 -0800965 return telecomCall == null ? null : telecomCall.getDetails().getAccountHandle();
Eric Erfanianccca3152017-02-22 16:32:36 -0800966 }
967
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700968 /** @return The {@link VideoCall} instance associated with the {@link Call}. */
Eric Erfanianccca3152017-02-22 16:32:36 -0800969 public VideoCall getVideoCall() {
linyuh183cb712017-12-27 17:02:37 -0800970 return telecomCall == null ? null : telecomCall.getVideoCall();
Eric Erfanianccca3152017-02-22 16:32:36 -0800971 }
972
973 public List<String> getChildCallIds() {
linyuh183cb712017-12-27 17:02:37 -0800974 return childCallIds;
Eric Erfanianccca3152017-02-22 16:32:36 -0800975 }
976
977 public String getParentId() {
linyuh183cb712017-12-27 17:02:37 -0800978 Call parentCall = telecomCall.getParent();
Eric Erfanianccca3152017-02-22 16:32:36 -0800979 if (parentCall != null) {
linyuh183cb712017-12-27 17:02:37 -0800980 return dialerCallDelegate.getDialerCallFromTelecomCall(parentCall).getId();
Eric Erfanianccca3152017-02-22 16:32:36 -0800981 }
982 return null;
983 }
984
985 public int getVideoState() {
linyuh183cb712017-12-27 17:02:37 -0800986 return telecomCall.getDetails().getVideoState();
Eric Erfanianccca3152017-02-22 16:32:36 -0800987 }
988
989 public boolean isVideoCall() {
roldenburg2cec3802017-10-11 16:26:51 -0700990 return getVideoTech().isTransmittingOrReceiving() || VideoProfile.isVideo(getVideoState());
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700991 }
992
wangqi8d407a02018-02-15 15:32:52 -0800993 @TargetApi(28)
wangqif6be6172018-03-30 15:57:56 -0700994 public boolean isActiveRttCall() {
wangqi219b8702018-02-13 09:34:41 -0800995 if (BuildCompat.isAtLeastP()) {
996 return getTelecomCall().isRttActive();
997 } else {
998 return false;
999 }
1000 }
1001
wangqi153af2f2018-02-15 16:21:49 -08001002 @TargetApi(28)
1003 public RttCall getRttCall() {
wangqif6be6172018-03-30 15:57:56 -07001004 if (!isActiveRttCall()) {
wangqi153af2f2018-02-15 16:21:49 -08001005 return null;
1006 }
1007 return getTelecomCall().getRttCall();
1008 }
1009
wangqif6be6172018-03-30 15:57:56 -07001010 @TargetApi(28)
1011 public boolean canUpgradeToRttCall() {
1012 PhoneAccount phoneAccount = getPhoneAccount();
1013 if (phoneAccount == null) {
1014 return false;
1015 }
1016 if (!phoneAccount.hasCapabilities(PhoneAccount.CAPABILITY_RTT)) {
1017 return false;
1018 }
1019 if (isActiveRttCall()) {
1020 return false;
1021 }
1022 if (isVideoCall()) {
1023 return false;
1024 }
1025 if (isConferenceCall()) {
1026 return false;
1027 }
1028 if (CallList.getInstance().hasActiveRttCall()) {
1029 return false;
1030 }
1031 return true;
1032 }
1033
1034 @TargetApi(28)
1035 public void sendRttUpgradeRequest() {
1036 getTelecomCall().sendRttRequest();
1037 }
1038
wangqibc28ea72018-04-02 16:23:00 -07001039 @TargetApi(28)
1040 public void respondToRttRequest(boolean accept, int rttRequestId) {
1041 getTelecomCall().respondToRttRequest(rttRequestId, accept);
1042 }
1043
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001044 public boolean hasReceivedVideoUpgradeRequest() {
1045 return VideoUtils.hasReceivedVideoUpgradeRequest(getVideoTech().getSessionModificationState());
1046 }
1047
1048 public boolean hasSentVideoUpgradeRequest() {
1049 return VideoUtils.hasSentVideoUpgradeRequest(getVideoTech().getSessionModificationState());
Eric Erfanianccca3152017-02-22 16:32:36 -08001050 }
1051
wangqi219b8702018-02-13 09:34:41 -08001052 public boolean hasSentRttUpgradeRequest() {
wangqi219b8702018-02-13 09:34:41 -08001053 return false;
1054 }
1055
Eric Erfanianccca3152017-02-22 16:32:36 -08001056 /**
1057 * Determines if the call handle is an emergency number or not and caches the result to avoid
1058 * repeated calls to isEmergencyNumber.
1059 */
1060 private void updateEmergencyCallState() {
linyuh183cb712017-12-27 17:02:37 -08001061 isEmergencyCall = TelecomCallUtil.isEmergencyCall(telecomCall);
Eric Erfanianccca3152017-02-22 16:32:36 -08001062 }
1063
Eric Erfanianccca3152017-02-22 16:32:36 -08001064 public LogState getLogState() {
linyuh183cb712017-12-27 17:02:37 -08001065 return logState;
Eric Erfanianccca3152017-02-22 16:32:36 -08001066 }
1067
1068 /**
1069 * Determines if the call is an external call.
1070 *
1071 * <p>An external call is one which does not exist locally for the {@link
1072 * android.telecom.ConnectionService} it is associated with.
1073 *
Eric Erfanianccca3152017-02-22 16:32:36 -08001074 * @return {@code true} if the call is an external call, {@code false} otherwise.
1075 */
linyuh437ae952018-03-26 12:46:18 -07001076 boolean isExternalCall() {
1077 return hasProperty(CallCompat.Details.PROPERTY_IS_EXTERNAL_CALL);
Eric Erfanianccca3152017-02-22 16:32:36 -08001078 }
1079
1080 /**
Eric Erfanianccca3152017-02-22 16:32:36 -08001081 * Determines if answering this call will cause an ongoing video call to be dropped.
1082 *
1083 * @return {@code true} if answering this call will drop an ongoing video call, {@code false}
1084 * otherwise.
1085 */
1086 public boolean answeringDisconnectsForegroundVideoCall() {
1087 Bundle extras = getExtras();
1088 if (extras == null
1089 || !extras.containsKey(CallCompat.Details.EXTRA_ANSWERING_DROPS_FOREGROUND_CALL)) {
1090 return false;
1091 }
1092 return extras.getBoolean(CallCompat.Details.EXTRA_ANSWERING_DROPS_FOREGROUND_CALL);
1093 }
1094
1095 private void parseCallSpecificAppData() {
1096 if (isExternalCall()) {
1097 return;
1098 }
1099
linyuh183cb712017-12-27 17:02:37 -08001100 logState.callSpecificAppData = CallIntentParser.getCallSpecificAppData(getIntentExtras());
1101 if (logState.callSpecificAppData == null) {
Eric Erfanian8369df02017-05-03 10:27:13 -07001102
linyuh183cb712017-12-27 17:02:37 -08001103 logState.callSpecificAppData =
Eric Erfanian8369df02017-05-03 10:27:13 -07001104 CallSpecificAppData.newBuilder()
1105 .setCallInitiationType(CallInitiationType.Type.EXTERNAL_INITIATION)
1106 .build();
Eric Erfanianccca3152017-02-22 16:32:36 -08001107 }
1108 if (getState() == State.INCOMING) {
linyuh183cb712017-12-27 17:02:37 -08001109 logState.callSpecificAppData =
1110 logState
Eric Erfanian8369df02017-05-03 10:27:13 -07001111 .callSpecificAppData
1112 .toBuilder()
1113 .setCallInitiationType(CallInitiationType.Type.INCOMING_INITIATION)
1114 .build();
Eric Erfanianccca3152017-02-22 16:32:36 -08001115 }
1116 }
1117
1118 @Override
1119 public String toString() {
linyuh183cb712017-12-27 17:02:37 -08001120 if (telecomCall == null) {
Eric Erfanianccca3152017-02-22 16:32:36 -08001121 // This should happen only in testing since otherwise we would never have a null
1122 // Telecom call.
linyuh183cb712017-12-27 17:02:37 -08001123 return String.valueOf(id);
Eric Erfanianccca3152017-02-22 16:32:36 -08001124 }
1125
1126 return String.format(
1127 Locale.US,
1128 "[%s, %s, %s, %s, children:%s, parent:%s, "
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001129 + "conferenceable:%s, videoState:%s, mSessionModificationState:%d, CameraDir:%s]",
linyuh183cb712017-12-27 17:02:37 -08001130 id,
Eric Erfanianccca3152017-02-22 16:32:36 -08001131 State.toString(getState()),
linyuh183cb712017-12-27 17:02:37 -08001132 Details.capabilitiesToString(telecomCall.getDetails().getCallCapabilities()),
1133 Details.propertiesToString(telecomCall.getDetails().getCallProperties()),
1134 childCallIds,
Eric Erfanianccca3152017-02-22 16:32:36 -08001135 getParentId(),
linyuh183cb712017-12-27 17:02:37 -08001136 this.telecomCall.getConferenceableCalls(),
1137 VideoProfile.videoStateToString(telecomCall.getDetails().getVideoState()),
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001138 getVideoTech().getSessionModificationState(),
1139 getCameraDir());
Eric Erfanianccca3152017-02-22 16:32:36 -08001140 }
1141
1142 public String toSimpleString() {
1143 return super.toString();
1144 }
1145
1146 @CallHistoryStatus
1147 public int getCallHistoryStatus() {
linyuh183cb712017-12-27 17:02:37 -08001148 return callHistoryStatus;
Eric Erfanianccca3152017-02-22 16:32:36 -08001149 }
1150
1151 public void setCallHistoryStatus(@CallHistoryStatus int callHistoryStatus) {
linyuh183cb712017-12-27 17:02:37 -08001152 this.callHistoryStatus = callHistoryStatus;
Eric Erfanianccca3152017-02-22 16:32:36 -08001153 }
1154
1155 public boolean didShowCameraPermission() {
1156 return didShowCameraPermission;
1157 }
1158
1159 public void setDidShowCameraPermission(boolean didShow) {
1160 didShowCameraPermission = didShow;
1161 }
1162
wangqida410d32018-03-06 16:51:38 -08001163 public boolean didDismissVideoChargesAlertDialog() {
1164 return didDismissVideoChargesAlertDialog;
1165 }
1166
1167 public void setDidDismissVideoChargesAlertDialog(boolean didDismiss) {
1168 didDismissVideoChargesAlertDialog = didDismiss;
1169 }
1170
Eric Erfanian938468d2017-10-24 14:05:52 -07001171 @Nullable
1172 public Boolean isInGlobalSpamList() {
Eric Erfanianccca3152017-02-22 16:32:36 -08001173 return isInGlobalSpamList;
1174 }
1175
1176 public void setIsInGlobalSpamList(boolean inSpamList) {
1177 isInGlobalSpamList = inSpamList;
1178 }
1179
Eric Erfanian938468d2017-10-24 14:05:52 -07001180 @Nullable
1181 public Boolean isInUserSpamList() {
Eric Erfanianccca3152017-02-22 16:32:36 -08001182 return isInUserSpamList;
1183 }
1184
1185 public void setIsInUserSpamList(boolean inSpamList) {
1186 isInUserSpamList = inSpamList;
1187 }
1188
Eric Erfanian938468d2017-10-24 14:05:52 -07001189 @Nullable
1190 public Boolean isInUserWhiteList() {
Eric Erfanianccca3152017-02-22 16:32:36 -08001191 return isInUserWhiteList;
1192 }
1193
1194 public void setIsInUserWhiteList(boolean inWhiteList) {
1195 isInUserWhiteList = inWhiteList;
1196 }
1197
1198 public boolean isSpam() {
linyuh183cb712017-12-27 17:02:37 -08001199 return isSpam;
Eric Erfanianccca3152017-02-22 16:32:36 -08001200 }
1201
1202 public void setSpam(boolean isSpam) {
linyuh183cb712017-12-27 17:02:37 -08001203 this.isSpam = isSpam;
Eric Erfanianccca3152017-02-22 16:32:36 -08001204 }
1205
1206 public boolean isBlocked() {
linyuh183cb712017-12-27 17:02:37 -08001207 return isBlocked;
Eric Erfanianccca3152017-02-22 16:32:36 -08001208 }
1209
1210 public void setBlockedStatus(boolean isBlocked) {
linyuh183cb712017-12-27 17:02:37 -08001211 this.isBlocked = isBlocked;
Eric Erfanianccca3152017-02-22 16:32:36 -08001212 }
1213
1214 public boolean isRemotelyHeld() {
1215 return isRemotelyHeld;
1216 }
1217
Eric Erfanian2ca43182017-08-31 06:57:16 -07001218 public boolean isMergeInProcess() {
1219 return isMergeInProcess;
1220 }
1221
Eric Erfanianccca3152017-02-22 16:32:36 -08001222 public boolean isIncoming() {
linyuh183cb712017-12-27 17:02:37 -08001223 return logState.isIncoming;
Eric Erfanianccca3152017-02-22 16:32:36 -08001224 }
1225
erfanian2cf2c342017-12-21 12:01:33 -08001226 /**
1227 * Try and determine if the call used assisted dialing.
1228 *
1229 * <p>We will not be able to verify a call underwent assisted dialing until the Platform
1230 * implmentation is complete in P+.
1231 *
1232 * @return a boolean indicating assisted dialing may have been performed
1233 */
Eric Erfanian2ca43182017-08-31 06:57:16 -07001234 public boolean isAssistedDialed() {
1235 if (getIntentExtras() != null) {
erfaniand2e5d0b2018-03-02 14:54:35 -08001236 // P and below uses the existence of USE_ASSISTED_DIALING to indicate assisted dialing
erfanian2cf2c342017-12-21 12:01:33 -08001237 // was used. The Dialer client is responsible for performing assisted dialing before
1238 // placing the outgoing call.
1239 //
1240 // The existence of the assisted dialing extras indicates that assisted dialing took place.
1241 if (getIntentExtras().getBoolean(TelephonyManagerCompat.USE_ASSISTED_DIALING, false)
1242 && getAssistedDialingExtras() != null
1243 && Build.VERSION.SDK_INT <= ConcreteCreator.BUILD_CODE_CEILING) {
1244 return true;
1245 }
1246 }
1247
Eric Erfanian2ca43182017-08-31 06:57:16 -07001248 return false;
1249 }
1250
erfanian2cf2c342017-12-21 12:01:33 -08001251 @Nullable
erfaniand0f207f2017-10-11 12:23:29 -07001252 public TransformationInfo getAssistedDialingExtras() {
erfanian2cf2c342017-12-21 12:01:33 -08001253 if (getIntentExtras() == null) {
1254 return null;
erfaniand0f207f2017-10-11 12:23:29 -07001255 }
erfanian2cf2c342017-12-21 12:01:33 -08001256
1257 if (getIntentExtras().getBundle(TelephonyManagerCompat.ASSISTED_DIALING_EXTRAS) == null) {
1258 return null;
1259 }
1260
erfanianf2556612018-01-23 09:55:59 -08001261 // Used in N-OMR1
erfanian2cf2c342017-12-21 12:01:33 -08001262 return TransformationInfo.newInstanceFromBundle(
1263 getIntentExtras().getBundle(TelephonyManagerCompat.ASSISTED_DIALING_EXTRAS));
erfaniand0f207f2017-10-11 12:23:29 -07001264 }
1265
Eric Erfanianccca3152017-02-22 16:32:36 -08001266 public LatencyReport getLatencyReport() {
linyuh183cb712017-12-27 17:02:37 -08001267 return latencyReport;
Eric Erfanianccca3152017-02-22 16:32:36 -08001268 }
1269
Eric Erfanian2ca43182017-08-31 06:57:16 -07001270 public int getAnswerAndReleaseButtonDisplayedTimes() {
1271 return answerAndReleaseButtonDisplayedTimes;
1272 }
1273
1274 public void increaseAnswerAndReleaseButtonDisplayedTimes() {
1275 answerAndReleaseButtonDisplayedTimes++;
1276 }
1277
1278 public boolean getReleasedByAnsweringSecondCall() {
1279 return releasedByAnsweringSecondCall;
1280 }
1281
1282 public void setReleasedByAnsweringSecondCall(boolean releasedByAnsweringSecondCall) {
1283 this.releasedByAnsweringSecondCall = releasedByAnsweringSecondCall;
1284 }
1285
1286 public int getSecondCallWithoutAnswerAndReleasedButtonTimes() {
1287 return secondCallWithoutAnswerAndReleasedButtonTimes;
1288 }
1289
1290 public void increaseSecondCallWithoutAnswerAndReleasedButtonTimes() {
1291 secondCallWithoutAnswerAndReleasedButtonTimes++;
1292 }
1293
Eric Erfanian8369df02017-05-03 10:27:13 -07001294 @Nullable
1295 public EnrichedCallCapabilities getEnrichedCallCapabilities() {
linyuh183cb712017-12-27 17:02:37 -08001296 return enrichedCallCapabilities;
Eric Erfanian8369df02017-05-03 10:27:13 -07001297 }
1298
1299 public void setEnrichedCallCapabilities(
1300 @Nullable EnrichedCallCapabilities mEnrichedCallCapabilities) {
linyuh183cb712017-12-27 17:02:37 -08001301 this.enrichedCallCapabilities = mEnrichedCallCapabilities;
Eric Erfanian8369df02017-05-03 10:27:13 -07001302 }
1303
1304 @Nullable
1305 public Session getEnrichedCallSession() {
linyuh183cb712017-12-27 17:02:37 -08001306 return enrichedCallSession;
Eric Erfanian8369df02017-05-03 10:27:13 -07001307 }
1308
1309 public void setEnrichedCallSession(@Nullable Session mEnrichedCallSession) {
linyuh183cb712017-12-27 17:02:37 -08001310 this.enrichedCallSession = mEnrichedCallSession;
Eric Erfanian8369df02017-05-03 10:27:13 -07001311 }
1312
Eric Erfanianccca3152017-02-22 16:32:36 -08001313 public void unregisterCallback() {
linyuh183cb712017-12-27 17:02:37 -08001314 telecomCall.unregisterCallback(telecomCallCallback);
Eric Erfanianccca3152017-02-22 16:32:36 -08001315 }
1316
Eric Erfanianccca3152017-02-22 16:32:36 -08001317 public void phoneAccountSelected(PhoneAccountHandle accountHandle, boolean setDefault) {
1318 LogUtil.i(
1319 "DialerCall.phoneAccountSelected",
1320 "accountHandle: %s, setDefault: %b",
1321 accountHandle,
1322 setDefault);
linyuh183cb712017-12-27 17:02:37 -08001323 telecomCall.phoneAccountSelected(accountHandle, setDefault);
Eric Erfanianccca3152017-02-22 16:32:36 -08001324 }
1325
1326 public void disconnect() {
1327 LogUtil.i("DialerCall.disconnect", "");
1328 setState(DialerCall.State.DISCONNECTING);
linyuh183cb712017-12-27 17:02:37 -08001329 for (DialerCallListener listener : listeners) {
Eric Erfanianccca3152017-02-22 16:32:36 -08001330 listener.onDialerCallUpdate();
1331 }
linyuh183cb712017-12-27 17:02:37 -08001332 telecomCall.disconnect();
Eric Erfanianccca3152017-02-22 16:32:36 -08001333 }
1334
1335 public void hold() {
1336 LogUtil.i("DialerCall.hold", "");
linyuh183cb712017-12-27 17:02:37 -08001337 telecomCall.hold();
Eric Erfanianccca3152017-02-22 16:32:36 -08001338 }
1339
1340 public void unhold() {
1341 LogUtil.i("DialerCall.unhold", "");
linyuh183cb712017-12-27 17:02:37 -08001342 telecomCall.unhold();
Eric Erfanianccca3152017-02-22 16:32:36 -08001343 }
1344
1345 public void splitFromConference() {
1346 LogUtil.i("DialerCall.splitFromConference", "");
linyuh183cb712017-12-27 17:02:37 -08001347 telecomCall.splitFromConference();
Eric Erfanianccca3152017-02-22 16:32:36 -08001348 }
1349
1350 public void answer(int videoState) {
1351 LogUtil.i("DialerCall.answer", "videoState: " + videoState);
linyuh183cb712017-12-27 17:02:37 -08001352 telecomCall.answer(videoState);
Eric Erfanianccca3152017-02-22 16:32:36 -08001353 }
1354
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001355 public void answer() {
linyuh183cb712017-12-27 17:02:37 -08001356 answer(telecomCall.getDetails().getVideoState());
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001357 }
1358
Eric Erfanianccca3152017-02-22 16:32:36 -08001359 public void reject(boolean rejectWithMessage, String message) {
1360 LogUtil.i("DialerCall.reject", "");
linyuh183cb712017-12-27 17:02:37 -08001361 telecomCall.reject(rejectWithMessage, message);
Eric Erfanianccca3152017-02-22 16:32:36 -08001362 }
1363
1364 /** Return the string label to represent the call provider */
1365 public String getCallProviderLabel() {
1366 if (callProviderLabel == null) {
1367 PhoneAccount account = getPhoneAccount();
1368 if (account != null && !TextUtils.isEmpty(account.getLabel())) {
wangqi9982f0d2017-10-11 17:46:07 -07001369 if (callCapableAccounts != null && callCapableAccounts.size() > 1) {
Eric Erfanianccca3152017-02-22 16:32:36 -08001370 callProviderLabel = account.getLabel().toString();
1371 }
1372 }
1373 if (callProviderLabel == null) {
1374 callProviderLabel = "";
1375 }
1376 }
1377 return callProviderLabel;
1378 }
1379
1380 private PhoneAccount getPhoneAccount() {
1381 PhoneAccountHandle accountHandle = getAccountHandle();
1382 if (accountHandle == null) {
1383 return null;
1384 }
linyuh183cb712017-12-27 17:02:37 -08001385 return context.getSystemService(TelecomManager.class).getPhoneAccount(accountHandle);
Eric Erfanianccca3152017-02-22 16:32:36 -08001386 }
1387
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001388 public VideoTech getVideoTech() {
roldenburg7bb96232017-10-09 10:32:05 -07001389 if (videoTech == null) {
roldenburg6bd612f2018-01-18 12:57:19 -08001390 videoTech = videoTechManager.getVideoTech(getAccountHandle());
roldenburg7bb96232017-10-09 10:32:05 -07001391
1392 // Only store the first video tech type found to be available during the life of the call.
1393 if (selectedAvailableVideoTechType == com.android.dialer.logging.VideoTech.Type.NONE) {
1394 // Update the video tech.
1395 selectedAvailableVideoTechType = videoTech.getVideoTechType();
1396 }
1397 }
Eric Erfanian2ca43182017-08-31 06:57:16 -07001398 return videoTech;
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001399 }
1400
Eric Erfanianccca3152017-02-22 16:32:36 -08001401 public String getCallbackNumber() {
1402 if (callbackNumber == null) {
1403 // Show the emergency callback number if either:
1404 // 1. This is an emergency call.
1405 // 2. The phone is in Emergency Callback Mode, which means we should show the callback
1406 // number.
1407 boolean showCallbackNumber = hasProperty(Details.PROPERTY_EMERGENCY_CALLBACK_MODE);
1408
1409 if (isEmergencyCall() || showCallbackNumber) {
wangqi339b4f32017-09-18 14:32:09 -07001410 callbackNumber =
linyuh183cb712017-12-27 17:02:37 -08001411 context.getSystemService(TelecomManager.class).getLine1Number(getAccountHandle());
Eric Erfanianccca3152017-02-22 16:32:36 -08001412 }
1413
Eric Erfanianccca3152017-02-22 16:32:36 -08001414 if (callbackNumber == null) {
1415 callbackNumber = "";
1416 }
1417 }
1418 return callbackNumber;
1419 }
1420
wangqi97539352017-09-25 11:15:16 -07001421 public String getSimCountryIso() {
1422 String simCountryIso =
linyuh183cb712017-12-27 17:02:37 -08001423 TelephonyManagerCompat.getTelephonyManagerForPhoneAccountHandle(context, getAccountHandle())
wangqi97539352017-09-25 11:15:16 -07001424 .getSimCountryIso();
1425 if (!TextUtils.isEmpty(simCountryIso)) {
1426 simCountryIso = simCountryIso.toUpperCase(Locale.US);
1427 }
1428 return simCountryIso;
1429 }
1430
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001431 @Override
1432 public void onVideoTechStateChanged() {
1433 update();
1434 }
1435
1436 @Override
1437 public void onSessionModificationStateChanged() {
wangqi9982f0d2017-10-11 17:46:07 -07001438 Trace.beginSection("DialerCall.onSessionModificationStateChanged");
linyuh183cb712017-12-27 17:02:37 -08001439 for (DialerCallListener listener : listeners) {
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001440 listener.onDialerCallSessionModificationStateChange();
1441 }
wangqi9982f0d2017-10-11 17:46:07 -07001442 Trace.endSection();
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001443 }
1444
1445 @Override
1446 public void onCameraDimensionsChanged(int width, int height) {
1447 InCallVideoCallCallbackNotifier.getInstance().cameraDimensionsChanged(this, width, height);
1448 }
1449
1450 @Override
1451 public void onPeerDimensionsChanged(int width, int height) {
1452 InCallVideoCallCallbackNotifier.getInstance().peerDimensionsChanged(this, width, height);
1453 }
1454
1455 @Override
1456 public void onVideoUpgradeRequestReceived() {
1457 LogUtil.enterBlock("DialerCall.onVideoUpgradeRequestReceived");
1458
linyuh183cb712017-12-27 17:02:37 -08001459 for (DialerCallListener listener : listeners) {
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001460 listener.onDialerCallUpgradeToVideo();
1461 }
1462
1463 update();
Eric Erfanian8369df02017-05-03 10:27:13 -07001464
linyuh183cb712017-12-27 17:02:37 -08001465 Logger.get(context)
Eric Erfanian8369df02017-05-03 10:27:13 -07001466 .logCallImpression(
1467 DialerImpression.Type.VIDEO_CALL_REQUEST_RECEIVED, getUniqueCallId(), getTimeAddedMs());
1468 }
1469
1470 @Override
1471 public void onUpgradedToVideo(boolean switchToSpeaker) {
1472 LogUtil.enterBlock("DialerCall.onUpgradedToVideo");
1473
1474 if (!switchToSpeaker) {
1475 return;
1476 }
1477
1478 CallAudioState audioState = AudioModeProvider.getInstance().getAudioState();
1479
1480 if (0 != (CallAudioState.ROUTE_BLUETOOTH & audioState.getSupportedRouteMask())) {
1481 LogUtil.e(
1482 "DialerCall.onUpgradedToVideo",
1483 "toggling speakerphone not allowed when bluetooth supported.");
1484 return;
1485 }
1486
1487 if (audioState.getRoute() == CallAudioState.ROUTE_SPEAKER) {
1488 return;
1489 }
1490
1491 TelecomAdapter.getInstance().setAudioRoute(CallAudioState.ROUTE_SPEAKER);
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001492 }
1493
Eric Erfanian2ca43182017-08-31 06:57:16 -07001494 @Override
1495 public void onCapabilitiesUpdated() {
1496 if (getNumber() == null) {
1497 return;
1498 }
1499 EnrichedCallCapabilities capabilities =
linyuh183cb712017-12-27 17:02:37 -08001500 EnrichedCallComponent.get(context).getEnrichedCallManager().getCapabilities(getNumber());
Eric Erfanian2ca43182017-08-31 06:57:16 -07001501 if (capabilities != null) {
1502 setEnrichedCallCapabilities(capabilities);
1503 update();
1504 }
1505 }
1506
1507 @Override
1508 public void onEnrichedCallStateChanged() {
1509 updateEnrichedCallSession();
1510 }
1511
1512 @Override
1513 public void onImpressionLoggingNeeded(DialerImpression.Type impressionType) {
linyuh183cb712017-12-27 17:02:37 -08001514 Logger.get(context).logCallImpression(impressionType, getUniqueCallId(), getTimeAddedMs());
twyendde01c52017-09-22 10:07:31 -07001515 if (impressionType == DialerImpression.Type.LIGHTBRINGER_UPGRADE_REQUESTED) {
1516 if (getLogState().contactLookupResult == Type.NOT_FOUND) {
linyuh183cb712017-12-27 17:02:37 -08001517 Logger.get(context)
twyendde01c52017-09-22 10:07:31 -07001518 .logCallImpression(
1519 DialerImpression.Type.LIGHTBRINGER_NON_CONTACT_UPGRADE_REQUESTED,
1520 getUniqueCallId(),
1521 getTimeAddedMs());
1522 }
1523 }
Eric Erfanian2ca43182017-08-31 06:57:16 -07001524 }
1525
1526 private void updateEnrichedCallSession() {
1527 if (getNumber() == null) {
1528 return;
1529 }
1530 if (getEnrichedCallSession() != null) {
1531 // State changes to existing sessions are currently handled by the UI components (which have
1532 // their own listeners). Someday instead we could remove those and just call update() here and
1533 // have the usual onDialerCallUpdate update the UI.
1534 dispatchOnEnrichedCallSessionUpdate();
1535 return;
1536 }
1537
linyuh183cb712017-12-27 17:02:37 -08001538 EnrichedCallManager manager = EnrichedCallComponent.get(context).getEnrichedCallManager();
Eric Erfanian2ca43182017-08-31 06:57:16 -07001539
1540 Filter filter =
1541 isIncoming()
1542 ? manager.createIncomingCallComposerFilter()
1543 : manager.createOutgoingCallComposerFilter();
1544
1545 Session session = manager.getSession(getUniqueCallId(), getNumber(), filter);
1546 if (session == null) {
1547 return;
1548 }
1549
1550 session.setUniqueDialerCallId(getUniqueCallId());
1551 setEnrichedCallSession(session);
1552
1553 LogUtil.i(
1554 "DialerCall.updateEnrichedCallSession",
1555 "setting session %d's dialer id to %s",
1556 session.getSessionId(),
1557 getUniqueCallId());
1558
1559 dispatchOnEnrichedCallSessionUpdate();
1560 }
1561
1562 private void dispatchOnEnrichedCallSessionUpdate() {
linyuh183cb712017-12-27 17:02:37 -08001563 for (DialerCallListener listener : listeners) {
Eric Erfanian2ca43182017-08-31 06:57:16 -07001564 listener.onEnrichedCallSessionUpdate();
1565 }
1566 }
1567
1568 void onRemovedFromCallList() {
1569 // Ensure we clean up when this call is removed.
linyuh183cb712017-12-27 17:02:37 -08001570 videoTechManager.dispatchRemovedFromCallList();
Eric Erfanian2ca43182017-08-31 06:57:16 -07001571 }
1572
wangqi4d705e52017-09-28 12:23:35 -07001573 public com.android.dialer.logging.VideoTech.Type getSelectedAvailableVideoTechType() {
1574 return selectedAvailableVideoTechType;
yueg457b3972017-09-18 15:11:47 -07001575 }
1576
Android Dialer974fc292018-02-01 16:12:25 -08001577 public void markFeedbackRequested() {
1578 feedbackRequested = true;
1579 }
1580
1581 public boolean isFeedbackRequested() {
1582 return feedbackRequested;
1583 }
1584
Eric Erfanianccca3152017-02-22 16:32:36 -08001585 /**
twyen73a74c32018-03-07 12:12:24 -08001586 * If the in call UI has shown the phone account selection dialog for the call, the {@link
1587 * PreferredAccountRecorder} to record the result from the dialog.
1588 */
1589 @Nullable
1590 public PreferredAccountRecorder getPreferredAccountRecorder() {
1591 return preferredAccountRecorder;
1592 }
1593
1594 public void setPreferredAccountRecorder(PreferredAccountRecorder preferredAccountRecorder) {
1595 this.preferredAccountRecorder = preferredAccountRecorder;
1596 }
1597
erfaniand05d8992018-03-20 19:42:26 -07001598 /** Indicates the call is eligible for SpeakEasy */
1599 public boolean isSpeakEasyEligible() {
1600 // TODO(erfanian): refactor key location
1601 return ConfigProviderBindings.get(context).getBoolean("speak_easy_enabled", false);
1602 }
1603
1604 /** Indicates the user has selected SpeakEasy */
1605 public boolean isSpeakEasyCall() {
1606 if (!isSpeakEasyEligible()) {
1607 return false;
1608 }
1609 return isSpeakEasyCall;
1610 }
1611
1612 /** Sets the user preference for SpeakEasy */
1613 public void setIsSpeakEasyCall(boolean isSpeakEasyCall) {
1614 this.isSpeakEasyCall = isSpeakEasyCall;
1615 }
1616
twyen73a74c32018-03-07 12:12:24 -08001617 /**
Eric Erfanianccca3152017-02-22 16:32:36 -08001618 * Specifies whether a number is in the call history or not. {@link #CALL_HISTORY_STATUS_UNKNOWN}
1619 * means there is no result.
1620 */
1621 @IntDef({
1622 CALL_HISTORY_STATUS_UNKNOWN,
1623 CALL_HISTORY_STATUS_PRESENT,
1624 CALL_HISTORY_STATUS_NOT_PRESENT
1625 })
1626 @Retention(RetentionPolicy.SOURCE)
1627 public @interface CallHistoryStatus {}
1628
1629 /* Defines different states of this call */
1630 public static class State {
1631
1632 public static final int INVALID = 0;
1633 public static final int NEW = 1; /* The call is new. */
1634 public static final int IDLE = 2; /* The call is idle. Nothing active */
1635 public static final int ACTIVE = 3; /* There is an active call */
1636 public static final int INCOMING = 4; /* A normal incoming phone call */
1637 public static final int CALL_WAITING = 5; /* Incoming call while another is active */
1638 public static final int DIALING = 6; /* An outgoing call during dial phase */
1639 public static final int REDIALING = 7; /* Subsequent dialing attempt after a failure */
1640 public static final int ONHOLD = 8; /* An active phone call placed on hold */
1641 public static final int DISCONNECTING = 9; /* A call is being ended. */
1642 public static final int DISCONNECTED = 10; /* State after a call disconnects */
1643 public static final int CONFERENCED = 11; /* DialerCall part of a conference call */
1644 public static final int SELECT_PHONE_ACCOUNT = 12; /* Waiting for account selection */
1645 public static final int CONNECTING = 13; /* Waiting for Telecom broadcast to finish */
1646 public static final int BLOCKED = 14; /* The number was found on the block list */
1647 public static final int PULLING = 15; /* An external call being pulled to the device */
Eric Erfanian2ca43182017-08-31 06:57:16 -07001648 public static final int CALL_PENDING = 16; /* A call is pending on a long process to finish */
Eric Erfanianccca3152017-02-22 16:32:36 -08001649
1650 public static boolean isConnectingOrConnected(int state) {
1651 switch (state) {
1652 case ACTIVE:
1653 case INCOMING:
1654 case CALL_WAITING:
1655 case CONNECTING:
1656 case DIALING:
1657 case PULLING:
1658 case REDIALING:
1659 case ONHOLD:
1660 case CONFERENCED:
1661 return true;
1662 default:
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001663 return false;
Eric Erfanianccca3152017-02-22 16:32:36 -08001664 }
Eric Erfanianccca3152017-02-22 16:32:36 -08001665 }
1666
1667 public static boolean isDialing(int state) {
1668 return state == DIALING || state == PULLING || state == REDIALING;
1669 }
1670
1671 public static String toString(int state) {
1672 switch (state) {
1673 case INVALID:
1674 return "INVALID";
1675 case NEW:
1676 return "NEW";
1677 case IDLE:
1678 return "IDLE";
1679 case ACTIVE:
1680 return "ACTIVE";
1681 case INCOMING:
1682 return "INCOMING";
1683 case CALL_WAITING:
1684 return "CALL_WAITING";
1685 case DIALING:
1686 return "DIALING";
1687 case PULLING:
1688 return "PULLING";
1689 case REDIALING:
1690 return "REDIALING";
1691 case ONHOLD:
1692 return "ONHOLD";
1693 case DISCONNECTING:
1694 return "DISCONNECTING";
1695 case DISCONNECTED:
1696 return "DISCONNECTED";
1697 case CONFERENCED:
1698 return "CONFERENCED";
1699 case SELECT_PHONE_ACCOUNT:
1700 return "SELECT_PHONE_ACCOUNT";
1701 case CONNECTING:
1702 return "CONNECTING";
1703 case BLOCKED:
1704 return "BLOCKED";
1705 default:
1706 return "UNKNOWN";
1707 }
1708 }
1709 }
1710
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001711 /** Camera direction constants */
1712 public static class CameraDirection {
Eric Erfanianccca3152017-02-22 16:32:36 -08001713 public static final int CAMERA_DIRECTION_UNKNOWN = -1;
1714 public static final int CAMERA_DIRECTION_FRONT_FACING = CameraCharacteristics.LENS_FACING_FRONT;
1715 public static final int CAMERA_DIRECTION_BACK_FACING = CameraCharacteristics.LENS_FACING_BACK;
Eric Erfanianccca3152017-02-22 16:32:36 -08001716 }
1717
1718 /**
1719 * Tracks any state variables that is useful for logging. There is some amount of overlap with
1720 * existing call member variables, but this duplication helps to ensure that none of these logging
1721 * variables will interface with/and affect call logic.
1722 */
1723 public static class LogState {
1724
1725 public DisconnectCause disconnectCause;
1726 public boolean isIncoming = false;
Eric Erfanian8369df02017-05-03 10:27:13 -07001727 public ContactLookupResult.Type contactLookupResult =
1728 ContactLookupResult.Type.UNKNOWN_LOOKUP_RESULT_TYPE;
Eric Erfanianccca3152017-02-22 16:32:36 -08001729 public CallSpecificAppData callSpecificAppData;
1730 // If this was a conference call, the total number of calls involved in the conference.
1731 public int conferencedCalls = 0;
1732 public long duration = 0;
1733 public boolean isLogged = false;
1734
Eric Erfanian8369df02017-05-03 10:27:13 -07001735 private static String lookupToString(ContactLookupResult.Type lookupType) {
Eric Erfanianccca3152017-02-22 16:32:36 -08001736 switch (lookupType) {
Eric Erfanian8369df02017-05-03 10:27:13 -07001737 case LOCAL_CONTACT:
Eric Erfanianccca3152017-02-22 16:32:36 -08001738 return "Local";
Eric Erfanian8369df02017-05-03 10:27:13 -07001739 case LOCAL_CACHE:
Eric Erfanianccca3152017-02-22 16:32:36 -08001740 return "Cache";
Eric Erfanian8369df02017-05-03 10:27:13 -07001741 case REMOTE:
Eric Erfanianccca3152017-02-22 16:32:36 -08001742 return "Remote";
Eric Erfanian8369df02017-05-03 10:27:13 -07001743 case EMERGENCY:
Eric Erfanianccca3152017-02-22 16:32:36 -08001744 return "Emergency";
Eric Erfanian8369df02017-05-03 10:27:13 -07001745 case VOICEMAIL:
Eric Erfanianccca3152017-02-22 16:32:36 -08001746 return "Voicemail";
1747 default:
1748 return "Not found";
1749 }
1750 }
1751
1752 private static String initiationToString(CallSpecificAppData callSpecificAppData) {
1753 if (callSpecificAppData == null) {
1754 return "null";
1755 }
Eric Erfanian8369df02017-05-03 10:27:13 -07001756 switch (callSpecificAppData.getCallInitiationType()) {
1757 case INCOMING_INITIATION:
Eric Erfanianccca3152017-02-22 16:32:36 -08001758 return "Incoming";
Eric Erfanian8369df02017-05-03 10:27:13 -07001759 case DIALPAD:
Eric Erfanianccca3152017-02-22 16:32:36 -08001760 return "Dialpad";
Eric Erfanian8369df02017-05-03 10:27:13 -07001761 case SPEED_DIAL:
Eric Erfanianccca3152017-02-22 16:32:36 -08001762 return "Speed Dial";
Eric Erfanian8369df02017-05-03 10:27:13 -07001763 case REMOTE_DIRECTORY:
Eric Erfanianccca3152017-02-22 16:32:36 -08001764 return "Remote Directory";
Eric Erfanian8369df02017-05-03 10:27:13 -07001765 case SMART_DIAL:
Eric Erfanianccca3152017-02-22 16:32:36 -08001766 return "Smart Dial";
Eric Erfanian8369df02017-05-03 10:27:13 -07001767 case REGULAR_SEARCH:
Eric Erfanianccca3152017-02-22 16:32:36 -08001768 return "Regular Search";
Eric Erfanian8369df02017-05-03 10:27:13 -07001769 case CALL_LOG:
Eric Erfanianccca3152017-02-22 16:32:36 -08001770 return "DialerCall Log";
Eric Erfanian8369df02017-05-03 10:27:13 -07001771 case CALL_LOG_FILTER:
Eric Erfanianccca3152017-02-22 16:32:36 -08001772 return "DialerCall Log Filter";
Eric Erfanian8369df02017-05-03 10:27:13 -07001773 case VOICEMAIL_LOG:
Eric Erfanianccca3152017-02-22 16:32:36 -08001774 return "Voicemail Log";
Eric Erfanian8369df02017-05-03 10:27:13 -07001775 case CALL_DETAILS:
Eric Erfanianccca3152017-02-22 16:32:36 -08001776 return "DialerCall Details";
Eric Erfanian8369df02017-05-03 10:27:13 -07001777 case QUICK_CONTACTS:
Eric Erfanianccca3152017-02-22 16:32:36 -08001778 return "Quick Contacts";
Eric Erfanian8369df02017-05-03 10:27:13 -07001779 case EXTERNAL_INITIATION:
Eric Erfanianccca3152017-02-22 16:32:36 -08001780 return "External";
Eric Erfanian8369df02017-05-03 10:27:13 -07001781 case LAUNCHER_SHORTCUT:
Eric Erfanianccca3152017-02-22 16:32:36 -08001782 return "Launcher Shortcut";
1783 default:
Eric Erfanian8369df02017-05-03 10:27:13 -07001784 return "Unknown: " + callSpecificAppData.getCallInitiationType();
Eric Erfanianccca3152017-02-22 16:32:36 -08001785 }
1786 }
1787
1788 @Override
1789 public String toString() {
1790 return String.format(
1791 Locale.US,
1792 "["
1793 + "%s, " // DisconnectCause toString already describes the object type
1794 + "isIncoming: %s, "
1795 + "contactLookup: %s, "
1796 + "callInitiation: %s, "
1797 + "duration: %s"
1798 + "]",
1799 disconnectCause,
1800 isIncoming,
1801 lookupToString(contactLookupResult),
1802 initiationToString(callSpecificAppData),
1803 duration);
1804 }
1805 }
1806
roldenburgd7490db2018-01-09 13:51:29 -08001807 /** Coordinates the available VideoTech implementations for a call. */
1808 @VisibleForTesting
1809 public static class VideoTechManager {
Eric Erfaniand8046e52017-04-06 09:41:50 -07001810 private final Context context;
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001811 private final EmptyVideoTech emptyVideoTech = new EmptyVideoTech();
roldenburgd7490db2018-01-09 13:51:29 -08001812 private final VideoTech rcsVideoShare;
Eric Erfanian90508232017-03-24 09:31:16 -07001813 private final List<VideoTech> videoTechs;
roldenburg7bb96232017-10-09 10:32:05 -07001814 private VideoTech savedTech;
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001815
roldenburgd7490db2018-01-09 13:51:29 -08001816 @VisibleForTesting
1817 public VideoTechManager(DialerCall call) {
linyuh183cb712017-12-27 17:02:37 -08001818 this.context = call.context;
Eric Erfaniand8046e52017-04-06 09:41:50 -07001819
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001820 String phoneNumber = call.getNumber();
Eric Erfaniand8046e52017-04-06 09:41:50 -07001821 phoneNumber = phoneNumber != null ? phoneNumber : "";
Eric Erfanian2ca43182017-08-31 06:57:16 -07001822 phoneNumber = phoneNumber.replaceAll("[^+0-9]", "");
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001823
1824 // Insert order here determines the priority of that video tech option
Eric Erfanian8369df02017-05-03 10:27:13 -07001825 videoTechs = new ArrayList<>();
yueg457b3972017-09-18 15:11:47 -07001826
linyuh183cb712017-12-27 17:02:37 -08001827 videoTechs.add(new ImsVideoTech(Logger.get(call.context), call, call.telecomCall));
Eric Erfanian90508232017-03-24 09:31:16 -07001828
roldenburgd7490db2018-01-09 13:51:29 -08001829 rcsVideoShare =
linyuh183cb712017-12-27 17:02:37 -08001830 EnrichedCallComponent.get(call.context)
Eric Erfanian90508232017-03-24 09:31:16 -07001831 .getRcsVideoShareFactory()
1832 .newRcsVideoShare(
linyuh183cb712017-12-27 17:02:37 -08001833 EnrichedCallComponent.get(call.context).getEnrichedCallManager(),
Eric Erfanian90508232017-03-24 09:31:16 -07001834 call,
Eric Erfaniand8046e52017-04-06 09:41:50 -07001835 phoneNumber);
roldenburg3eca69f2018-01-16 12:07:04 -08001836 videoTechs.add(rcsVideoShare);
Eric Erfaniand8046e52017-04-06 09:41:50 -07001837
1838 videoTechs.add(
roldenburg4f026392017-10-13 18:42:20 -07001839 new DuoVideoTech(
linyuh183cb712017-12-27 17:02:37 -08001840 DuoComponent.get(call.context).getDuo(), call, call.telecomCall, phoneNumber));
roldenburgd7490db2018-01-09 13:51:29 -08001841
1842 savedTech = emptyVideoTech;
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001843 }
1844
roldenburgd7490db2018-01-09 13:51:29 -08001845 @VisibleForTesting
roldenburg6bd612f2018-01-18 12:57:19 -08001846 public VideoTech getVideoTech(PhoneAccountHandle phoneAccountHandle) {
roldenburgd7490db2018-01-09 13:51:29 -08001847 if (savedTech == emptyVideoTech) {
1848 for (VideoTech tech : videoTechs) {
roldenburg6bd612f2018-01-18 12:57:19 -08001849 if (tech.isAvailable(context, phoneAccountHandle)) {
roldenburgd7490db2018-01-09 13:51:29 -08001850 savedTech = tech;
1851 savedTech.becomePrimary();
1852 break;
1853 }
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001854 }
roldenburg6bd612f2018-01-18 12:57:19 -08001855 } else if (savedTech instanceof DuoVideoTech
1856 && rcsVideoShare.isAvailable(context, phoneAccountHandle)) {
roldenburgd7490db2018-01-09 13:51:29 -08001857 // RCS Video Share will become available after the capability exchange which is slower than
1858 // Duo reading local contacts for reachability. If Video Share becomes available and we are
1859 // not in the middle of any session changes, let it take over.
1860 savedTech = rcsVideoShare;
1861 rcsVideoShare.becomePrimary();
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001862 }
1863
roldenburgd7490db2018-01-09 13:51:29 -08001864 return savedTech;
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001865 }
1866
roldenburgd7490db2018-01-09 13:51:29 -08001867 @VisibleForTesting
roldenburg6bd612f2018-01-18 12:57:19 -08001868 public void dispatchCallStateChanged(int newState, PhoneAccountHandle phoneAccountHandle) {
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001869 for (VideoTech videoTech : videoTechs) {
roldenburg6bd612f2018-01-18 12:57:19 -08001870 videoTech.onCallStateChanged(context, newState, phoneAccountHandle);
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001871 }
1872 }
Eric Erfanian2ca43182017-08-31 06:57:16 -07001873
1874 void dispatchRemovedFromCallList() {
1875 for (VideoTech videoTech : videoTechs) {
1876 videoTech.onRemovedFromCallList();
1877 }
1878 }
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001879 }
1880
Eric Erfanianccca3152017-02-22 16:32:36 -08001881 /** Called when canned text responses have been loaded. */
1882 public interface CannedTextResponsesLoadedListener {
1883 void onCannedTextResponsesLoaded(DialerCall call);
1884 }
1885}