blob: 2ce4550bb2e4944c695c07878e6cdd82282bd0d3 [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;
50import com.android.contacts.common.compat.CallCompat;
Eric Erfanianccca3152017-02-22 16:32:36 -080051import com.android.contacts.common.compat.telecom.TelecomManagerCompat;
erfanian2cf2c342017-12-21 12:01:33 -080052import com.android.dialer.assisteddialing.ConcreteCreator;
erfaniand0f207f2017-10-11 12:23:29 -070053import com.android.dialer.assisteddialing.TransformationInfo;
Eric Erfanian8369df02017-05-03 10:27:13 -070054import com.android.dialer.callintent.CallInitiationType;
Eric Erfanianccca3152017-02-22 16:32:36 -080055import com.android.dialer.callintent.CallIntentParser;
Eric Erfanian8369df02017-05-03 10:27:13 -070056import com.android.dialer.callintent.CallSpecificAppData;
Eric Erfanianccca3152017-02-22 16:32:36 -080057import com.android.dialer.common.Assert;
Eric Erfanianccca3152017-02-22 16:32:36 -080058import com.android.dialer.common.LogUtil;
Eric Erfanian2ca43182017-08-31 06:57:16 -070059import com.android.dialer.compat.telephony.TelephonyManagerCompat;
60import com.android.dialer.configprovider.ConfigProviderBindings;
roldenburg4f026392017-10-13 18:42:20 -070061import com.android.dialer.duo.DuoComponent;
Eric Erfanian8369df02017-05-03 10:27:13 -070062import com.android.dialer.enrichedcall.EnrichedCallCapabilities;
Eric Erfaniand5e47f62017-03-15 14:41:07 -070063import com.android.dialer.enrichedcall.EnrichedCallComponent;
Eric Erfanian2ca43182017-08-31 06:57:16 -070064import com.android.dialer.enrichedcall.EnrichedCallManager;
65import com.android.dialer.enrichedcall.EnrichedCallManager.CapabilitiesListener;
66import com.android.dialer.enrichedcall.EnrichedCallManager.Filter;
67import com.android.dialer.enrichedcall.EnrichedCallManager.StateChangedListener;
Eric Erfanian8369df02017-05-03 10:27:13 -070068import com.android.dialer.enrichedcall.Session;
wangqi9982f0d2017-10-11 17:46:07 -070069import com.android.dialer.location.GeoUtil;
Eric Erfanian8369df02017-05-03 10:27:13 -070070import com.android.dialer.logging.ContactLookupResult;
twyendde01c52017-09-22 10:07:31 -070071import com.android.dialer.logging.ContactLookupResult.Type;
Eric Erfanian8369df02017-05-03 10:27:13 -070072import com.android.dialer.logging.DialerImpression;
73import com.android.dialer.logging.Logger;
twyen73a74c32018-03-07 12:12:24 -080074import com.android.dialer.preferredsim.PreferredAccountRecorder;
twyena4745bd2017-12-12 18:40:11 -080075import com.android.dialer.telecom.TelecomCallUtil;
wangqi9982f0d2017-10-11 17:46:07 -070076import com.android.dialer.telecom.TelecomUtil;
Eric Erfanianc857f902017-05-15 14:05:33 -070077import com.android.dialer.theme.R;
wangqi9982f0d2017-10-11 17:46:07 -070078import com.android.dialer.util.PermissionsUtil;
Eric Erfanian8369df02017-05-03 10:27:13 -070079import com.android.incallui.audiomode.AudioModeProvider;
Eric Erfanianccca3152017-02-22 16:32:36 -080080import com.android.incallui.latencyreport.LatencyReport;
Eric Erfaniand5e47f62017-03-15 14:41:07 -070081import com.android.incallui.videotech.VideoTech;
82import com.android.incallui.videotech.VideoTech.VideoTechListener;
roldenburg4f026392017-10-13 18:42:20 -070083import com.android.incallui.videotech.duo.DuoVideoTech;
Eric Erfaniand5e47f62017-03-15 14:41:07 -070084import com.android.incallui.videotech.empty.EmptyVideoTech;
85import com.android.incallui.videotech.ims.ImsVideoTech;
Eric Erfanian90508232017-03-24 09:31:16 -070086import com.android.incallui.videotech.utils.VideoUtils;
Eric Erfanianccca3152017-02-22 16:32:36 -080087import java.lang.annotation.Retention;
88import java.lang.annotation.RetentionPolicy;
89import java.util.ArrayList;
90import java.util.List;
91import java.util.Locale;
92import java.util.Objects;
93import java.util.UUID;
94import java.util.concurrent.CopyOnWriteArrayList;
95import java.util.concurrent.TimeUnit;
96
97/** Describes a single call and its state. */
Eric Erfanian2ca43182017-08-31 06:57:16 -070098public class DialerCall implements VideoTechListener, StateChangedListener, CapabilitiesListener {
Eric Erfanianccca3152017-02-22 16:32:36 -080099
100 public static final int CALL_HISTORY_STATUS_UNKNOWN = 0;
101 public static final int CALL_HISTORY_STATUS_PRESENT = 1;
102 public static final int CALL_HISTORY_STATUS_NOT_PRESENT = 2;
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700103
104 // Hard coded property for {@code Call}. Upstreamed change from Motorola.
Eric Erfanian938468d2017-10-24 14:05:52 -0700105 // TODO(a bug): Move it to Telecom in framework.
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700106 public static final int PROPERTY_CODEC_KNOWN = 0x04000000;
107
Eric Erfanianccca3152017-02-22 16:32:36 -0800108 private static final String ID_PREFIX = "DialerCall_";
109 private static final String CONFIG_EMERGENCY_CALLBACK_WINDOW_MILLIS =
110 "emergency_callback_window_millis";
linyuh183cb712017-12-27 17:02:37 -0800111 private static int idCounter = 0;
Eric Erfanianccca3152017-02-22 16:32:36 -0800112
113 /**
Eric Erfanianc857f902017-05-15 14:05:33 -0700114 * A counter used to append to restricted/private/hidden calls so that users can identify them in
115 * a conversation. This value is reset in {@link CallList#onCallRemoved(Context, Call)} when there
116 * are no live calls.
117 */
linyuh183cb712017-12-27 17:02:37 -0800118 private static int hiddenCounter;
Eric Erfanianc857f902017-05-15 14:05:33 -0700119
120 /**
Eric Erfanianccca3152017-02-22 16:32:36 -0800121 * The unique call ID for every call. This will help us to identify each call and allow us the
122 * ability to stitch impressions to calls if needed.
123 */
124 private final String uniqueCallId = UUID.randomUUID().toString();
125
linyuh183cb712017-12-27 17:02:37 -0800126 private final Call telecomCall;
127 private final LatencyReport latencyReport;
128 private final String id;
129 private final int hiddenId;
130 private final List<String> childCallIds = new ArrayList<>();
131 private final LogState logState = new LogState();
132 private final Context context;
133 private final DialerCallDelegate dialerCallDelegate;
134 private final List<DialerCallListener> listeners = new CopyOnWriteArrayList<>();
135 private final List<CannedTextResponsesLoadedListener> cannedTextResponsesLoadedListeners =
Eric Erfanianccca3152017-02-22 16:32:36 -0800136 new CopyOnWriteArrayList<>();
linyuh183cb712017-12-27 17:02:37 -0800137 private final VideoTechManager videoTechManager;
Eric Erfanianccca3152017-02-22 16:32:36 -0800138
erfaniand05d8992018-03-20 19:42:26 -0700139 private boolean isSpeakEasyCall;
linyuh183cb712017-12-27 17:02:37 -0800140 private boolean isEmergencyCall;
141 private Uri handle;
142 private int state = State.INVALID;
143 private DisconnectCause disconnectCause;
Eric Erfanianccca3152017-02-22 16:32:36 -0800144
145 private boolean hasShownWiFiToLteHandoverToast;
146 private boolean doNotShowDialogForHandoffToWifiFailure;
147
linyuh183cb712017-12-27 17:02:37 -0800148 private String childNumber;
149 private String lastForwardedNumber;
wangqif4ba3452018-01-09 11:26:29 -0800150 private boolean isCallForwarded;
linyuh183cb712017-12-27 17:02:37 -0800151 private String callSubject;
152 private PhoneAccountHandle phoneAccountHandle;
153 @CallHistoryStatus private int callHistoryStatus = CALL_HISTORY_STATUS_UNKNOWN;
154 private boolean isSpam;
155 private boolean isBlocked;
Eric Erfanian938468d2017-10-24 14:05:52 -0700156
157 @Nullable private Boolean isInUserSpamList;
158
159 @Nullable private Boolean isInUserWhiteList;
160
161 @Nullable private Boolean isInGlobalSpamList;
Eric Erfanianccca3152017-02-22 16:32:36 -0800162 private boolean didShowCameraPermission;
wangqida410d32018-03-06 16:51:38 -0800163 private boolean didDismissVideoChargesAlertDialog;
164 private PersistableBundle carrierConfig;
Eric Erfanianccca3152017-02-22 16:32:36 -0800165 private String callProviderLabel;
166 private String callbackNumber;
linyuh183cb712017-12-27 17:02:37 -0800167 private int cameraDirection = CameraDirection.CAMERA_DIRECTION_UNKNOWN;
168 private EnrichedCallCapabilities enrichedCallCapabilities;
169 private Session enrichedCallSession;
Eric Erfanianccca3152017-02-22 16:32:36 -0800170
Eric Erfanian2ca43182017-08-31 06:57:16 -0700171 private int answerAndReleaseButtonDisplayedTimes = 0;
172 private boolean releasedByAnsweringSecondCall = false;
173 // Times when a second call is received but AnswerAndRelease button is not shown
174 // since it's not supported.
175 private int secondCallWithoutAnswerAndReleasedButtonTimes = 0;
roldenburg7bb96232017-10-09 10:32:05 -0700176 private VideoTech videoTech;
Eric Erfanian2ca43182017-08-31 06:57:16 -0700177
wangqi4d705e52017-09-28 12:23:35 -0700178 private com.android.dialer.logging.VideoTech.Type selectedAvailableVideoTechType =
179 com.android.dialer.logging.VideoTech.Type.NONE;
wangqi9982f0d2017-10-11 17:46:07 -0700180 private boolean isVoicemailNumber;
181 private List<PhoneAccountHandle> callCapableAccounts;
182 private String countryIso;
yueg457b3972017-09-18 15:11:47 -0700183
Android Dialer974fc292018-02-01 16:12:25 -0800184 private volatile boolean feedbackRequested = false;
185
twyen73a74c32018-03-07 12:12:24 -0800186 @Nullable private PreferredAccountRecorder preferredAccountRecorder;
187
Eric Erfanianccca3152017-02-22 16:32:36 -0800188 public static String getNumberFromHandle(Uri handle) {
189 return handle == null ? "" : handle.getSchemeSpecificPart();
190 }
191
192 /**
193 * Whether the call is put on hold by remote party. This is different than the {@link
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700194 * State#ONHOLD} state which indicates that the call is being held locally on the device.
Eric Erfanianccca3152017-02-22 16:32:36 -0800195 */
196 private boolean isRemotelyHeld;
197
Eric Erfanian2ca43182017-08-31 06:57:16 -0700198 /** Indicates whether this call is currently in the process of being merged into a conference. */
199 private boolean isMergeInProcess;
200
Eric Erfanianccca3152017-02-22 16:32:36 -0800201 /**
202 * Indicates whether the phone account associated with this call supports specifying a call
203 * subject.
204 */
linyuh183cb712017-12-27 17:02:37 -0800205 private boolean isCallSubjectSupported;
Eric Erfanianccca3152017-02-22 16:32:36 -0800206
linyuh183cb712017-12-27 17:02:37 -0800207 private final Call.Callback telecomCallCallback =
Eric Erfanianccca3152017-02-22 16:32:36 -0800208 new Call.Callback() {
209 @Override
210 public void onStateChanged(Call call, int newState) {
211 LogUtil.v("TelecomCallCallback.onStateChanged", "call=" + call + " newState=" + newState);
212 update();
213 }
214
215 @Override
216 public void onParentChanged(Call call, Call newParent) {
217 LogUtil.v(
218 "TelecomCallCallback.onParentChanged", "call=" + call + " newParent=" + newParent);
219 update();
220 }
221
222 @Override
223 public void onChildrenChanged(Call call, List<Call> children) {
224 update();
225 }
226
227 @Override
228 public void onDetailsChanged(Call call, Call.Details details) {
Eric Erfanian2ca43182017-08-31 06:57:16 -0700229 LogUtil.v(
230 "TelecomCallCallback.onDetailsChanged", " call=" + call + " details=" + details);
Eric Erfanianccca3152017-02-22 16:32:36 -0800231 update();
232 }
233
234 @Override
235 public void onCannedTextResponsesLoaded(Call call, List<String> cannedTextResponses) {
236 LogUtil.v(
Eric Erfanian2ca43182017-08-31 06:57:16 -0700237 "TelecomCallCallback.onCannedTextResponsesLoaded",
Eric Erfanianccca3152017-02-22 16:32:36 -0800238 "call=" + call + " cannedTextResponses=" + cannedTextResponses);
linyuh183cb712017-12-27 17:02:37 -0800239 for (CannedTextResponsesLoadedListener listener : cannedTextResponsesLoadedListeners) {
Eric Erfanianccca3152017-02-22 16:32:36 -0800240 listener.onCannedTextResponsesLoaded(DialerCall.this);
241 }
242 }
243
244 @Override
245 public void onPostDialWait(Call call, String remainingPostDialSequence) {
246 LogUtil.v(
Eric Erfanian2ca43182017-08-31 06:57:16 -0700247 "TelecomCallCallback.onPostDialWait",
Eric Erfanianccca3152017-02-22 16:32:36 -0800248 "call=" + call + " remainingPostDialSequence=" + remainingPostDialSequence);
249 update();
250 }
251
252 @Override
253 public void onVideoCallChanged(Call call, VideoCall videoCall) {
254 LogUtil.v(
Eric Erfanian2ca43182017-08-31 06:57:16 -0700255 "TelecomCallCallback.onVideoCallChanged", "call=" + call + " videoCall=" + videoCall);
Eric Erfanianccca3152017-02-22 16:32:36 -0800256 update();
257 }
258
259 @Override
260 public void onCallDestroyed(Call call) {
Eric Erfanian2ca43182017-08-31 06:57:16 -0700261 LogUtil.v("TelecomCallCallback.onCallDestroyed", "call=" + call);
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700262 unregisterCallback();
Eric Erfanianccca3152017-02-22 16:32:36 -0800263 }
264
265 @Override
266 public void onConferenceableCallsChanged(Call call, List<Call> conferenceableCalls) {
267 LogUtil.v(
Eric Erfanian2ca43182017-08-31 06:57:16 -0700268 "TelecomCallCallback.onConferenceableCallsChanged",
Eric Erfanianccca3152017-02-22 16:32:36 -0800269 "call %s, conferenceable calls: %d",
270 call,
271 conferenceableCalls.size());
272 update();
273 }
274
275 @Override
wangqi219b8702018-02-13 09:34:41 -0800276 public void onRttModeChanged(Call call, int mode) {
277 LogUtil.v("TelecomCallCallback.onRttModeChanged", "mode=%d", mode);
278 }
279
280 @Override
281 public void onRttRequest(Call call, int id) {
282 LogUtil.v("TelecomCallCallback.onRttRequest", "id=%d", id);
283 }
284
285 @Override
286 public void onRttInitiationFailure(Call call, int reason) {
287 LogUtil.v("TelecomCallCallback.onRttInitiationFailure", "reason=%d", reason);
288 update();
289 }
290
291 @Override
292 public void onRttStatusChanged(Call call, boolean enabled, RttCall rttCall) {
293 LogUtil.v("TelecomCallCallback.onRttStatusChanged", "enabled=%b", enabled);
294 update();
295 }
296
297 @Override
Eric Erfanianccca3152017-02-22 16:32:36 -0800298 public void onConnectionEvent(android.telecom.Call call, String event, Bundle extras) {
299 LogUtil.v(
Eric Erfanian2ca43182017-08-31 06:57:16 -0700300 "TelecomCallCallback.onConnectionEvent",
Eric Erfanianccca3152017-02-22 16:32:36 -0800301 "Call: " + call + ", Event: " + event + ", Extras: " + extras);
302 switch (event) {
303 // The Previous attempt to Merge two calls together has failed in Telecom. We must
304 // now update the UI to possibly re-enable the Merge button based on the number of
305 // currently conferenceable calls available or Connection Capabilities.
306 case android.telecom.Connection.EVENT_CALL_MERGE_FAILED:
307 update();
308 break;
309 case TelephonyManagerCompat.EVENT_HANDOVER_VIDEO_FROM_WIFI_TO_LTE:
310 notifyWiFiToLteHandover();
311 break;
312 case TelephonyManagerCompat.EVENT_HANDOVER_TO_WIFI_FAILED:
313 notifyHandoverToWifiFailed();
314 break;
315 case TelephonyManagerCompat.EVENT_CALL_REMOTELY_HELD:
316 isRemotelyHeld = true;
317 update();
318 break;
319 case TelephonyManagerCompat.EVENT_CALL_REMOTELY_UNHELD:
320 isRemotelyHeld = false;
321 update();
322 break;
Eric Erfanianc857f902017-05-15 14:05:33 -0700323 case TelephonyManagerCompat.EVENT_NOTIFY_INTERNATIONAL_CALL_ON_WFC:
324 notifyInternationalCallOnWifi();
325 break;
Eric Erfanian2ca43182017-08-31 06:57:16 -0700326 case TelephonyManagerCompat.EVENT_MERGE_START:
327 LogUtil.i("DialerCall.onConnectionEvent", "merge start");
328 isMergeInProcess = true;
329 break;
330 case TelephonyManagerCompat.EVENT_MERGE_COMPLETE:
331 LogUtil.i("DialerCall.onConnectionEvent", "merge complete");
332 isMergeInProcess = false;
333 break;
wangqif4ba3452018-01-09 11:26:29 -0800334 case TelephonyManagerCompat.EVENT_CALL_FORWARDED:
335 // Only handle this event for P+ since it's unreliable pre-P.
336 if (BuildCompat.isAtLeastP()) {
337 isCallForwarded = true;
338 update();
339 }
340 break;
Eric Erfanianccca3152017-02-22 16:32:36 -0800341 default:
342 break;
343 }
344 }
345 };
Eric Erfanianc857f902017-05-15 14:05:33 -0700346
linyuh183cb712017-12-27 17:02:37 -0800347 private long timeAddedMs;
Eric Erfanianccca3152017-02-22 16:32:36 -0800348
349 public DialerCall(
350 Context context,
351 DialerCallDelegate dialerCallDelegate,
352 Call telecomCall,
353 LatencyReport latencyReport,
354 boolean registerCallback) {
355 Assert.isNotNull(context);
linyuh183cb712017-12-27 17:02:37 -0800356 this.context = context;
357 this.dialerCallDelegate = dialerCallDelegate;
358 this.telecomCall = telecomCall;
359 this.latencyReport = latencyReport;
360 id = ID_PREFIX + Integer.toString(idCounter++);
Eric Erfanianccca3152017-02-22 16:32:36 -0800361
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700362 // Must be after assigning mTelecomCall
linyuh183cb712017-12-27 17:02:37 -0800363 videoTechManager = new VideoTechManager(this);
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700364
365 updateFromTelecomCall();
Eric Erfanianc857f902017-05-15 14:05:33 -0700366 if (isHiddenNumber() && TextUtils.isEmpty(getNumber())) {
linyuh183cb712017-12-27 17:02:37 -0800367 hiddenId = ++hiddenCounter;
Eric Erfanianc857f902017-05-15 14:05:33 -0700368 } else {
linyuh183cb712017-12-27 17:02:37 -0800369 hiddenId = 0;
Eric Erfanianc857f902017-05-15 14:05:33 -0700370 }
Eric Erfanianccca3152017-02-22 16:32:36 -0800371
372 if (registerCallback) {
linyuh183cb712017-12-27 17:02:37 -0800373 this.telecomCall.registerCallback(telecomCallCallback);
Eric Erfanianccca3152017-02-22 16:32:36 -0800374 }
375
linyuh183cb712017-12-27 17:02:37 -0800376 timeAddedMs = System.currentTimeMillis();
Eric Erfanianccca3152017-02-22 16:32:36 -0800377 parseCallSpecificAppData();
Eric Erfanian2ca43182017-08-31 06:57:16 -0700378
379 updateEnrichedCallSession();
Eric Erfanianccca3152017-02-22 16:32:36 -0800380 }
381
twyendde01c52017-09-22 10:07:31 -0700382 /** Test only constructor to avoid initializing dependencies. */
383 @VisibleForTesting
384 DialerCall(Context context) {
linyuh183cb712017-12-27 17:02:37 -0800385 this.context = context;
386 telecomCall = null;
387 latencyReport = null;
388 id = null;
389 hiddenId = 0;
390 dialerCallDelegate = null;
391 videoTechManager = null;
twyendde01c52017-09-22 10:07:31 -0700392 }
393
Eric Erfanianccca3152017-02-22 16:32:36 -0800394 private static int translateState(int state) {
395 switch (state) {
396 case Call.STATE_NEW:
397 case Call.STATE_CONNECTING:
398 return DialerCall.State.CONNECTING;
399 case Call.STATE_SELECT_PHONE_ACCOUNT:
400 return DialerCall.State.SELECT_PHONE_ACCOUNT;
401 case Call.STATE_DIALING:
402 return DialerCall.State.DIALING;
403 case Call.STATE_PULLING_CALL:
404 return DialerCall.State.PULLING;
405 case Call.STATE_RINGING:
406 return DialerCall.State.INCOMING;
407 case Call.STATE_ACTIVE:
408 return DialerCall.State.ACTIVE;
409 case Call.STATE_HOLDING:
410 return DialerCall.State.ONHOLD;
411 case Call.STATE_DISCONNECTED:
412 return DialerCall.State.DISCONNECTED;
413 case Call.STATE_DISCONNECTING:
414 return DialerCall.State.DISCONNECTING;
415 default:
416 return DialerCall.State.INVALID;
417 }
418 }
419
420 public static boolean areSame(DialerCall call1, DialerCall call2) {
421 if (call1 == null && call2 == null) {
422 return true;
423 } else if (call1 == null || call2 == null) {
424 return false;
425 }
426
427 // otherwise compare call Ids
428 return call1.getId().equals(call2.getId());
429 }
430
Eric Erfanianccca3152017-02-22 16:32:36 -0800431 public void addListener(DialerCallListener listener) {
432 Assert.isMainThread();
linyuh183cb712017-12-27 17:02:37 -0800433 listeners.add(listener);
Eric Erfanianccca3152017-02-22 16:32:36 -0800434 }
435
436 public void removeListener(DialerCallListener listener) {
437 Assert.isMainThread();
linyuh183cb712017-12-27 17:02:37 -0800438 listeners.remove(listener);
Eric Erfanianccca3152017-02-22 16:32:36 -0800439 }
440
441 public void addCannedTextResponsesLoadedListener(CannedTextResponsesLoadedListener listener) {
442 Assert.isMainThread();
linyuh183cb712017-12-27 17:02:37 -0800443 cannedTextResponsesLoadedListeners.add(listener);
Eric Erfanianccca3152017-02-22 16:32:36 -0800444 }
445
446 public void removeCannedTextResponsesLoadedListener(CannedTextResponsesLoadedListener listener) {
447 Assert.isMainThread();
linyuh183cb712017-12-27 17:02:37 -0800448 cannedTextResponsesLoadedListeners.remove(listener);
Eric Erfanianccca3152017-02-22 16:32:36 -0800449 }
450
451 public void notifyWiFiToLteHandover() {
452 LogUtil.i("DialerCall.notifyWiFiToLteHandover", "");
linyuh183cb712017-12-27 17:02:37 -0800453 for (DialerCallListener listener : listeners) {
Eric Erfanianccca3152017-02-22 16:32:36 -0800454 listener.onWiFiToLteHandover();
455 }
456 }
457
458 public void notifyHandoverToWifiFailed() {
459 LogUtil.i("DialerCall.notifyHandoverToWifiFailed", "");
linyuh183cb712017-12-27 17:02:37 -0800460 for (DialerCallListener listener : listeners) {
Eric Erfanianccca3152017-02-22 16:32:36 -0800461 listener.onHandoverToWifiFailure();
462 }
463 }
464
Eric Erfanianc857f902017-05-15 14:05:33 -0700465 public void notifyInternationalCallOnWifi() {
466 LogUtil.enterBlock("DialerCall.notifyInternationalCallOnWifi");
linyuh183cb712017-12-27 17:02:37 -0800467 for (DialerCallListener dialerCallListener : listeners) {
Eric Erfanianc857f902017-05-15 14:05:33 -0700468 dialerCallListener.onInternationalCallOnWifi();
469 }
470 }
471
Eric Erfanianccca3152017-02-22 16:32:36 -0800472 /* package-private */ Call getTelecomCall() {
linyuh183cb712017-12-27 17:02:37 -0800473 return telecomCall;
Eric Erfanianccca3152017-02-22 16:32:36 -0800474 }
wangqida410d32018-03-06 16:51:38 -0800475
Eric Erfanianccca3152017-02-22 16:32:36 -0800476 public StatusHints getStatusHints() {
linyuh183cb712017-12-27 17:02:37 -0800477 return telecomCall.getDetails().getStatusHints();
Eric Erfanianccca3152017-02-22 16:32:36 -0800478 }
479
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700480 public int getCameraDir() {
linyuh183cb712017-12-27 17:02:37 -0800481 return cameraDirection;
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700482 }
483
484 public void setCameraDir(int cameraDir) {
485 if (cameraDir == CameraDirection.CAMERA_DIRECTION_FRONT_FACING
486 || cameraDir == CameraDirection.CAMERA_DIRECTION_BACK_FACING) {
linyuh183cb712017-12-27 17:02:37 -0800487 cameraDirection = cameraDir;
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700488 } else {
linyuh183cb712017-12-27 17:02:37 -0800489 cameraDirection = CameraDirection.CAMERA_DIRECTION_UNKNOWN;
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700490 }
Eric Erfanianccca3152017-02-22 16:32:36 -0800491 }
492
Eric Erfanian2ca43182017-08-31 06:57:16 -0700493 public boolean wasParentCall() {
linyuh183cb712017-12-27 17:02:37 -0800494 return logState.conferencedCalls != 0;
Eric Erfanian2ca43182017-08-31 06:57:16 -0700495 }
496
wangqi9982f0d2017-10-11 17:46:07 -0700497 public boolean isVoiceMailNumber() {
498 return isVoicemailNumber;
499 }
500
501 public List<PhoneAccountHandle> getCallCapableAccounts() {
502 return callCapableAccounts;
503 }
504
505 public String getCountryIso() {
506 return countryIso;
507 }
508
509 private void updateIsVoiceMailNumber() {
510 if (getHandle() != null && PhoneAccount.SCHEME_VOICEMAIL.equals(getHandle().getScheme())) {
511 isVoicemailNumber = true;
roldenburg37a969d2018-02-22 14:46:44 -0800512 return;
wangqi9982f0d2017-10-11 17:46:07 -0700513 }
514
linyuh183cb712017-12-27 17:02:37 -0800515 if (!PermissionsUtil.hasPermission(context, permission.READ_PHONE_STATE)) {
wangqi9982f0d2017-10-11 17:46:07 -0700516 isVoicemailNumber = false;
roldenburg37a969d2018-02-22 14:46:44 -0800517 return;
wangqi9982f0d2017-10-11 17:46:07 -0700518 }
519
linyuh183cb712017-12-27 17:02:37 -0800520 isVoicemailNumber = TelecomUtil.isVoicemailNumber(context, getAccountHandle(), getNumber());
wangqi9982f0d2017-10-11 17:46:07 -0700521 }
522
Eric Erfanianccca3152017-02-22 16:32:36 -0800523 private void update() {
Eric Erfanian2ca43182017-08-31 06:57:16 -0700524 Trace.beginSection("DialerCall.update");
Eric Erfanianccca3152017-02-22 16:32:36 -0800525 int oldState = getState();
roldenburg7bb96232017-10-09 10:32:05 -0700526 // Clear any cache here that could potentially change on update.
527 videoTech = null;
Eric Erfanianccca3152017-02-22 16:32:36 -0800528 // We want to potentially register a video call callback here.
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700529 updateFromTelecomCall();
Eric Erfanianccca3152017-02-22 16:32:36 -0800530 if (oldState != getState() && getState() == DialerCall.State.DISCONNECTED) {
linyuh183cb712017-12-27 17:02:37 -0800531 for (DialerCallListener listener : listeners) {
Eric Erfanianccca3152017-02-22 16:32:36 -0800532 listener.onDialerCallDisconnect();
533 }
linyuh183cb712017-12-27 17:02:37 -0800534 EnrichedCallComponent.get(context)
Eric Erfanian2ca43182017-08-31 06:57:16 -0700535 .getEnrichedCallManager()
536 .unregisterCapabilitiesListener(this);
linyuh183cb712017-12-27 17:02:37 -0800537 EnrichedCallComponent.get(context)
Eric Erfanian2ca43182017-08-31 06:57:16 -0700538 .getEnrichedCallManager()
539 .unregisterStateChangedListener(this);
Eric Erfanianccca3152017-02-22 16:32:36 -0800540 } else {
linyuh183cb712017-12-27 17:02:37 -0800541 for (DialerCallListener listener : listeners) {
Eric Erfanianccca3152017-02-22 16:32:36 -0800542 listener.onDialerCallUpdate();
543 }
544 }
545 Trace.endSection();
546 }
547
wangqi9982f0d2017-10-11 17:46:07 -0700548 @SuppressWarnings("MissingPermission")
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700549 private void updateFromTelecomCall() {
Eric Erfanian2ca43182017-08-31 06:57:16 -0700550 Trace.beginSection("DialerCall.updateFromTelecomCall");
linyuh183cb712017-12-27 17:02:37 -0800551 LogUtil.v("DialerCall.updateFromTelecomCall", telecomCall.toString());
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700552
roldenburg6bd612f2018-01-18 12:57:19 -0800553 videoTechManager.dispatchCallStateChanged(telecomCall.getState(), getAccountHandle());
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700554
linyuh183cb712017-12-27 17:02:37 -0800555 final int translatedState = translateState(telecomCall.getState());
556 if (state != State.BLOCKED) {
Eric Erfanianccca3152017-02-22 16:32:36 -0800557 setState(translatedState);
linyuh183cb712017-12-27 17:02:37 -0800558 setDisconnectCause(telecomCall.getDetails().getDisconnectCause());
Eric Erfanianccca3152017-02-22 16:32:36 -0800559 }
560
linyuh183cb712017-12-27 17:02:37 -0800561 childCallIds.clear();
562 final int numChildCalls = telecomCall.getChildren().size();
Eric Erfanianccca3152017-02-22 16:32:36 -0800563 for (int i = 0; i < numChildCalls; i++) {
linyuh183cb712017-12-27 17:02:37 -0800564 childCallIds.add(
565 dialerCallDelegate
566 .getDialerCallFromTelecomCall(telecomCall.getChildren().get(i))
Eric Erfanianccca3152017-02-22 16:32:36 -0800567 .getId());
568 }
569
570 // The number of conferenced calls can change over the course of the call, so use the
571 // maximum number of conferenced child calls as the metric for conference call usage.
linyuh183cb712017-12-27 17:02:37 -0800572 logState.conferencedCalls = Math.max(numChildCalls, logState.conferencedCalls);
Eric Erfanianccca3152017-02-22 16:32:36 -0800573
linyuh183cb712017-12-27 17:02:37 -0800574 updateFromCallExtras(telecomCall.getDetails().getExtras());
Eric Erfanianccca3152017-02-22 16:32:36 -0800575
576 // If the handle of the call has changed, update state for the call determining if it is an
577 // emergency call.
linyuh183cb712017-12-27 17:02:37 -0800578 Uri newHandle = telecomCall.getDetails().getHandle();
579 if (!Objects.equals(handle, newHandle)) {
580 handle = newHandle;
Eric Erfanianccca3152017-02-22 16:32:36 -0800581 updateEmergencyCallState();
582 }
583
linyuh183cb712017-12-27 17:02:37 -0800584 TelecomManager telecomManager = context.getSystemService(TelecomManager.class);
Eric Erfanianccca3152017-02-22 16:32:36 -0800585 // If the phone account handle of the call is set, cache capability bit indicating whether
586 // the phone account supports call subjects.
linyuh183cb712017-12-27 17:02:37 -0800587 PhoneAccountHandle newPhoneAccountHandle = telecomCall.getDetails().getAccountHandle();
588 if (!Objects.equals(phoneAccountHandle, newPhoneAccountHandle)) {
589 phoneAccountHandle = newPhoneAccountHandle;
Eric Erfanianccca3152017-02-22 16:32:36 -0800590
linyuh183cb712017-12-27 17:02:37 -0800591 if (phoneAccountHandle != null) {
592 PhoneAccount phoneAccount = telecomManager.getPhoneAccount(phoneAccountHandle);
Eric Erfanianccca3152017-02-22 16:32:36 -0800593 if (phoneAccount != null) {
linyuh183cb712017-12-27 17:02:37 -0800594 isCallSubjectSupported =
Eric Erfanianccca3152017-02-22 16:32:36 -0800595 phoneAccount.hasCapabilities(PhoneAccount.CAPABILITY_CALL_SUBJECT);
wangqida410d32018-03-06 16:51:38 -0800596 if (phoneAccount.hasCapabilities(PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION)) {
597 cacheCarrierConfiguration(phoneAccountHandle);
598 }
Eric Erfanianccca3152017-02-22 16:32:36 -0800599 }
600 }
601 }
linyuh183cb712017-12-27 17:02:37 -0800602 if (PermissionsUtil.hasPermission(context, permission.READ_PHONE_STATE)) {
wangqi9982f0d2017-10-11 17:46:07 -0700603 updateIsVoiceMailNumber();
604 callCapableAccounts = telecomManager.getCallCapablePhoneAccounts();
linyuh183cb712017-12-27 17:02:37 -0800605 countryIso = GeoUtil.getCurrentCountryIso(context);
wangqi9982f0d2017-10-11 17:46:07 -0700606 }
Eric Erfanian2ca43182017-08-31 06:57:16 -0700607 Trace.endSection();
Eric Erfanianccca3152017-02-22 16:32:36 -0800608 }
609
610 /**
wangqida410d32018-03-06 16:51:38 -0800611 * Caches frequently used carrier configuration locally.
612 *
613 * @param accountHandle The PhoneAccount handle.
614 */
615 @SuppressLint("MissingPermission")
616 private void cacheCarrierConfiguration(PhoneAccountHandle accountHandle) {
617 if (!PermissionsUtil.hasPermission(context, permission.READ_PHONE_STATE)) {
618 return;
619 }
620 if (VERSION.SDK_INT < VERSION_CODES.O) {
621 return;
622 }
623 // TODO(a bug): This may take several seconds to complete, revisit it to move it to worker
624 // thread.
625 carrierConfig =
626 TelephonyManagerCompat.getTelephonyManagerForPhoneAccountHandle(context, accountHandle)
627 .getCarrierConfig();
628 }
629
630 /**
Eric Erfanianccca3152017-02-22 16:32:36 -0800631 * Tests corruption of the {@code callExtras} bundle by calling {@link
632 * Bundle#containsKey(String)}. If the bundle is corrupted a {@link IllegalArgumentException} will
633 * be thrown and caught by this function.
634 *
635 * @param callExtras the bundle to verify
636 * @return {@code true} if the bundle is corrupted, {@code false} otherwise.
637 */
638 protected boolean areCallExtrasCorrupted(Bundle callExtras) {
639 /**
Eric Erfanian938468d2017-10-24 14:05:52 -0700640 * There's currently a bug in Telephony service (a bug) that could corrupt the extras
Eric Erfanianccca3152017-02-22 16:32:36 -0800641 * bundle, resulting in a IllegalArgumentException while validating data under {@link
642 * Bundle#containsKey(String)}.
643 */
644 try {
645 callExtras.containsKey(Connection.EXTRA_CHILD_ADDRESS);
646 return false;
647 } catch (IllegalArgumentException e) {
648 LogUtil.e(
649 "DialerCall.areCallExtrasCorrupted", "callExtras is corrupted, ignoring exception", e);
650 return true;
651 }
652 }
653
654 protected void updateFromCallExtras(Bundle callExtras) {
655 if (callExtras == null || areCallExtrasCorrupted(callExtras)) {
656 /**
657 * If the bundle is corrupted, abandon information update as a work around. These are not
658 * critical for the dialer to function.
659 */
660 return;
661 }
662 // Check for a change in the child address and notify any listeners.
663 if (callExtras.containsKey(Connection.EXTRA_CHILD_ADDRESS)) {
664 String childNumber = callExtras.getString(Connection.EXTRA_CHILD_ADDRESS);
linyuh183cb712017-12-27 17:02:37 -0800665 if (!Objects.equals(childNumber, this.childNumber)) {
666 this.childNumber = childNumber;
667 for (DialerCallListener listener : listeners) {
Eric Erfanianccca3152017-02-22 16:32:36 -0800668 listener.onDialerCallChildNumberChange();
669 }
670 }
671 }
672
673 // Last forwarded number comes in as an array of strings. We want to choose the
674 // last item in the array. The forwarding numbers arrive independently of when the
675 // call is originally set up, so we need to notify the the UI of the change.
676 if (callExtras.containsKey(Connection.EXTRA_LAST_FORWARDED_NUMBER)) {
677 ArrayList<String> lastForwardedNumbers =
678 callExtras.getStringArrayList(Connection.EXTRA_LAST_FORWARDED_NUMBER);
679
680 if (lastForwardedNumbers != null) {
681 String lastForwardedNumber = null;
682 if (!lastForwardedNumbers.isEmpty()) {
683 lastForwardedNumber = lastForwardedNumbers.get(lastForwardedNumbers.size() - 1);
684 }
685
linyuh183cb712017-12-27 17:02:37 -0800686 if (!Objects.equals(lastForwardedNumber, this.lastForwardedNumber)) {
687 this.lastForwardedNumber = lastForwardedNumber;
688 for (DialerCallListener listener : listeners) {
Eric Erfanianccca3152017-02-22 16:32:36 -0800689 listener.onDialerCallLastForwardedNumberChange();
690 }
691 }
692 }
693 }
694
695 // DialerCall subject is present in the extras at the start of call, so we do not need to
696 // notify any other listeners of this.
697 if (callExtras.containsKey(Connection.EXTRA_CALL_SUBJECT)) {
698 String callSubject = callExtras.getString(Connection.EXTRA_CALL_SUBJECT);
linyuh183cb712017-12-27 17:02:37 -0800699 if (!Objects.equals(this.callSubject, callSubject)) {
700 this.callSubject = callSubject;
Eric Erfanianccca3152017-02-22 16:32:36 -0800701 }
702 }
703 }
704
Eric Erfanianccca3152017-02-22 16:32:36 -0800705 public String getId() {
linyuh183cb712017-12-27 17:02:37 -0800706 return id;
Eric Erfanianccca3152017-02-22 16:32:36 -0800707 }
708
Eric Erfanianc857f902017-05-15 14:05:33 -0700709 /**
710 * @return name appended with a number if the number is restricted/unknown and the user has
711 * received more than one restricted/unknown call.
712 */
713 @Nullable
714 public String updateNameIfRestricted(@Nullable String name) {
linyuh183cb712017-12-27 17:02:37 -0800715 if (name != null && isHiddenNumber() && hiddenId != 0 && hiddenCounter > 1) {
716 return context.getString(R.string.unknown_counter, name, hiddenId);
Eric Erfanianc857f902017-05-15 14:05:33 -0700717 }
718 return name;
719 }
720
721 public static void clearRestrictedCount() {
linyuh183cb712017-12-27 17:02:37 -0800722 hiddenCounter = 0;
Eric Erfanianc857f902017-05-15 14:05:33 -0700723 }
724
725 private boolean isHiddenNumber() {
726 return getNumberPresentation() == TelecomManager.PRESENTATION_RESTRICTED
727 || getNumberPresentation() == TelecomManager.PRESENTATION_UNKNOWN;
728 }
729
Eric Erfanianccca3152017-02-22 16:32:36 -0800730 public boolean hasShownWiFiToLteHandoverToast() {
731 return hasShownWiFiToLteHandoverToast;
732 }
733
734 public void setHasShownWiFiToLteHandoverToast() {
735 hasShownWiFiToLteHandoverToast = true;
736 }
737
738 public boolean showWifiHandoverAlertAsToast() {
739 return doNotShowDialogForHandoffToWifiFailure;
740 }
741
742 public void setDoNotShowDialogForHandoffToWifiFailure(boolean bool) {
743 doNotShowDialogForHandoffToWifiFailure = bool;
744 }
745
wangqida410d32018-03-06 16:51:38 -0800746 public boolean showVideoChargesAlertDialog() {
747 if (carrierConfig == null) {
748 return false;
749 }
750 return carrierConfig.getBoolean(
751 TelephonyManagerCompat.CARRIER_CONFIG_KEY_SHOW_VIDEO_CALL_CHARGES_ALERT_DIALOG_BOOL);
752 }
753
Eric Erfanianccca3152017-02-22 16:32:36 -0800754 public long getTimeAddedMs() {
linyuh183cb712017-12-27 17:02:37 -0800755 return timeAddedMs;
Eric Erfanianccca3152017-02-22 16:32:36 -0800756 }
757
758 @Nullable
759 public String getNumber() {
linyuh183cb712017-12-27 17:02:37 -0800760 return TelecomCallUtil.getNumber(telecomCall);
Eric Erfanianccca3152017-02-22 16:32:36 -0800761 }
762
763 public void blockCall() {
linyuh183cb712017-12-27 17:02:37 -0800764 telecomCall.reject(false, null);
Eric Erfanianccca3152017-02-22 16:32:36 -0800765 setState(State.BLOCKED);
766 }
767
768 @Nullable
769 public Uri getHandle() {
linyuh183cb712017-12-27 17:02:37 -0800770 return telecomCall == null ? null : telecomCall.getDetails().getHandle();
Eric Erfanianccca3152017-02-22 16:32:36 -0800771 }
772
773 public boolean isEmergencyCall() {
linyuh183cb712017-12-27 17:02:37 -0800774 return isEmergencyCall;
Eric Erfanianccca3152017-02-22 16:32:36 -0800775 }
776
777 public boolean isPotentialEmergencyCallback() {
778 // The property PROPERTY_EMERGENCY_CALLBACK_MODE is only set for CDMA calls when the system
779 // is actually in emergency callback mode (ie data is disabled).
780 if (hasProperty(Details.PROPERTY_EMERGENCY_CALLBACK_MODE)) {
781 return true;
782 }
783 // We want to treat any incoming call that arrives a short time after an outgoing emergency call
784 // as a potential emergency callback.
785 if (getExtras() != null
786 && getExtras().getLong(TelecomManagerCompat.EXTRA_LAST_EMERGENCY_CALLBACK_TIME_MILLIS, 0)
787 > 0) {
788 long lastEmergencyCallMillis =
789 getExtras().getLong(TelecomManagerCompat.EXTRA_LAST_EMERGENCY_CALLBACK_TIME_MILLIS, 0);
790 if (isInEmergencyCallbackWindow(lastEmergencyCallMillis)) {
791 return true;
792 }
793 }
794 return false;
795 }
796
797 boolean isInEmergencyCallbackWindow(long timestampMillis) {
798 long emergencyCallbackWindowMillis =
linyuh183cb712017-12-27 17:02:37 -0800799 ConfigProviderBindings.get(context)
Eric Erfanianccca3152017-02-22 16:32:36 -0800800 .getLong(CONFIG_EMERGENCY_CALLBACK_WINDOW_MILLIS, TimeUnit.MINUTES.toMillis(5));
801 return System.currentTimeMillis() - timestampMillis < emergencyCallbackWindowMillis;
802 }
803
804 public int getState() {
linyuh183cb712017-12-27 17:02:37 -0800805 if (telecomCall != null && telecomCall.getParent() != null) {
Eric Erfanianccca3152017-02-22 16:32:36 -0800806 return State.CONFERENCED;
807 } else {
linyuh183cb712017-12-27 17:02:37 -0800808 return state;
Eric Erfanianccca3152017-02-22 16:32:36 -0800809 }
810 }
811
yueg265089a2017-10-06 14:35:15 -0700812 public int getNonConferenceState() {
linyuh183cb712017-12-27 17:02:37 -0800813 return state;
yueg265089a2017-10-06 14:35:15 -0700814 }
815
Eric Erfanianccca3152017-02-22 16:32:36 -0800816 public void setState(int state) {
Eric Erfanian2ca43182017-08-31 06:57:16 -0700817 if (state == State.INCOMING) {
linyuh183cb712017-12-27 17:02:37 -0800818 logState.isIncoming = true;
Eric Erfanian2ca43182017-08-31 06:57:16 -0700819 } else if (state == State.DISCONNECTED) {
820 long newDuration =
Eric Erfanianccca3152017-02-22 16:32:36 -0800821 getConnectTimeMillis() == 0 ? 0 : System.currentTimeMillis() - getConnectTimeMillis();
linyuh183cb712017-12-27 17:02:37 -0800822 if (this.state != state) {
823 logState.duration = newDuration;
Eric Erfanian2ca43182017-08-31 06:57:16 -0700824 } else {
825 LogUtil.i(
826 "DialerCall.setState",
827 "ignoring state transition from DISCONNECTED to DISCONNECTED."
828 + " Duration would have changed from %s to %s",
linyuh183cb712017-12-27 17:02:37 -0800829 logState.duration,
Eric Erfanian2ca43182017-08-31 06:57:16 -0700830 newDuration);
831 }
Eric Erfanianccca3152017-02-22 16:32:36 -0800832 }
linyuh183cb712017-12-27 17:02:37 -0800833 this.state = state;
Eric Erfanianccca3152017-02-22 16:32:36 -0800834 }
835
836 public int getNumberPresentation() {
linyuh183cb712017-12-27 17:02:37 -0800837 return telecomCall == null ? -1 : telecomCall.getDetails().getHandlePresentation();
Eric Erfanianccca3152017-02-22 16:32:36 -0800838 }
839
840 public int getCnapNamePresentation() {
linyuh183cb712017-12-27 17:02:37 -0800841 return telecomCall == null ? -1 : telecomCall.getDetails().getCallerDisplayNamePresentation();
Eric Erfanianccca3152017-02-22 16:32:36 -0800842 }
843
844 @Nullable
845 public String getCnapName() {
linyuh183cb712017-12-27 17:02:37 -0800846 return telecomCall == null ? null : getTelecomCall().getDetails().getCallerDisplayName();
Eric Erfanianccca3152017-02-22 16:32:36 -0800847 }
848
849 public Bundle getIntentExtras() {
linyuh183cb712017-12-27 17:02:37 -0800850 return telecomCall.getDetails().getIntentExtras();
Eric Erfanianccca3152017-02-22 16:32:36 -0800851 }
852
853 @Nullable
854 public Bundle getExtras() {
linyuh183cb712017-12-27 17:02:37 -0800855 return telecomCall == null ? null : telecomCall.getDetails().getExtras();
Eric Erfanianccca3152017-02-22 16:32:36 -0800856 }
857
858 /** @return The child number for the call, or {@code null} if none specified. */
859 public String getChildNumber() {
linyuh183cb712017-12-27 17:02:37 -0800860 return childNumber;
Eric Erfanianccca3152017-02-22 16:32:36 -0800861 }
862
863 /** @return The last forwarded number for the call, or {@code null} if none specified. */
864 public String getLastForwardedNumber() {
linyuh183cb712017-12-27 17:02:37 -0800865 return lastForwardedNumber;
Eric Erfanianccca3152017-02-22 16:32:36 -0800866 }
867
wangqif4ba3452018-01-09 11:26:29 -0800868 public boolean isCallForwarded() {
869 return isCallForwarded;
870 }
871
Eric Erfanianccca3152017-02-22 16:32:36 -0800872 /** @return The call subject, or {@code null} if none specified. */
873 public String getCallSubject() {
linyuh183cb712017-12-27 17:02:37 -0800874 return callSubject;
Eric Erfanianccca3152017-02-22 16:32:36 -0800875 }
876
877 /**
878 * @return {@code true} if the call's phone account supports call subjects, {@code false}
879 * otherwise.
880 */
881 public boolean isCallSubjectSupported() {
linyuh183cb712017-12-27 17:02:37 -0800882 return isCallSubjectSupported;
Eric Erfanianccca3152017-02-22 16:32:36 -0800883 }
884
885 /** Returns call disconnect cause, defined by {@link DisconnectCause}. */
886 public DisconnectCause getDisconnectCause() {
linyuh183cb712017-12-27 17:02:37 -0800887 if (state == State.DISCONNECTED || state == State.IDLE) {
888 return disconnectCause;
Eric Erfanianccca3152017-02-22 16:32:36 -0800889 }
890
891 return new DisconnectCause(DisconnectCause.UNKNOWN);
892 }
893
894 public void setDisconnectCause(DisconnectCause disconnectCause) {
linyuh183cb712017-12-27 17:02:37 -0800895 this.disconnectCause = disconnectCause;
896 logState.disconnectCause = this.disconnectCause;
Eric Erfanianccca3152017-02-22 16:32:36 -0800897 }
898
899 /** Returns the possible text message responses. */
900 public List<String> getCannedSmsResponses() {
linyuh183cb712017-12-27 17:02:37 -0800901 return telecomCall.getCannedTextResponses();
Eric Erfanianccca3152017-02-22 16:32:36 -0800902 }
903
904 /** Checks if the call supports the given set of capabilities supplied as a bit mask. */
905 public boolean can(int capabilities) {
linyuh183cb712017-12-27 17:02:37 -0800906 int supportedCapabilities = telecomCall.getDetails().getCallCapabilities();
Eric Erfanianccca3152017-02-22 16:32:36 -0800907
908 if ((capabilities & Call.Details.CAPABILITY_MERGE_CONFERENCE) != 0) {
909 // We allow you to merge if the capabilities allow it or if it is a call with
910 // conferenceable calls.
linyuh183cb712017-12-27 17:02:37 -0800911 if (telecomCall.getConferenceableCalls().isEmpty()
Eric Erfanianccca3152017-02-22 16:32:36 -0800912 && ((Call.Details.CAPABILITY_MERGE_CONFERENCE & supportedCapabilities) == 0)) {
913 // Cannot merge calls if there are no calls to merge with.
914 return false;
915 }
916 capabilities &= ~Call.Details.CAPABILITY_MERGE_CONFERENCE;
917 }
918 return (capabilities == (capabilities & supportedCapabilities));
919 }
920
921 public boolean hasProperty(int property) {
linyuh183cb712017-12-27 17:02:37 -0800922 return telecomCall.getDetails().hasProperty(property);
Eric Erfanianccca3152017-02-22 16:32:36 -0800923 }
924
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700925 @NonNull
Eric Erfanianccca3152017-02-22 16:32:36 -0800926 public String getUniqueCallId() {
927 return uniqueCallId;
928 }
929
930 /** Gets the time when the call first became active. */
931 public long getConnectTimeMillis() {
linyuh183cb712017-12-27 17:02:37 -0800932 return telecomCall.getDetails().getConnectTimeMillis();
Eric Erfanianccca3152017-02-22 16:32:36 -0800933 }
934
935 public boolean isConferenceCall() {
936 return hasProperty(Call.Details.PROPERTY_CONFERENCE);
937 }
938
939 @Nullable
940 public GatewayInfo getGatewayInfo() {
linyuh183cb712017-12-27 17:02:37 -0800941 return telecomCall == null ? null : telecomCall.getDetails().getGatewayInfo();
Eric Erfanianccca3152017-02-22 16:32:36 -0800942 }
943
944 @Nullable
945 public PhoneAccountHandle getAccountHandle() {
linyuh183cb712017-12-27 17:02:37 -0800946 return telecomCall == null ? null : telecomCall.getDetails().getAccountHandle();
Eric Erfanianccca3152017-02-22 16:32:36 -0800947 }
948
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700949 /** @return The {@link VideoCall} instance associated with the {@link Call}. */
Eric Erfanianccca3152017-02-22 16:32:36 -0800950 public VideoCall getVideoCall() {
linyuh183cb712017-12-27 17:02:37 -0800951 return telecomCall == null ? null : telecomCall.getVideoCall();
Eric Erfanianccca3152017-02-22 16:32:36 -0800952 }
953
954 public List<String> getChildCallIds() {
linyuh183cb712017-12-27 17:02:37 -0800955 return childCallIds;
Eric Erfanianccca3152017-02-22 16:32:36 -0800956 }
957
958 public String getParentId() {
linyuh183cb712017-12-27 17:02:37 -0800959 Call parentCall = telecomCall.getParent();
Eric Erfanianccca3152017-02-22 16:32:36 -0800960 if (parentCall != null) {
linyuh183cb712017-12-27 17:02:37 -0800961 return dialerCallDelegate.getDialerCallFromTelecomCall(parentCall).getId();
Eric Erfanianccca3152017-02-22 16:32:36 -0800962 }
963 return null;
964 }
965
966 public int getVideoState() {
linyuh183cb712017-12-27 17:02:37 -0800967 return telecomCall.getDetails().getVideoState();
Eric Erfanianccca3152017-02-22 16:32:36 -0800968 }
969
970 public boolean isVideoCall() {
roldenburg2cec3802017-10-11 16:26:51 -0700971 return getVideoTech().isTransmittingOrReceiving() || VideoProfile.isVideo(getVideoState());
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700972 }
973
wangqi8d407a02018-02-15 15:32:52 -0800974 @TargetApi(28)
wangqi219b8702018-02-13 09:34:41 -0800975 public boolean isRttCall() {
976 if (BuildCompat.isAtLeastP()) {
977 return getTelecomCall().isRttActive();
978 } else {
979 return false;
980 }
981 }
982
wangqi153af2f2018-02-15 16:21:49 -0800983 @TargetApi(28)
984 public RttCall getRttCall() {
985 if (!isRttCall()) {
986 return null;
987 }
988 return getTelecomCall().getRttCall();
989 }
990
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700991 public boolean hasReceivedVideoUpgradeRequest() {
992 return VideoUtils.hasReceivedVideoUpgradeRequest(getVideoTech().getSessionModificationState());
993 }
994
995 public boolean hasSentVideoUpgradeRequest() {
996 return VideoUtils.hasSentVideoUpgradeRequest(getVideoTech().getSessionModificationState());
Eric Erfanianccca3152017-02-22 16:32:36 -0800997 }
998
wangqi219b8702018-02-13 09:34:41 -0800999 public boolean hasSentRttUpgradeRequest() {
wangqi219b8702018-02-13 09:34:41 -08001000 return false;
1001 }
1002
Eric Erfanianccca3152017-02-22 16:32:36 -08001003 /**
1004 * Determines if the call handle is an emergency number or not and caches the result to avoid
1005 * repeated calls to isEmergencyNumber.
1006 */
1007 private void updateEmergencyCallState() {
linyuh183cb712017-12-27 17:02:37 -08001008 isEmergencyCall = TelecomCallUtil.isEmergencyCall(telecomCall);
Eric Erfanianccca3152017-02-22 16:32:36 -08001009 }
1010
Eric Erfanianccca3152017-02-22 16:32:36 -08001011 public LogState getLogState() {
linyuh183cb712017-12-27 17:02:37 -08001012 return logState;
Eric Erfanianccca3152017-02-22 16:32:36 -08001013 }
1014
1015 /**
1016 * Determines if the call is an external call.
1017 *
1018 * <p>An external call is one which does not exist locally for the {@link
1019 * android.telecom.ConnectionService} it is associated with.
1020 *
1021 * <p>External calls are only supported in N and higher.
1022 *
1023 * @return {@code true} if the call is an external call, {@code false} otherwise.
1024 */
1025 public boolean isExternalCall() {
1026 return VERSION.SDK_INT >= VERSION_CODES.N
1027 && hasProperty(CallCompat.Details.PROPERTY_IS_EXTERNAL_CALL);
1028 }
1029
1030 /**
Eric Erfanianccca3152017-02-22 16:32:36 -08001031 * Determines if answering this call will cause an ongoing video call to be dropped.
1032 *
1033 * @return {@code true} if answering this call will drop an ongoing video call, {@code false}
1034 * otherwise.
1035 */
1036 public boolean answeringDisconnectsForegroundVideoCall() {
1037 Bundle extras = getExtras();
1038 if (extras == null
1039 || !extras.containsKey(CallCompat.Details.EXTRA_ANSWERING_DROPS_FOREGROUND_CALL)) {
1040 return false;
1041 }
1042 return extras.getBoolean(CallCompat.Details.EXTRA_ANSWERING_DROPS_FOREGROUND_CALL);
1043 }
1044
1045 private void parseCallSpecificAppData() {
1046 if (isExternalCall()) {
1047 return;
1048 }
1049
linyuh183cb712017-12-27 17:02:37 -08001050 logState.callSpecificAppData = CallIntentParser.getCallSpecificAppData(getIntentExtras());
1051 if (logState.callSpecificAppData == null) {
Eric Erfanian8369df02017-05-03 10:27:13 -07001052
linyuh183cb712017-12-27 17:02:37 -08001053 logState.callSpecificAppData =
Eric Erfanian8369df02017-05-03 10:27:13 -07001054 CallSpecificAppData.newBuilder()
1055 .setCallInitiationType(CallInitiationType.Type.EXTERNAL_INITIATION)
1056 .build();
Eric Erfanianccca3152017-02-22 16:32:36 -08001057 }
1058 if (getState() == State.INCOMING) {
linyuh183cb712017-12-27 17:02:37 -08001059 logState.callSpecificAppData =
1060 logState
Eric Erfanian8369df02017-05-03 10:27:13 -07001061 .callSpecificAppData
1062 .toBuilder()
1063 .setCallInitiationType(CallInitiationType.Type.INCOMING_INITIATION)
1064 .build();
Eric Erfanianccca3152017-02-22 16:32:36 -08001065 }
1066 }
1067
1068 @Override
1069 public String toString() {
linyuh183cb712017-12-27 17:02:37 -08001070 if (telecomCall == null) {
Eric Erfanianccca3152017-02-22 16:32:36 -08001071 // This should happen only in testing since otherwise we would never have a null
1072 // Telecom call.
linyuh183cb712017-12-27 17:02:37 -08001073 return String.valueOf(id);
Eric Erfanianccca3152017-02-22 16:32:36 -08001074 }
1075
1076 return String.format(
1077 Locale.US,
1078 "[%s, %s, %s, %s, children:%s, parent:%s, "
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001079 + "conferenceable:%s, videoState:%s, mSessionModificationState:%d, CameraDir:%s]",
linyuh183cb712017-12-27 17:02:37 -08001080 id,
Eric Erfanianccca3152017-02-22 16:32:36 -08001081 State.toString(getState()),
linyuh183cb712017-12-27 17:02:37 -08001082 Details.capabilitiesToString(telecomCall.getDetails().getCallCapabilities()),
1083 Details.propertiesToString(telecomCall.getDetails().getCallProperties()),
1084 childCallIds,
Eric Erfanianccca3152017-02-22 16:32:36 -08001085 getParentId(),
linyuh183cb712017-12-27 17:02:37 -08001086 this.telecomCall.getConferenceableCalls(),
1087 VideoProfile.videoStateToString(telecomCall.getDetails().getVideoState()),
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001088 getVideoTech().getSessionModificationState(),
1089 getCameraDir());
Eric Erfanianccca3152017-02-22 16:32:36 -08001090 }
1091
1092 public String toSimpleString() {
1093 return super.toString();
1094 }
1095
1096 @CallHistoryStatus
1097 public int getCallHistoryStatus() {
linyuh183cb712017-12-27 17:02:37 -08001098 return callHistoryStatus;
Eric Erfanianccca3152017-02-22 16:32:36 -08001099 }
1100
1101 public void setCallHistoryStatus(@CallHistoryStatus int callHistoryStatus) {
linyuh183cb712017-12-27 17:02:37 -08001102 this.callHistoryStatus = callHistoryStatus;
Eric Erfanianccca3152017-02-22 16:32:36 -08001103 }
1104
1105 public boolean didShowCameraPermission() {
1106 return didShowCameraPermission;
1107 }
1108
1109 public void setDidShowCameraPermission(boolean didShow) {
1110 didShowCameraPermission = didShow;
1111 }
1112
wangqida410d32018-03-06 16:51:38 -08001113 public boolean didDismissVideoChargesAlertDialog() {
1114 return didDismissVideoChargesAlertDialog;
1115 }
1116
1117 public void setDidDismissVideoChargesAlertDialog(boolean didDismiss) {
1118 didDismissVideoChargesAlertDialog = didDismiss;
1119 }
1120
Eric Erfanian938468d2017-10-24 14:05:52 -07001121 @Nullable
1122 public Boolean isInGlobalSpamList() {
Eric Erfanianccca3152017-02-22 16:32:36 -08001123 return isInGlobalSpamList;
1124 }
1125
1126 public void setIsInGlobalSpamList(boolean inSpamList) {
1127 isInGlobalSpamList = inSpamList;
1128 }
1129
Eric Erfanian938468d2017-10-24 14:05:52 -07001130 @Nullable
1131 public Boolean isInUserSpamList() {
Eric Erfanianccca3152017-02-22 16:32:36 -08001132 return isInUserSpamList;
1133 }
1134
1135 public void setIsInUserSpamList(boolean inSpamList) {
1136 isInUserSpamList = inSpamList;
1137 }
1138
Eric Erfanian938468d2017-10-24 14:05:52 -07001139 @Nullable
1140 public Boolean isInUserWhiteList() {
Eric Erfanianccca3152017-02-22 16:32:36 -08001141 return isInUserWhiteList;
1142 }
1143
1144 public void setIsInUserWhiteList(boolean inWhiteList) {
1145 isInUserWhiteList = inWhiteList;
1146 }
1147
1148 public boolean isSpam() {
linyuh183cb712017-12-27 17:02:37 -08001149 return isSpam;
Eric Erfanianccca3152017-02-22 16:32:36 -08001150 }
1151
1152 public void setSpam(boolean isSpam) {
linyuh183cb712017-12-27 17:02:37 -08001153 this.isSpam = isSpam;
Eric Erfanianccca3152017-02-22 16:32:36 -08001154 }
1155
1156 public boolean isBlocked() {
linyuh183cb712017-12-27 17:02:37 -08001157 return isBlocked;
Eric Erfanianccca3152017-02-22 16:32:36 -08001158 }
1159
1160 public void setBlockedStatus(boolean isBlocked) {
linyuh183cb712017-12-27 17:02:37 -08001161 this.isBlocked = isBlocked;
Eric Erfanianccca3152017-02-22 16:32:36 -08001162 }
1163
1164 public boolean isRemotelyHeld() {
1165 return isRemotelyHeld;
1166 }
1167
Eric Erfanian2ca43182017-08-31 06:57:16 -07001168 public boolean isMergeInProcess() {
1169 return isMergeInProcess;
1170 }
1171
Eric Erfanianccca3152017-02-22 16:32:36 -08001172 public boolean isIncoming() {
linyuh183cb712017-12-27 17:02:37 -08001173 return logState.isIncoming;
Eric Erfanianccca3152017-02-22 16:32:36 -08001174 }
1175
erfanian2cf2c342017-12-21 12:01:33 -08001176 /**
1177 * Try and determine if the call used assisted dialing.
1178 *
1179 * <p>We will not be able to verify a call underwent assisted dialing until the Platform
1180 * implmentation is complete in P+.
1181 *
1182 * @return a boolean indicating assisted dialing may have been performed
1183 */
Eric Erfanian2ca43182017-08-31 06:57:16 -07001184 public boolean isAssistedDialed() {
1185 if (getIntentExtras() != null) {
erfaniand2e5d0b2018-03-02 14:54:35 -08001186 // P and below uses the existence of USE_ASSISTED_DIALING to indicate assisted dialing
erfanian2cf2c342017-12-21 12:01:33 -08001187 // was used. The Dialer client is responsible for performing assisted dialing before
1188 // placing the outgoing call.
1189 //
1190 // The existence of the assisted dialing extras indicates that assisted dialing took place.
1191 if (getIntentExtras().getBoolean(TelephonyManagerCompat.USE_ASSISTED_DIALING, false)
1192 && getAssistedDialingExtras() != null
1193 && Build.VERSION.SDK_INT <= ConcreteCreator.BUILD_CODE_CEILING) {
1194 return true;
1195 }
1196 }
1197
Eric Erfanian2ca43182017-08-31 06:57:16 -07001198 return false;
1199 }
1200
erfanian2cf2c342017-12-21 12:01:33 -08001201 @Nullable
erfaniand0f207f2017-10-11 12:23:29 -07001202 public TransformationInfo getAssistedDialingExtras() {
erfanian2cf2c342017-12-21 12:01:33 -08001203 if (getIntentExtras() == null) {
1204 return null;
erfaniand0f207f2017-10-11 12:23:29 -07001205 }
erfanian2cf2c342017-12-21 12:01:33 -08001206
1207 if (getIntentExtras().getBundle(TelephonyManagerCompat.ASSISTED_DIALING_EXTRAS) == null) {
1208 return null;
1209 }
1210
erfanianf2556612018-01-23 09:55:59 -08001211 // Used in N-OMR1
erfanian2cf2c342017-12-21 12:01:33 -08001212 return TransformationInfo.newInstanceFromBundle(
1213 getIntentExtras().getBundle(TelephonyManagerCompat.ASSISTED_DIALING_EXTRAS));
erfaniand0f207f2017-10-11 12:23:29 -07001214 }
1215
Eric Erfanianccca3152017-02-22 16:32:36 -08001216 public LatencyReport getLatencyReport() {
linyuh183cb712017-12-27 17:02:37 -08001217 return latencyReport;
Eric Erfanianccca3152017-02-22 16:32:36 -08001218 }
1219
Eric Erfanian2ca43182017-08-31 06:57:16 -07001220 public int getAnswerAndReleaseButtonDisplayedTimes() {
1221 return answerAndReleaseButtonDisplayedTimes;
1222 }
1223
1224 public void increaseAnswerAndReleaseButtonDisplayedTimes() {
1225 answerAndReleaseButtonDisplayedTimes++;
1226 }
1227
1228 public boolean getReleasedByAnsweringSecondCall() {
1229 return releasedByAnsweringSecondCall;
1230 }
1231
1232 public void setReleasedByAnsweringSecondCall(boolean releasedByAnsweringSecondCall) {
1233 this.releasedByAnsweringSecondCall = releasedByAnsweringSecondCall;
1234 }
1235
1236 public int getSecondCallWithoutAnswerAndReleasedButtonTimes() {
1237 return secondCallWithoutAnswerAndReleasedButtonTimes;
1238 }
1239
1240 public void increaseSecondCallWithoutAnswerAndReleasedButtonTimes() {
1241 secondCallWithoutAnswerAndReleasedButtonTimes++;
1242 }
1243
Eric Erfanian8369df02017-05-03 10:27:13 -07001244 @Nullable
1245 public EnrichedCallCapabilities getEnrichedCallCapabilities() {
linyuh183cb712017-12-27 17:02:37 -08001246 return enrichedCallCapabilities;
Eric Erfanian8369df02017-05-03 10:27:13 -07001247 }
1248
1249 public void setEnrichedCallCapabilities(
1250 @Nullable EnrichedCallCapabilities mEnrichedCallCapabilities) {
linyuh183cb712017-12-27 17:02:37 -08001251 this.enrichedCallCapabilities = mEnrichedCallCapabilities;
Eric Erfanian8369df02017-05-03 10:27:13 -07001252 }
1253
1254 @Nullable
1255 public Session getEnrichedCallSession() {
linyuh183cb712017-12-27 17:02:37 -08001256 return enrichedCallSession;
Eric Erfanian8369df02017-05-03 10:27:13 -07001257 }
1258
1259 public void setEnrichedCallSession(@Nullable Session mEnrichedCallSession) {
linyuh183cb712017-12-27 17:02:37 -08001260 this.enrichedCallSession = mEnrichedCallSession;
Eric Erfanian8369df02017-05-03 10:27:13 -07001261 }
1262
Eric Erfanianccca3152017-02-22 16:32:36 -08001263 public void unregisterCallback() {
linyuh183cb712017-12-27 17:02:37 -08001264 telecomCall.unregisterCallback(telecomCallCallback);
Eric Erfanianccca3152017-02-22 16:32:36 -08001265 }
1266
Eric Erfanianccca3152017-02-22 16:32:36 -08001267 public void phoneAccountSelected(PhoneAccountHandle accountHandle, boolean setDefault) {
1268 LogUtil.i(
1269 "DialerCall.phoneAccountSelected",
1270 "accountHandle: %s, setDefault: %b",
1271 accountHandle,
1272 setDefault);
linyuh183cb712017-12-27 17:02:37 -08001273 telecomCall.phoneAccountSelected(accountHandle, setDefault);
Eric Erfanianccca3152017-02-22 16:32:36 -08001274 }
1275
1276 public void disconnect() {
1277 LogUtil.i("DialerCall.disconnect", "");
1278 setState(DialerCall.State.DISCONNECTING);
linyuh183cb712017-12-27 17:02:37 -08001279 for (DialerCallListener listener : listeners) {
Eric Erfanianccca3152017-02-22 16:32:36 -08001280 listener.onDialerCallUpdate();
1281 }
linyuh183cb712017-12-27 17:02:37 -08001282 telecomCall.disconnect();
Eric Erfanianccca3152017-02-22 16:32:36 -08001283 }
1284
1285 public void hold() {
1286 LogUtil.i("DialerCall.hold", "");
linyuh183cb712017-12-27 17:02:37 -08001287 telecomCall.hold();
Eric Erfanianccca3152017-02-22 16:32:36 -08001288 }
1289
1290 public void unhold() {
1291 LogUtil.i("DialerCall.unhold", "");
linyuh183cb712017-12-27 17:02:37 -08001292 telecomCall.unhold();
Eric Erfanianccca3152017-02-22 16:32:36 -08001293 }
1294
1295 public void splitFromConference() {
1296 LogUtil.i("DialerCall.splitFromConference", "");
linyuh183cb712017-12-27 17:02:37 -08001297 telecomCall.splitFromConference();
Eric Erfanianccca3152017-02-22 16:32:36 -08001298 }
1299
1300 public void answer(int videoState) {
1301 LogUtil.i("DialerCall.answer", "videoState: " + videoState);
linyuh183cb712017-12-27 17:02:37 -08001302 telecomCall.answer(videoState);
Eric Erfanianccca3152017-02-22 16:32:36 -08001303 }
1304
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001305 public void answer() {
linyuh183cb712017-12-27 17:02:37 -08001306 answer(telecomCall.getDetails().getVideoState());
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001307 }
1308
Eric Erfanianccca3152017-02-22 16:32:36 -08001309 public void reject(boolean rejectWithMessage, String message) {
1310 LogUtil.i("DialerCall.reject", "");
linyuh183cb712017-12-27 17:02:37 -08001311 telecomCall.reject(rejectWithMessage, message);
Eric Erfanianccca3152017-02-22 16:32:36 -08001312 }
1313
1314 /** Return the string label to represent the call provider */
1315 public String getCallProviderLabel() {
1316 if (callProviderLabel == null) {
1317 PhoneAccount account = getPhoneAccount();
1318 if (account != null && !TextUtils.isEmpty(account.getLabel())) {
wangqi9982f0d2017-10-11 17:46:07 -07001319 if (callCapableAccounts != null && callCapableAccounts.size() > 1) {
Eric Erfanianccca3152017-02-22 16:32:36 -08001320 callProviderLabel = account.getLabel().toString();
1321 }
1322 }
1323 if (callProviderLabel == null) {
1324 callProviderLabel = "";
1325 }
1326 }
1327 return callProviderLabel;
1328 }
1329
1330 private PhoneAccount getPhoneAccount() {
1331 PhoneAccountHandle accountHandle = getAccountHandle();
1332 if (accountHandle == null) {
1333 return null;
1334 }
linyuh183cb712017-12-27 17:02:37 -08001335 return context.getSystemService(TelecomManager.class).getPhoneAccount(accountHandle);
Eric Erfanianccca3152017-02-22 16:32:36 -08001336 }
1337
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001338 public VideoTech getVideoTech() {
roldenburg7bb96232017-10-09 10:32:05 -07001339 if (videoTech == null) {
roldenburg6bd612f2018-01-18 12:57:19 -08001340 videoTech = videoTechManager.getVideoTech(getAccountHandle());
roldenburg7bb96232017-10-09 10:32:05 -07001341
1342 // Only store the first video tech type found to be available during the life of the call.
1343 if (selectedAvailableVideoTechType == com.android.dialer.logging.VideoTech.Type.NONE) {
1344 // Update the video tech.
1345 selectedAvailableVideoTechType = videoTech.getVideoTechType();
1346 }
1347 }
Eric Erfanian2ca43182017-08-31 06:57:16 -07001348 return videoTech;
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001349 }
1350
Eric Erfanianccca3152017-02-22 16:32:36 -08001351 public String getCallbackNumber() {
1352 if (callbackNumber == null) {
1353 // Show the emergency callback number if either:
1354 // 1. This is an emergency call.
1355 // 2. The phone is in Emergency Callback Mode, which means we should show the callback
1356 // number.
1357 boolean showCallbackNumber = hasProperty(Details.PROPERTY_EMERGENCY_CALLBACK_MODE);
1358
1359 if (isEmergencyCall() || showCallbackNumber) {
wangqi339b4f32017-09-18 14:32:09 -07001360 callbackNumber =
linyuh183cb712017-12-27 17:02:37 -08001361 context.getSystemService(TelecomManager.class).getLine1Number(getAccountHandle());
Eric Erfanianccca3152017-02-22 16:32:36 -08001362 }
1363
Eric Erfanianccca3152017-02-22 16:32:36 -08001364 if (callbackNumber == null) {
1365 callbackNumber = "";
1366 }
1367 }
1368 return callbackNumber;
1369 }
1370
wangqi97539352017-09-25 11:15:16 -07001371 public String getSimCountryIso() {
1372 String simCountryIso =
linyuh183cb712017-12-27 17:02:37 -08001373 TelephonyManagerCompat.getTelephonyManagerForPhoneAccountHandle(context, getAccountHandle())
wangqi97539352017-09-25 11:15:16 -07001374 .getSimCountryIso();
1375 if (!TextUtils.isEmpty(simCountryIso)) {
1376 simCountryIso = simCountryIso.toUpperCase(Locale.US);
1377 }
1378 return simCountryIso;
1379 }
1380
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001381 @Override
1382 public void onVideoTechStateChanged() {
1383 update();
1384 }
1385
1386 @Override
1387 public void onSessionModificationStateChanged() {
wangqi9982f0d2017-10-11 17:46:07 -07001388 Trace.beginSection("DialerCall.onSessionModificationStateChanged");
linyuh183cb712017-12-27 17:02:37 -08001389 for (DialerCallListener listener : listeners) {
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001390 listener.onDialerCallSessionModificationStateChange();
1391 }
wangqi9982f0d2017-10-11 17:46:07 -07001392 Trace.endSection();
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001393 }
1394
1395 @Override
1396 public void onCameraDimensionsChanged(int width, int height) {
1397 InCallVideoCallCallbackNotifier.getInstance().cameraDimensionsChanged(this, width, height);
1398 }
1399
1400 @Override
1401 public void onPeerDimensionsChanged(int width, int height) {
1402 InCallVideoCallCallbackNotifier.getInstance().peerDimensionsChanged(this, width, height);
1403 }
1404
1405 @Override
1406 public void onVideoUpgradeRequestReceived() {
1407 LogUtil.enterBlock("DialerCall.onVideoUpgradeRequestReceived");
1408
linyuh183cb712017-12-27 17:02:37 -08001409 for (DialerCallListener listener : listeners) {
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001410 listener.onDialerCallUpgradeToVideo();
1411 }
1412
1413 update();
Eric Erfanian8369df02017-05-03 10:27:13 -07001414
linyuh183cb712017-12-27 17:02:37 -08001415 Logger.get(context)
Eric Erfanian8369df02017-05-03 10:27:13 -07001416 .logCallImpression(
1417 DialerImpression.Type.VIDEO_CALL_REQUEST_RECEIVED, getUniqueCallId(), getTimeAddedMs());
1418 }
1419
1420 @Override
1421 public void onUpgradedToVideo(boolean switchToSpeaker) {
1422 LogUtil.enterBlock("DialerCall.onUpgradedToVideo");
1423
1424 if (!switchToSpeaker) {
1425 return;
1426 }
1427
1428 CallAudioState audioState = AudioModeProvider.getInstance().getAudioState();
1429
1430 if (0 != (CallAudioState.ROUTE_BLUETOOTH & audioState.getSupportedRouteMask())) {
1431 LogUtil.e(
1432 "DialerCall.onUpgradedToVideo",
1433 "toggling speakerphone not allowed when bluetooth supported.");
1434 return;
1435 }
1436
1437 if (audioState.getRoute() == CallAudioState.ROUTE_SPEAKER) {
1438 return;
1439 }
1440
1441 TelecomAdapter.getInstance().setAudioRoute(CallAudioState.ROUTE_SPEAKER);
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001442 }
1443
Eric Erfanian2ca43182017-08-31 06:57:16 -07001444 @Override
1445 public void onCapabilitiesUpdated() {
1446 if (getNumber() == null) {
1447 return;
1448 }
1449 EnrichedCallCapabilities capabilities =
linyuh183cb712017-12-27 17:02:37 -08001450 EnrichedCallComponent.get(context).getEnrichedCallManager().getCapabilities(getNumber());
Eric Erfanian2ca43182017-08-31 06:57:16 -07001451 if (capabilities != null) {
1452 setEnrichedCallCapabilities(capabilities);
1453 update();
1454 }
1455 }
1456
1457 @Override
1458 public void onEnrichedCallStateChanged() {
1459 updateEnrichedCallSession();
1460 }
1461
1462 @Override
1463 public void onImpressionLoggingNeeded(DialerImpression.Type impressionType) {
linyuh183cb712017-12-27 17:02:37 -08001464 Logger.get(context).logCallImpression(impressionType, getUniqueCallId(), getTimeAddedMs());
twyendde01c52017-09-22 10:07:31 -07001465 if (impressionType == DialerImpression.Type.LIGHTBRINGER_UPGRADE_REQUESTED) {
1466 if (getLogState().contactLookupResult == Type.NOT_FOUND) {
linyuh183cb712017-12-27 17:02:37 -08001467 Logger.get(context)
twyendde01c52017-09-22 10:07:31 -07001468 .logCallImpression(
1469 DialerImpression.Type.LIGHTBRINGER_NON_CONTACT_UPGRADE_REQUESTED,
1470 getUniqueCallId(),
1471 getTimeAddedMs());
1472 }
1473 }
Eric Erfanian2ca43182017-08-31 06:57:16 -07001474 }
1475
1476 private void updateEnrichedCallSession() {
1477 if (getNumber() == null) {
1478 return;
1479 }
1480 if (getEnrichedCallSession() != null) {
1481 // State changes to existing sessions are currently handled by the UI components (which have
1482 // their own listeners). Someday instead we could remove those and just call update() here and
1483 // have the usual onDialerCallUpdate update the UI.
1484 dispatchOnEnrichedCallSessionUpdate();
1485 return;
1486 }
1487
linyuh183cb712017-12-27 17:02:37 -08001488 EnrichedCallManager manager = EnrichedCallComponent.get(context).getEnrichedCallManager();
Eric Erfanian2ca43182017-08-31 06:57:16 -07001489
1490 Filter filter =
1491 isIncoming()
1492 ? manager.createIncomingCallComposerFilter()
1493 : manager.createOutgoingCallComposerFilter();
1494
1495 Session session = manager.getSession(getUniqueCallId(), getNumber(), filter);
1496 if (session == null) {
1497 return;
1498 }
1499
1500 session.setUniqueDialerCallId(getUniqueCallId());
1501 setEnrichedCallSession(session);
1502
1503 LogUtil.i(
1504 "DialerCall.updateEnrichedCallSession",
1505 "setting session %d's dialer id to %s",
1506 session.getSessionId(),
1507 getUniqueCallId());
1508
1509 dispatchOnEnrichedCallSessionUpdate();
1510 }
1511
1512 private void dispatchOnEnrichedCallSessionUpdate() {
linyuh183cb712017-12-27 17:02:37 -08001513 for (DialerCallListener listener : listeners) {
Eric Erfanian2ca43182017-08-31 06:57:16 -07001514 listener.onEnrichedCallSessionUpdate();
1515 }
1516 }
1517
1518 void onRemovedFromCallList() {
1519 // Ensure we clean up when this call is removed.
linyuh183cb712017-12-27 17:02:37 -08001520 videoTechManager.dispatchRemovedFromCallList();
Eric Erfanian2ca43182017-08-31 06:57:16 -07001521 }
1522
wangqi4d705e52017-09-28 12:23:35 -07001523 public com.android.dialer.logging.VideoTech.Type getSelectedAvailableVideoTechType() {
1524 return selectedAvailableVideoTechType;
yueg457b3972017-09-18 15:11:47 -07001525 }
1526
Android Dialer974fc292018-02-01 16:12:25 -08001527 public void markFeedbackRequested() {
1528 feedbackRequested = true;
1529 }
1530
1531 public boolean isFeedbackRequested() {
1532 return feedbackRequested;
1533 }
1534
Eric Erfanianccca3152017-02-22 16:32:36 -08001535 /**
twyen73a74c32018-03-07 12:12:24 -08001536 * If the in call UI has shown the phone account selection dialog for the call, the {@link
1537 * PreferredAccountRecorder} to record the result from the dialog.
1538 */
1539 @Nullable
1540 public PreferredAccountRecorder getPreferredAccountRecorder() {
1541 return preferredAccountRecorder;
1542 }
1543
1544 public void setPreferredAccountRecorder(PreferredAccountRecorder preferredAccountRecorder) {
1545 this.preferredAccountRecorder = preferredAccountRecorder;
1546 }
1547
erfaniand05d8992018-03-20 19:42:26 -07001548 /** Indicates the call is eligible for SpeakEasy */
1549 public boolean isSpeakEasyEligible() {
1550 // TODO(erfanian): refactor key location
1551 return ConfigProviderBindings.get(context).getBoolean("speak_easy_enabled", false);
1552 }
1553
1554 /** Indicates the user has selected SpeakEasy */
1555 public boolean isSpeakEasyCall() {
1556 if (!isSpeakEasyEligible()) {
1557 return false;
1558 }
1559 return isSpeakEasyCall;
1560 }
1561
1562 /** Sets the user preference for SpeakEasy */
1563 public void setIsSpeakEasyCall(boolean isSpeakEasyCall) {
1564 this.isSpeakEasyCall = isSpeakEasyCall;
1565 }
1566
twyen73a74c32018-03-07 12:12:24 -08001567 /**
Eric Erfanianccca3152017-02-22 16:32:36 -08001568 * Specifies whether a number is in the call history or not. {@link #CALL_HISTORY_STATUS_UNKNOWN}
1569 * means there is no result.
1570 */
1571 @IntDef({
1572 CALL_HISTORY_STATUS_UNKNOWN,
1573 CALL_HISTORY_STATUS_PRESENT,
1574 CALL_HISTORY_STATUS_NOT_PRESENT
1575 })
1576 @Retention(RetentionPolicy.SOURCE)
1577 public @interface CallHistoryStatus {}
1578
1579 /* Defines different states of this call */
1580 public static class State {
1581
1582 public static final int INVALID = 0;
1583 public static final int NEW = 1; /* The call is new. */
1584 public static final int IDLE = 2; /* The call is idle. Nothing active */
1585 public static final int ACTIVE = 3; /* There is an active call */
1586 public static final int INCOMING = 4; /* A normal incoming phone call */
1587 public static final int CALL_WAITING = 5; /* Incoming call while another is active */
1588 public static final int DIALING = 6; /* An outgoing call during dial phase */
1589 public static final int REDIALING = 7; /* Subsequent dialing attempt after a failure */
1590 public static final int ONHOLD = 8; /* An active phone call placed on hold */
1591 public static final int DISCONNECTING = 9; /* A call is being ended. */
1592 public static final int DISCONNECTED = 10; /* State after a call disconnects */
1593 public static final int CONFERENCED = 11; /* DialerCall part of a conference call */
1594 public static final int SELECT_PHONE_ACCOUNT = 12; /* Waiting for account selection */
1595 public static final int CONNECTING = 13; /* Waiting for Telecom broadcast to finish */
1596 public static final int BLOCKED = 14; /* The number was found on the block list */
1597 public static final int PULLING = 15; /* An external call being pulled to the device */
Eric Erfanian2ca43182017-08-31 06:57:16 -07001598 public static final int CALL_PENDING = 16; /* A call is pending on a long process to finish */
Eric Erfanianccca3152017-02-22 16:32:36 -08001599
1600 public static boolean isConnectingOrConnected(int state) {
1601 switch (state) {
1602 case ACTIVE:
1603 case INCOMING:
1604 case CALL_WAITING:
1605 case CONNECTING:
1606 case DIALING:
1607 case PULLING:
1608 case REDIALING:
1609 case ONHOLD:
1610 case CONFERENCED:
1611 return true;
1612 default:
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001613 return false;
Eric Erfanianccca3152017-02-22 16:32:36 -08001614 }
Eric Erfanianccca3152017-02-22 16:32:36 -08001615 }
1616
1617 public static boolean isDialing(int state) {
1618 return state == DIALING || state == PULLING || state == REDIALING;
1619 }
1620
1621 public static String toString(int state) {
1622 switch (state) {
1623 case INVALID:
1624 return "INVALID";
1625 case NEW:
1626 return "NEW";
1627 case IDLE:
1628 return "IDLE";
1629 case ACTIVE:
1630 return "ACTIVE";
1631 case INCOMING:
1632 return "INCOMING";
1633 case CALL_WAITING:
1634 return "CALL_WAITING";
1635 case DIALING:
1636 return "DIALING";
1637 case PULLING:
1638 return "PULLING";
1639 case REDIALING:
1640 return "REDIALING";
1641 case ONHOLD:
1642 return "ONHOLD";
1643 case DISCONNECTING:
1644 return "DISCONNECTING";
1645 case DISCONNECTED:
1646 return "DISCONNECTED";
1647 case CONFERENCED:
1648 return "CONFERENCED";
1649 case SELECT_PHONE_ACCOUNT:
1650 return "SELECT_PHONE_ACCOUNT";
1651 case CONNECTING:
1652 return "CONNECTING";
1653 case BLOCKED:
1654 return "BLOCKED";
1655 default:
1656 return "UNKNOWN";
1657 }
1658 }
1659 }
1660
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001661 /** Camera direction constants */
1662 public static class CameraDirection {
Eric Erfanianccca3152017-02-22 16:32:36 -08001663 public static final int CAMERA_DIRECTION_UNKNOWN = -1;
1664 public static final int CAMERA_DIRECTION_FRONT_FACING = CameraCharacteristics.LENS_FACING_FRONT;
1665 public static final int CAMERA_DIRECTION_BACK_FACING = CameraCharacteristics.LENS_FACING_BACK;
Eric Erfanianccca3152017-02-22 16:32:36 -08001666 }
1667
1668 /**
1669 * Tracks any state variables that is useful for logging. There is some amount of overlap with
1670 * existing call member variables, but this duplication helps to ensure that none of these logging
1671 * variables will interface with/and affect call logic.
1672 */
1673 public static class LogState {
1674
1675 public DisconnectCause disconnectCause;
1676 public boolean isIncoming = false;
Eric Erfanian8369df02017-05-03 10:27:13 -07001677 public ContactLookupResult.Type contactLookupResult =
1678 ContactLookupResult.Type.UNKNOWN_LOOKUP_RESULT_TYPE;
Eric Erfanianccca3152017-02-22 16:32:36 -08001679 public CallSpecificAppData callSpecificAppData;
1680 // If this was a conference call, the total number of calls involved in the conference.
1681 public int conferencedCalls = 0;
1682 public long duration = 0;
1683 public boolean isLogged = false;
1684
Eric Erfanian8369df02017-05-03 10:27:13 -07001685 private static String lookupToString(ContactLookupResult.Type lookupType) {
Eric Erfanianccca3152017-02-22 16:32:36 -08001686 switch (lookupType) {
Eric Erfanian8369df02017-05-03 10:27:13 -07001687 case LOCAL_CONTACT:
Eric Erfanianccca3152017-02-22 16:32:36 -08001688 return "Local";
Eric Erfanian8369df02017-05-03 10:27:13 -07001689 case LOCAL_CACHE:
Eric Erfanianccca3152017-02-22 16:32:36 -08001690 return "Cache";
Eric Erfanian8369df02017-05-03 10:27:13 -07001691 case REMOTE:
Eric Erfanianccca3152017-02-22 16:32:36 -08001692 return "Remote";
Eric Erfanian8369df02017-05-03 10:27:13 -07001693 case EMERGENCY:
Eric Erfanianccca3152017-02-22 16:32:36 -08001694 return "Emergency";
Eric Erfanian8369df02017-05-03 10:27:13 -07001695 case VOICEMAIL:
Eric Erfanianccca3152017-02-22 16:32:36 -08001696 return "Voicemail";
1697 default:
1698 return "Not found";
1699 }
1700 }
1701
1702 private static String initiationToString(CallSpecificAppData callSpecificAppData) {
1703 if (callSpecificAppData == null) {
1704 return "null";
1705 }
Eric Erfanian8369df02017-05-03 10:27:13 -07001706 switch (callSpecificAppData.getCallInitiationType()) {
1707 case INCOMING_INITIATION:
Eric Erfanianccca3152017-02-22 16:32:36 -08001708 return "Incoming";
Eric Erfanian8369df02017-05-03 10:27:13 -07001709 case DIALPAD:
Eric Erfanianccca3152017-02-22 16:32:36 -08001710 return "Dialpad";
Eric Erfanian8369df02017-05-03 10:27:13 -07001711 case SPEED_DIAL:
Eric Erfanianccca3152017-02-22 16:32:36 -08001712 return "Speed Dial";
Eric Erfanian8369df02017-05-03 10:27:13 -07001713 case REMOTE_DIRECTORY:
Eric Erfanianccca3152017-02-22 16:32:36 -08001714 return "Remote Directory";
Eric Erfanian8369df02017-05-03 10:27:13 -07001715 case SMART_DIAL:
Eric Erfanianccca3152017-02-22 16:32:36 -08001716 return "Smart Dial";
Eric Erfanian8369df02017-05-03 10:27:13 -07001717 case REGULAR_SEARCH:
Eric Erfanianccca3152017-02-22 16:32:36 -08001718 return "Regular Search";
Eric Erfanian8369df02017-05-03 10:27:13 -07001719 case CALL_LOG:
Eric Erfanianccca3152017-02-22 16:32:36 -08001720 return "DialerCall Log";
Eric Erfanian8369df02017-05-03 10:27:13 -07001721 case CALL_LOG_FILTER:
Eric Erfanianccca3152017-02-22 16:32:36 -08001722 return "DialerCall Log Filter";
Eric Erfanian8369df02017-05-03 10:27:13 -07001723 case VOICEMAIL_LOG:
Eric Erfanianccca3152017-02-22 16:32:36 -08001724 return "Voicemail Log";
Eric Erfanian8369df02017-05-03 10:27:13 -07001725 case CALL_DETAILS:
Eric Erfanianccca3152017-02-22 16:32:36 -08001726 return "DialerCall Details";
Eric Erfanian8369df02017-05-03 10:27:13 -07001727 case QUICK_CONTACTS:
Eric Erfanianccca3152017-02-22 16:32:36 -08001728 return "Quick Contacts";
Eric Erfanian8369df02017-05-03 10:27:13 -07001729 case EXTERNAL_INITIATION:
Eric Erfanianccca3152017-02-22 16:32:36 -08001730 return "External";
Eric Erfanian8369df02017-05-03 10:27:13 -07001731 case LAUNCHER_SHORTCUT:
Eric Erfanianccca3152017-02-22 16:32:36 -08001732 return "Launcher Shortcut";
1733 default:
Eric Erfanian8369df02017-05-03 10:27:13 -07001734 return "Unknown: " + callSpecificAppData.getCallInitiationType();
Eric Erfanianccca3152017-02-22 16:32:36 -08001735 }
1736 }
1737
1738 @Override
1739 public String toString() {
1740 return String.format(
1741 Locale.US,
1742 "["
1743 + "%s, " // DisconnectCause toString already describes the object type
1744 + "isIncoming: %s, "
1745 + "contactLookup: %s, "
1746 + "callInitiation: %s, "
1747 + "duration: %s"
1748 + "]",
1749 disconnectCause,
1750 isIncoming,
1751 lookupToString(contactLookupResult),
1752 initiationToString(callSpecificAppData),
1753 duration);
1754 }
1755 }
1756
roldenburgd7490db2018-01-09 13:51:29 -08001757 /** Coordinates the available VideoTech implementations for a call. */
1758 @VisibleForTesting
1759 public static class VideoTechManager {
Eric Erfaniand8046e52017-04-06 09:41:50 -07001760 private final Context context;
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001761 private final EmptyVideoTech emptyVideoTech = new EmptyVideoTech();
roldenburgd7490db2018-01-09 13:51:29 -08001762 private final VideoTech rcsVideoShare;
Eric Erfanian90508232017-03-24 09:31:16 -07001763 private final List<VideoTech> videoTechs;
roldenburg7bb96232017-10-09 10:32:05 -07001764 private VideoTech savedTech;
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001765
roldenburgd7490db2018-01-09 13:51:29 -08001766 @VisibleForTesting
1767 public VideoTechManager(DialerCall call) {
linyuh183cb712017-12-27 17:02:37 -08001768 this.context = call.context;
Eric Erfaniand8046e52017-04-06 09:41:50 -07001769
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001770 String phoneNumber = call.getNumber();
Eric Erfaniand8046e52017-04-06 09:41:50 -07001771 phoneNumber = phoneNumber != null ? phoneNumber : "";
Eric Erfanian2ca43182017-08-31 06:57:16 -07001772 phoneNumber = phoneNumber.replaceAll("[^+0-9]", "");
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001773
1774 // Insert order here determines the priority of that video tech option
Eric Erfanian8369df02017-05-03 10:27:13 -07001775 videoTechs = new ArrayList<>();
yueg457b3972017-09-18 15:11:47 -07001776
linyuh183cb712017-12-27 17:02:37 -08001777 videoTechs.add(new ImsVideoTech(Logger.get(call.context), call, call.telecomCall));
Eric Erfanian90508232017-03-24 09:31:16 -07001778
roldenburgd7490db2018-01-09 13:51:29 -08001779 rcsVideoShare =
linyuh183cb712017-12-27 17:02:37 -08001780 EnrichedCallComponent.get(call.context)
Eric Erfanian90508232017-03-24 09:31:16 -07001781 .getRcsVideoShareFactory()
1782 .newRcsVideoShare(
linyuh183cb712017-12-27 17:02:37 -08001783 EnrichedCallComponent.get(call.context).getEnrichedCallManager(),
Eric Erfanian90508232017-03-24 09:31:16 -07001784 call,
Eric Erfaniand8046e52017-04-06 09:41:50 -07001785 phoneNumber);
roldenburg3eca69f2018-01-16 12:07:04 -08001786 videoTechs.add(rcsVideoShare);
Eric Erfaniand8046e52017-04-06 09:41:50 -07001787
1788 videoTechs.add(
roldenburg4f026392017-10-13 18:42:20 -07001789 new DuoVideoTech(
linyuh183cb712017-12-27 17:02:37 -08001790 DuoComponent.get(call.context).getDuo(), call, call.telecomCall, phoneNumber));
roldenburgd7490db2018-01-09 13:51:29 -08001791
1792 savedTech = emptyVideoTech;
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001793 }
1794
roldenburgd7490db2018-01-09 13:51:29 -08001795 @VisibleForTesting
roldenburg6bd612f2018-01-18 12:57:19 -08001796 public VideoTech getVideoTech(PhoneAccountHandle phoneAccountHandle) {
roldenburgd7490db2018-01-09 13:51:29 -08001797 if (savedTech == emptyVideoTech) {
1798 for (VideoTech tech : videoTechs) {
roldenburg6bd612f2018-01-18 12:57:19 -08001799 if (tech.isAvailable(context, phoneAccountHandle)) {
roldenburgd7490db2018-01-09 13:51:29 -08001800 savedTech = tech;
1801 savedTech.becomePrimary();
1802 break;
1803 }
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001804 }
roldenburg6bd612f2018-01-18 12:57:19 -08001805 } else if (savedTech instanceof DuoVideoTech
1806 && rcsVideoShare.isAvailable(context, phoneAccountHandle)) {
roldenburgd7490db2018-01-09 13:51:29 -08001807 // RCS Video Share will become available after the capability exchange which is slower than
1808 // Duo reading local contacts for reachability. If Video Share becomes available and we are
1809 // not in the middle of any session changes, let it take over.
1810 savedTech = rcsVideoShare;
1811 rcsVideoShare.becomePrimary();
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001812 }
1813
roldenburgd7490db2018-01-09 13:51:29 -08001814 return savedTech;
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001815 }
1816
roldenburgd7490db2018-01-09 13:51:29 -08001817 @VisibleForTesting
roldenburg6bd612f2018-01-18 12:57:19 -08001818 public void dispatchCallStateChanged(int newState, PhoneAccountHandle phoneAccountHandle) {
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001819 for (VideoTech videoTech : videoTechs) {
roldenburg6bd612f2018-01-18 12:57:19 -08001820 videoTech.onCallStateChanged(context, newState, phoneAccountHandle);
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001821 }
1822 }
Eric Erfanian2ca43182017-08-31 06:57:16 -07001823
1824 void dispatchRemovedFromCallList() {
1825 for (VideoTech videoTech : videoTechs) {
1826 videoTech.onRemovedFromCallList();
1827 }
1828 }
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001829 }
1830
Eric Erfanianccca3152017-02-22 16:32:36 -08001831 /** Called when canned text responses have been loaded. */
1832 public interface CannedTextResponsesLoadedListener {
1833 void onCannedTextResponsesLoaded(DialerCall call);
1834 }
1835}