blob: 30d2bcb5e2930f2af0c596a5be4fa5df11c215cd [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;
twyena4745bd2017-12-12 18:40:11 -080074import com.android.dialer.telecom.TelecomCallUtil;
wangqi9982f0d2017-10-11 17:46:07 -070075import com.android.dialer.telecom.TelecomUtil;
Eric Erfanianc857f902017-05-15 14:05:33 -070076import com.android.dialer.theme.R;
wangqi9982f0d2017-10-11 17:46:07 -070077import com.android.dialer.util.PermissionsUtil;
Eric Erfanian8369df02017-05-03 10:27:13 -070078import com.android.incallui.audiomode.AudioModeProvider;
Eric Erfanianccca3152017-02-22 16:32:36 -080079import com.android.incallui.latencyreport.LatencyReport;
Eric Erfaniand5e47f62017-03-15 14:41:07 -070080import com.android.incallui.videotech.VideoTech;
81import com.android.incallui.videotech.VideoTech.VideoTechListener;
roldenburg4f026392017-10-13 18:42:20 -070082import com.android.incallui.videotech.duo.DuoVideoTech;
Eric Erfaniand5e47f62017-03-15 14:41:07 -070083import com.android.incallui.videotech.empty.EmptyVideoTech;
84import com.android.incallui.videotech.ims.ImsVideoTech;
Eric Erfanian90508232017-03-24 09:31:16 -070085import com.android.incallui.videotech.utils.VideoUtils;
Eric Erfanianccca3152017-02-22 16:32:36 -080086import java.lang.annotation.Retention;
87import java.lang.annotation.RetentionPolicy;
88import java.util.ArrayList;
89import java.util.List;
90import java.util.Locale;
91import java.util.Objects;
92import java.util.UUID;
93import java.util.concurrent.CopyOnWriteArrayList;
94import java.util.concurrent.TimeUnit;
95
96/** Describes a single call and its state. */
Eric Erfanian2ca43182017-08-31 06:57:16 -070097public class DialerCall implements VideoTechListener, StateChangedListener, CapabilitiesListener {
Eric Erfanianccca3152017-02-22 16:32:36 -080098
99 public static final int CALL_HISTORY_STATUS_UNKNOWN = 0;
100 public static final int CALL_HISTORY_STATUS_PRESENT = 1;
101 public static final int CALL_HISTORY_STATUS_NOT_PRESENT = 2;
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700102
103 // Hard coded property for {@code Call}. Upstreamed change from Motorola.
Eric Erfanian938468d2017-10-24 14:05:52 -0700104 // TODO(a bug): Move it to Telecom in framework.
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700105 public static final int PROPERTY_CODEC_KNOWN = 0x04000000;
106
Eric Erfanianccca3152017-02-22 16:32:36 -0800107 private static final String ID_PREFIX = "DialerCall_";
108 private static final String CONFIG_EMERGENCY_CALLBACK_WINDOW_MILLIS =
109 "emergency_callback_window_millis";
linyuh183cb712017-12-27 17:02:37 -0800110 private static int idCounter = 0;
Eric Erfanianccca3152017-02-22 16:32:36 -0800111
112 /**
Eric Erfanianc857f902017-05-15 14:05:33 -0700113 * A counter used to append to restricted/private/hidden calls so that users can identify them in
114 * a conversation. This value is reset in {@link CallList#onCallRemoved(Context, Call)} when there
115 * are no live calls.
116 */
linyuh183cb712017-12-27 17:02:37 -0800117 private static int hiddenCounter;
Eric Erfanianc857f902017-05-15 14:05:33 -0700118
119 /**
Eric Erfanianccca3152017-02-22 16:32:36 -0800120 * The unique call ID for every call. This will help us to identify each call and allow us the
121 * ability to stitch impressions to calls if needed.
122 */
123 private final String uniqueCallId = UUID.randomUUID().toString();
124
linyuh183cb712017-12-27 17:02:37 -0800125 private final Call telecomCall;
126 private final LatencyReport latencyReport;
127 private final String id;
128 private final int hiddenId;
129 private final List<String> childCallIds = new ArrayList<>();
130 private final LogState logState = new LogState();
131 private final Context context;
132 private final DialerCallDelegate dialerCallDelegate;
133 private final List<DialerCallListener> listeners = new CopyOnWriteArrayList<>();
134 private final List<CannedTextResponsesLoadedListener> cannedTextResponsesLoadedListeners =
Eric Erfanianccca3152017-02-22 16:32:36 -0800135 new CopyOnWriteArrayList<>();
linyuh183cb712017-12-27 17:02:37 -0800136 private final VideoTechManager videoTechManager;
Eric Erfanianccca3152017-02-22 16:32:36 -0800137
linyuh183cb712017-12-27 17:02:37 -0800138 private boolean isEmergencyCall;
139 private Uri handle;
140 private int state = State.INVALID;
141 private DisconnectCause disconnectCause;
Eric Erfanianccca3152017-02-22 16:32:36 -0800142
143 private boolean hasShownWiFiToLteHandoverToast;
144 private boolean doNotShowDialogForHandoffToWifiFailure;
145
linyuh183cb712017-12-27 17:02:37 -0800146 private String childNumber;
147 private String lastForwardedNumber;
wangqif4ba3452018-01-09 11:26:29 -0800148 private boolean isCallForwarded;
linyuh183cb712017-12-27 17:02:37 -0800149 private String callSubject;
150 private PhoneAccountHandle phoneAccountHandle;
151 @CallHistoryStatus private int callHistoryStatus = CALL_HISTORY_STATUS_UNKNOWN;
152 private boolean isSpam;
153 private boolean isBlocked;
Eric Erfanian938468d2017-10-24 14:05:52 -0700154
155 @Nullable private Boolean isInUserSpamList;
156
157 @Nullable private Boolean isInUserWhiteList;
158
159 @Nullable private Boolean isInGlobalSpamList;
Eric Erfanianccca3152017-02-22 16:32:36 -0800160 private boolean didShowCameraPermission;
wangqida410d32018-03-06 16:51:38 -0800161 private boolean didDismissVideoChargesAlertDialog;
162 private PersistableBundle carrierConfig;
Eric Erfanianccca3152017-02-22 16:32:36 -0800163 private String callProviderLabel;
164 private String callbackNumber;
linyuh183cb712017-12-27 17:02:37 -0800165 private int cameraDirection = CameraDirection.CAMERA_DIRECTION_UNKNOWN;
166 private EnrichedCallCapabilities enrichedCallCapabilities;
167 private Session enrichedCallSession;
Eric Erfanianccca3152017-02-22 16:32:36 -0800168
Eric Erfanian2ca43182017-08-31 06:57:16 -0700169 private int answerAndReleaseButtonDisplayedTimes = 0;
170 private boolean releasedByAnsweringSecondCall = false;
171 // Times when a second call is received but AnswerAndRelease button is not shown
172 // since it's not supported.
173 private int secondCallWithoutAnswerAndReleasedButtonTimes = 0;
roldenburg7bb96232017-10-09 10:32:05 -0700174 private VideoTech videoTech;
Eric Erfanian2ca43182017-08-31 06:57:16 -0700175
wangqi4d705e52017-09-28 12:23:35 -0700176 private com.android.dialer.logging.VideoTech.Type selectedAvailableVideoTechType =
177 com.android.dialer.logging.VideoTech.Type.NONE;
wangqi9982f0d2017-10-11 17:46:07 -0700178 private boolean isVoicemailNumber;
179 private List<PhoneAccountHandle> callCapableAccounts;
180 private String countryIso;
yueg457b3972017-09-18 15:11:47 -0700181
Android Dialer974fc292018-02-01 16:12:25 -0800182 private volatile boolean feedbackRequested = false;
183
Eric Erfanianccca3152017-02-22 16:32:36 -0800184 public static String getNumberFromHandle(Uri handle) {
185 return handle == null ? "" : handle.getSchemeSpecificPart();
186 }
187
188 /**
189 * Whether the call is put on hold by remote party. This is different than the {@link
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700190 * State#ONHOLD} state which indicates that the call is being held locally on the device.
Eric Erfanianccca3152017-02-22 16:32:36 -0800191 */
192 private boolean isRemotelyHeld;
193
Eric Erfanian2ca43182017-08-31 06:57:16 -0700194 /** Indicates whether this call is currently in the process of being merged into a conference. */
195 private boolean isMergeInProcess;
196
Eric Erfanianccca3152017-02-22 16:32:36 -0800197 /**
198 * Indicates whether the phone account associated with this call supports specifying a call
199 * subject.
200 */
linyuh183cb712017-12-27 17:02:37 -0800201 private boolean isCallSubjectSupported;
Eric Erfanianccca3152017-02-22 16:32:36 -0800202
linyuh183cb712017-12-27 17:02:37 -0800203 private final Call.Callback telecomCallCallback =
Eric Erfanianccca3152017-02-22 16:32:36 -0800204 new Call.Callback() {
205 @Override
206 public void onStateChanged(Call call, int newState) {
207 LogUtil.v("TelecomCallCallback.onStateChanged", "call=" + call + " newState=" + newState);
208 update();
209 }
210
211 @Override
212 public void onParentChanged(Call call, Call newParent) {
213 LogUtil.v(
214 "TelecomCallCallback.onParentChanged", "call=" + call + " newParent=" + newParent);
215 update();
216 }
217
218 @Override
219 public void onChildrenChanged(Call call, List<Call> children) {
220 update();
221 }
222
223 @Override
224 public void onDetailsChanged(Call call, Call.Details details) {
Eric Erfanian2ca43182017-08-31 06:57:16 -0700225 LogUtil.v(
226 "TelecomCallCallback.onDetailsChanged", " call=" + call + " details=" + details);
Eric Erfanianccca3152017-02-22 16:32:36 -0800227 update();
228 }
229
230 @Override
231 public void onCannedTextResponsesLoaded(Call call, List<String> cannedTextResponses) {
232 LogUtil.v(
Eric Erfanian2ca43182017-08-31 06:57:16 -0700233 "TelecomCallCallback.onCannedTextResponsesLoaded",
Eric Erfanianccca3152017-02-22 16:32:36 -0800234 "call=" + call + " cannedTextResponses=" + cannedTextResponses);
linyuh183cb712017-12-27 17:02:37 -0800235 for (CannedTextResponsesLoadedListener listener : cannedTextResponsesLoadedListeners) {
Eric Erfanianccca3152017-02-22 16:32:36 -0800236 listener.onCannedTextResponsesLoaded(DialerCall.this);
237 }
238 }
239
240 @Override
241 public void onPostDialWait(Call call, String remainingPostDialSequence) {
242 LogUtil.v(
Eric Erfanian2ca43182017-08-31 06:57:16 -0700243 "TelecomCallCallback.onPostDialWait",
Eric Erfanianccca3152017-02-22 16:32:36 -0800244 "call=" + call + " remainingPostDialSequence=" + remainingPostDialSequence);
245 update();
246 }
247
248 @Override
249 public void onVideoCallChanged(Call call, VideoCall videoCall) {
250 LogUtil.v(
Eric Erfanian2ca43182017-08-31 06:57:16 -0700251 "TelecomCallCallback.onVideoCallChanged", "call=" + call + " videoCall=" + videoCall);
Eric Erfanianccca3152017-02-22 16:32:36 -0800252 update();
253 }
254
255 @Override
256 public void onCallDestroyed(Call call) {
Eric Erfanian2ca43182017-08-31 06:57:16 -0700257 LogUtil.v("TelecomCallCallback.onCallDestroyed", "call=" + call);
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700258 unregisterCallback();
Eric Erfanianccca3152017-02-22 16:32:36 -0800259 }
260
261 @Override
262 public void onConferenceableCallsChanged(Call call, List<Call> conferenceableCalls) {
263 LogUtil.v(
Eric Erfanian2ca43182017-08-31 06:57:16 -0700264 "TelecomCallCallback.onConferenceableCallsChanged",
Eric Erfanianccca3152017-02-22 16:32:36 -0800265 "call %s, conferenceable calls: %d",
266 call,
267 conferenceableCalls.size());
268 update();
269 }
270
271 @Override
wangqi219b8702018-02-13 09:34:41 -0800272 public void onRttModeChanged(Call call, int mode) {
273 LogUtil.v("TelecomCallCallback.onRttModeChanged", "mode=%d", mode);
274 }
275
276 @Override
277 public void onRttRequest(Call call, int id) {
278 LogUtil.v("TelecomCallCallback.onRttRequest", "id=%d", id);
279 }
280
281 @Override
282 public void onRttInitiationFailure(Call call, int reason) {
283 LogUtil.v("TelecomCallCallback.onRttInitiationFailure", "reason=%d", reason);
284 update();
285 }
286
287 @Override
288 public void onRttStatusChanged(Call call, boolean enabled, RttCall rttCall) {
289 LogUtil.v("TelecomCallCallback.onRttStatusChanged", "enabled=%b", enabled);
290 update();
291 }
292
293 @Override
Eric Erfanianccca3152017-02-22 16:32:36 -0800294 public void onConnectionEvent(android.telecom.Call call, String event, Bundle extras) {
295 LogUtil.v(
Eric Erfanian2ca43182017-08-31 06:57:16 -0700296 "TelecomCallCallback.onConnectionEvent",
Eric Erfanianccca3152017-02-22 16:32:36 -0800297 "Call: " + call + ", Event: " + event + ", Extras: " + extras);
298 switch (event) {
299 // The Previous attempt to Merge two calls together has failed in Telecom. We must
300 // now update the UI to possibly re-enable the Merge button based on the number of
301 // currently conferenceable calls available or Connection Capabilities.
302 case android.telecom.Connection.EVENT_CALL_MERGE_FAILED:
303 update();
304 break;
305 case TelephonyManagerCompat.EVENT_HANDOVER_VIDEO_FROM_WIFI_TO_LTE:
306 notifyWiFiToLteHandover();
307 break;
308 case TelephonyManagerCompat.EVENT_HANDOVER_TO_WIFI_FAILED:
309 notifyHandoverToWifiFailed();
310 break;
311 case TelephonyManagerCompat.EVENT_CALL_REMOTELY_HELD:
312 isRemotelyHeld = true;
313 update();
314 break;
315 case TelephonyManagerCompat.EVENT_CALL_REMOTELY_UNHELD:
316 isRemotelyHeld = false;
317 update();
318 break;
Eric Erfanianc857f902017-05-15 14:05:33 -0700319 case TelephonyManagerCompat.EVENT_NOTIFY_INTERNATIONAL_CALL_ON_WFC:
320 notifyInternationalCallOnWifi();
321 break;
Eric Erfanian2ca43182017-08-31 06:57:16 -0700322 case TelephonyManagerCompat.EVENT_MERGE_START:
323 LogUtil.i("DialerCall.onConnectionEvent", "merge start");
324 isMergeInProcess = true;
325 break;
326 case TelephonyManagerCompat.EVENT_MERGE_COMPLETE:
327 LogUtil.i("DialerCall.onConnectionEvent", "merge complete");
328 isMergeInProcess = false;
329 break;
wangqif4ba3452018-01-09 11:26:29 -0800330 case TelephonyManagerCompat.EVENT_CALL_FORWARDED:
331 // Only handle this event for P+ since it's unreliable pre-P.
332 if (BuildCompat.isAtLeastP()) {
333 isCallForwarded = true;
334 update();
335 }
336 break;
Eric Erfanianccca3152017-02-22 16:32:36 -0800337 default:
338 break;
339 }
340 }
341 };
Eric Erfanianc857f902017-05-15 14:05:33 -0700342
linyuh183cb712017-12-27 17:02:37 -0800343 private long timeAddedMs;
Eric Erfanianccca3152017-02-22 16:32:36 -0800344
345 public DialerCall(
346 Context context,
347 DialerCallDelegate dialerCallDelegate,
348 Call telecomCall,
349 LatencyReport latencyReport,
350 boolean registerCallback) {
351 Assert.isNotNull(context);
linyuh183cb712017-12-27 17:02:37 -0800352 this.context = context;
353 this.dialerCallDelegate = dialerCallDelegate;
354 this.telecomCall = telecomCall;
355 this.latencyReport = latencyReport;
356 id = ID_PREFIX + Integer.toString(idCounter++);
Eric Erfanianccca3152017-02-22 16:32:36 -0800357
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700358 // Must be after assigning mTelecomCall
linyuh183cb712017-12-27 17:02:37 -0800359 videoTechManager = new VideoTechManager(this);
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700360
361 updateFromTelecomCall();
Eric Erfanianc857f902017-05-15 14:05:33 -0700362 if (isHiddenNumber() && TextUtils.isEmpty(getNumber())) {
linyuh183cb712017-12-27 17:02:37 -0800363 hiddenId = ++hiddenCounter;
Eric Erfanianc857f902017-05-15 14:05:33 -0700364 } else {
linyuh183cb712017-12-27 17:02:37 -0800365 hiddenId = 0;
Eric Erfanianc857f902017-05-15 14:05:33 -0700366 }
Eric Erfanianccca3152017-02-22 16:32:36 -0800367
368 if (registerCallback) {
linyuh183cb712017-12-27 17:02:37 -0800369 this.telecomCall.registerCallback(telecomCallCallback);
Eric Erfanianccca3152017-02-22 16:32:36 -0800370 }
371
linyuh183cb712017-12-27 17:02:37 -0800372 timeAddedMs = System.currentTimeMillis();
Eric Erfanianccca3152017-02-22 16:32:36 -0800373 parseCallSpecificAppData();
Eric Erfanian2ca43182017-08-31 06:57:16 -0700374
375 updateEnrichedCallSession();
Eric Erfanianccca3152017-02-22 16:32:36 -0800376 }
377
twyendde01c52017-09-22 10:07:31 -0700378 /** Test only constructor to avoid initializing dependencies. */
379 @VisibleForTesting
380 DialerCall(Context context) {
linyuh183cb712017-12-27 17:02:37 -0800381 this.context = context;
382 telecomCall = null;
383 latencyReport = null;
384 id = null;
385 hiddenId = 0;
386 dialerCallDelegate = null;
387 videoTechManager = null;
twyendde01c52017-09-22 10:07:31 -0700388 }
389
Eric Erfanianccca3152017-02-22 16:32:36 -0800390 private static int translateState(int state) {
391 switch (state) {
392 case Call.STATE_NEW:
393 case Call.STATE_CONNECTING:
394 return DialerCall.State.CONNECTING;
395 case Call.STATE_SELECT_PHONE_ACCOUNT:
396 return DialerCall.State.SELECT_PHONE_ACCOUNT;
397 case Call.STATE_DIALING:
398 return DialerCall.State.DIALING;
399 case Call.STATE_PULLING_CALL:
400 return DialerCall.State.PULLING;
401 case Call.STATE_RINGING:
402 return DialerCall.State.INCOMING;
403 case Call.STATE_ACTIVE:
404 return DialerCall.State.ACTIVE;
405 case Call.STATE_HOLDING:
406 return DialerCall.State.ONHOLD;
407 case Call.STATE_DISCONNECTED:
408 return DialerCall.State.DISCONNECTED;
409 case Call.STATE_DISCONNECTING:
410 return DialerCall.State.DISCONNECTING;
411 default:
412 return DialerCall.State.INVALID;
413 }
414 }
415
416 public static boolean areSame(DialerCall call1, DialerCall call2) {
417 if (call1 == null && call2 == null) {
418 return true;
419 } else if (call1 == null || call2 == null) {
420 return false;
421 }
422
423 // otherwise compare call Ids
424 return call1.getId().equals(call2.getId());
425 }
426
Eric Erfanianccca3152017-02-22 16:32:36 -0800427 public void addListener(DialerCallListener listener) {
428 Assert.isMainThread();
linyuh183cb712017-12-27 17:02:37 -0800429 listeners.add(listener);
Eric Erfanianccca3152017-02-22 16:32:36 -0800430 }
431
432 public void removeListener(DialerCallListener listener) {
433 Assert.isMainThread();
linyuh183cb712017-12-27 17:02:37 -0800434 listeners.remove(listener);
Eric Erfanianccca3152017-02-22 16:32:36 -0800435 }
436
437 public void addCannedTextResponsesLoadedListener(CannedTextResponsesLoadedListener listener) {
438 Assert.isMainThread();
linyuh183cb712017-12-27 17:02:37 -0800439 cannedTextResponsesLoadedListeners.add(listener);
Eric Erfanianccca3152017-02-22 16:32:36 -0800440 }
441
442 public void removeCannedTextResponsesLoadedListener(CannedTextResponsesLoadedListener listener) {
443 Assert.isMainThread();
linyuh183cb712017-12-27 17:02:37 -0800444 cannedTextResponsesLoadedListeners.remove(listener);
Eric Erfanianccca3152017-02-22 16:32:36 -0800445 }
446
447 public void notifyWiFiToLteHandover() {
448 LogUtil.i("DialerCall.notifyWiFiToLteHandover", "");
linyuh183cb712017-12-27 17:02:37 -0800449 for (DialerCallListener listener : listeners) {
Eric Erfanianccca3152017-02-22 16:32:36 -0800450 listener.onWiFiToLteHandover();
451 }
452 }
453
454 public void notifyHandoverToWifiFailed() {
455 LogUtil.i("DialerCall.notifyHandoverToWifiFailed", "");
linyuh183cb712017-12-27 17:02:37 -0800456 for (DialerCallListener listener : listeners) {
Eric Erfanianccca3152017-02-22 16:32:36 -0800457 listener.onHandoverToWifiFailure();
458 }
459 }
460
Eric Erfanianc857f902017-05-15 14:05:33 -0700461 public void notifyInternationalCallOnWifi() {
462 LogUtil.enterBlock("DialerCall.notifyInternationalCallOnWifi");
linyuh183cb712017-12-27 17:02:37 -0800463 for (DialerCallListener dialerCallListener : listeners) {
Eric Erfanianc857f902017-05-15 14:05:33 -0700464 dialerCallListener.onInternationalCallOnWifi();
465 }
466 }
467
Eric Erfanianccca3152017-02-22 16:32:36 -0800468 /* package-private */ Call getTelecomCall() {
linyuh183cb712017-12-27 17:02:37 -0800469 return telecomCall;
Eric Erfanianccca3152017-02-22 16:32:36 -0800470 }
wangqida410d32018-03-06 16:51:38 -0800471
Eric Erfanianccca3152017-02-22 16:32:36 -0800472 public StatusHints getStatusHints() {
linyuh183cb712017-12-27 17:02:37 -0800473 return telecomCall.getDetails().getStatusHints();
Eric Erfanianccca3152017-02-22 16:32:36 -0800474 }
475
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700476 public int getCameraDir() {
linyuh183cb712017-12-27 17:02:37 -0800477 return cameraDirection;
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700478 }
479
480 public void setCameraDir(int cameraDir) {
481 if (cameraDir == CameraDirection.CAMERA_DIRECTION_FRONT_FACING
482 || cameraDir == CameraDirection.CAMERA_DIRECTION_BACK_FACING) {
linyuh183cb712017-12-27 17:02:37 -0800483 cameraDirection = cameraDir;
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700484 } else {
linyuh183cb712017-12-27 17:02:37 -0800485 cameraDirection = CameraDirection.CAMERA_DIRECTION_UNKNOWN;
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700486 }
Eric Erfanianccca3152017-02-22 16:32:36 -0800487 }
488
Eric Erfanian2ca43182017-08-31 06:57:16 -0700489 public boolean wasParentCall() {
linyuh183cb712017-12-27 17:02:37 -0800490 return logState.conferencedCalls != 0;
Eric Erfanian2ca43182017-08-31 06:57:16 -0700491 }
492
wangqi9982f0d2017-10-11 17:46:07 -0700493 public boolean isVoiceMailNumber() {
494 return isVoicemailNumber;
495 }
496
497 public List<PhoneAccountHandle> getCallCapableAccounts() {
498 return callCapableAccounts;
499 }
500
501 public String getCountryIso() {
502 return countryIso;
503 }
504
505 private void updateIsVoiceMailNumber() {
506 if (getHandle() != null && PhoneAccount.SCHEME_VOICEMAIL.equals(getHandle().getScheme())) {
507 isVoicemailNumber = true;
roldenburg37a969d2018-02-22 14:46:44 -0800508 return;
wangqi9982f0d2017-10-11 17:46:07 -0700509 }
510
linyuh183cb712017-12-27 17:02:37 -0800511 if (!PermissionsUtil.hasPermission(context, permission.READ_PHONE_STATE)) {
wangqi9982f0d2017-10-11 17:46:07 -0700512 isVoicemailNumber = false;
roldenburg37a969d2018-02-22 14:46:44 -0800513 return;
wangqi9982f0d2017-10-11 17:46:07 -0700514 }
515
linyuh183cb712017-12-27 17:02:37 -0800516 isVoicemailNumber = TelecomUtil.isVoicemailNumber(context, getAccountHandle(), getNumber());
wangqi9982f0d2017-10-11 17:46:07 -0700517 }
518
Eric Erfanianccca3152017-02-22 16:32:36 -0800519 private void update() {
Eric Erfanian2ca43182017-08-31 06:57:16 -0700520 Trace.beginSection("DialerCall.update");
Eric Erfanianccca3152017-02-22 16:32:36 -0800521 int oldState = getState();
roldenburg7bb96232017-10-09 10:32:05 -0700522 // Clear any cache here that could potentially change on update.
523 videoTech = null;
Eric Erfanianccca3152017-02-22 16:32:36 -0800524 // We want to potentially register a video call callback here.
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700525 updateFromTelecomCall();
Eric Erfanianccca3152017-02-22 16:32:36 -0800526 if (oldState != getState() && getState() == DialerCall.State.DISCONNECTED) {
linyuh183cb712017-12-27 17:02:37 -0800527 for (DialerCallListener listener : listeners) {
Eric Erfanianccca3152017-02-22 16:32:36 -0800528 listener.onDialerCallDisconnect();
529 }
linyuh183cb712017-12-27 17:02:37 -0800530 EnrichedCallComponent.get(context)
Eric Erfanian2ca43182017-08-31 06:57:16 -0700531 .getEnrichedCallManager()
532 .unregisterCapabilitiesListener(this);
linyuh183cb712017-12-27 17:02:37 -0800533 EnrichedCallComponent.get(context)
Eric Erfanian2ca43182017-08-31 06:57:16 -0700534 .getEnrichedCallManager()
535 .unregisterStateChangedListener(this);
Eric Erfanianccca3152017-02-22 16:32:36 -0800536 } else {
linyuh183cb712017-12-27 17:02:37 -0800537 for (DialerCallListener listener : listeners) {
Eric Erfanianccca3152017-02-22 16:32:36 -0800538 listener.onDialerCallUpdate();
539 }
540 }
541 Trace.endSection();
542 }
543
wangqi9982f0d2017-10-11 17:46:07 -0700544 @SuppressWarnings("MissingPermission")
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700545 private void updateFromTelecomCall() {
Eric Erfanian2ca43182017-08-31 06:57:16 -0700546 Trace.beginSection("DialerCall.updateFromTelecomCall");
linyuh183cb712017-12-27 17:02:37 -0800547 LogUtil.v("DialerCall.updateFromTelecomCall", telecomCall.toString());
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700548
roldenburg6bd612f2018-01-18 12:57:19 -0800549 videoTechManager.dispatchCallStateChanged(telecomCall.getState(), getAccountHandle());
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700550
linyuh183cb712017-12-27 17:02:37 -0800551 final int translatedState = translateState(telecomCall.getState());
552 if (state != State.BLOCKED) {
Eric Erfanianccca3152017-02-22 16:32:36 -0800553 setState(translatedState);
linyuh183cb712017-12-27 17:02:37 -0800554 setDisconnectCause(telecomCall.getDetails().getDisconnectCause());
Eric Erfanianccca3152017-02-22 16:32:36 -0800555 }
556
linyuh183cb712017-12-27 17:02:37 -0800557 childCallIds.clear();
558 final int numChildCalls = telecomCall.getChildren().size();
Eric Erfanianccca3152017-02-22 16:32:36 -0800559 for (int i = 0; i < numChildCalls; i++) {
linyuh183cb712017-12-27 17:02:37 -0800560 childCallIds.add(
561 dialerCallDelegate
562 .getDialerCallFromTelecomCall(telecomCall.getChildren().get(i))
Eric Erfanianccca3152017-02-22 16:32:36 -0800563 .getId());
564 }
565
566 // The number of conferenced calls can change over the course of the call, so use the
567 // maximum number of conferenced child calls as the metric for conference call usage.
linyuh183cb712017-12-27 17:02:37 -0800568 logState.conferencedCalls = Math.max(numChildCalls, logState.conferencedCalls);
Eric Erfanianccca3152017-02-22 16:32:36 -0800569
linyuh183cb712017-12-27 17:02:37 -0800570 updateFromCallExtras(telecomCall.getDetails().getExtras());
Eric Erfanianccca3152017-02-22 16:32:36 -0800571
572 // If the handle of the call has changed, update state for the call determining if it is an
573 // emergency call.
linyuh183cb712017-12-27 17:02:37 -0800574 Uri newHandle = telecomCall.getDetails().getHandle();
575 if (!Objects.equals(handle, newHandle)) {
576 handle = newHandle;
Eric Erfanianccca3152017-02-22 16:32:36 -0800577 updateEmergencyCallState();
578 }
579
linyuh183cb712017-12-27 17:02:37 -0800580 TelecomManager telecomManager = context.getSystemService(TelecomManager.class);
Eric Erfanianccca3152017-02-22 16:32:36 -0800581 // If the phone account handle of the call is set, cache capability bit indicating whether
582 // the phone account supports call subjects.
linyuh183cb712017-12-27 17:02:37 -0800583 PhoneAccountHandle newPhoneAccountHandle = telecomCall.getDetails().getAccountHandle();
584 if (!Objects.equals(phoneAccountHandle, newPhoneAccountHandle)) {
585 phoneAccountHandle = newPhoneAccountHandle;
Eric Erfanianccca3152017-02-22 16:32:36 -0800586
linyuh183cb712017-12-27 17:02:37 -0800587 if (phoneAccountHandle != null) {
588 PhoneAccount phoneAccount = telecomManager.getPhoneAccount(phoneAccountHandle);
Eric Erfanianccca3152017-02-22 16:32:36 -0800589 if (phoneAccount != null) {
linyuh183cb712017-12-27 17:02:37 -0800590 isCallSubjectSupported =
Eric Erfanianccca3152017-02-22 16:32:36 -0800591 phoneAccount.hasCapabilities(PhoneAccount.CAPABILITY_CALL_SUBJECT);
wangqida410d32018-03-06 16:51:38 -0800592 if (phoneAccount.hasCapabilities(PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION)) {
593 cacheCarrierConfiguration(phoneAccountHandle);
594 }
Eric Erfanianccca3152017-02-22 16:32:36 -0800595 }
596 }
597 }
linyuh183cb712017-12-27 17:02:37 -0800598 if (PermissionsUtil.hasPermission(context, permission.READ_PHONE_STATE)) {
wangqi9982f0d2017-10-11 17:46:07 -0700599 updateIsVoiceMailNumber();
600 callCapableAccounts = telecomManager.getCallCapablePhoneAccounts();
linyuh183cb712017-12-27 17:02:37 -0800601 countryIso = GeoUtil.getCurrentCountryIso(context);
wangqi9982f0d2017-10-11 17:46:07 -0700602 }
Eric Erfanian2ca43182017-08-31 06:57:16 -0700603 Trace.endSection();
Eric Erfanianccca3152017-02-22 16:32:36 -0800604 }
605
606 /**
wangqida410d32018-03-06 16:51:38 -0800607 * Caches frequently used carrier configuration locally.
608 *
609 * @param accountHandle The PhoneAccount handle.
610 */
611 @SuppressLint("MissingPermission")
612 private void cacheCarrierConfiguration(PhoneAccountHandle accountHandle) {
613 if (!PermissionsUtil.hasPermission(context, permission.READ_PHONE_STATE)) {
614 return;
615 }
616 if (VERSION.SDK_INT < VERSION_CODES.O) {
617 return;
618 }
619 // TODO(a bug): This may take several seconds to complete, revisit it to move it to worker
620 // thread.
621 carrierConfig =
622 TelephonyManagerCompat.getTelephonyManagerForPhoneAccountHandle(context, accountHandle)
623 .getCarrierConfig();
624 }
625
626 /**
Eric Erfanianccca3152017-02-22 16:32:36 -0800627 * Tests corruption of the {@code callExtras} bundle by calling {@link
628 * Bundle#containsKey(String)}. If the bundle is corrupted a {@link IllegalArgumentException} will
629 * be thrown and caught by this function.
630 *
631 * @param callExtras the bundle to verify
632 * @return {@code true} if the bundle is corrupted, {@code false} otherwise.
633 */
634 protected boolean areCallExtrasCorrupted(Bundle callExtras) {
635 /**
Eric Erfanian938468d2017-10-24 14:05:52 -0700636 * There's currently a bug in Telephony service (a bug) that could corrupt the extras
Eric Erfanianccca3152017-02-22 16:32:36 -0800637 * bundle, resulting in a IllegalArgumentException while validating data under {@link
638 * Bundle#containsKey(String)}.
639 */
640 try {
641 callExtras.containsKey(Connection.EXTRA_CHILD_ADDRESS);
642 return false;
643 } catch (IllegalArgumentException e) {
644 LogUtil.e(
645 "DialerCall.areCallExtrasCorrupted", "callExtras is corrupted, ignoring exception", e);
646 return true;
647 }
648 }
649
650 protected void updateFromCallExtras(Bundle callExtras) {
651 if (callExtras == null || areCallExtrasCorrupted(callExtras)) {
652 /**
653 * If the bundle is corrupted, abandon information update as a work around. These are not
654 * critical for the dialer to function.
655 */
656 return;
657 }
658 // Check for a change in the child address and notify any listeners.
659 if (callExtras.containsKey(Connection.EXTRA_CHILD_ADDRESS)) {
660 String childNumber = callExtras.getString(Connection.EXTRA_CHILD_ADDRESS);
linyuh183cb712017-12-27 17:02:37 -0800661 if (!Objects.equals(childNumber, this.childNumber)) {
662 this.childNumber = childNumber;
663 for (DialerCallListener listener : listeners) {
Eric Erfanianccca3152017-02-22 16:32:36 -0800664 listener.onDialerCallChildNumberChange();
665 }
666 }
667 }
668
669 // Last forwarded number comes in as an array of strings. We want to choose the
670 // last item in the array. The forwarding numbers arrive independently of when the
671 // call is originally set up, so we need to notify the the UI of the change.
672 if (callExtras.containsKey(Connection.EXTRA_LAST_FORWARDED_NUMBER)) {
673 ArrayList<String> lastForwardedNumbers =
674 callExtras.getStringArrayList(Connection.EXTRA_LAST_FORWARDED_NUMBER);
675
676 if (lastForwardedNumbers != null) {
677 String lastForwardedNumber = null;
678 if (!lastForwardedNumbers.isEmpty()) {
679 lastForwardedNumber = lastForwardedNumbers.get(lastForwardedNumbers.size() - 1);
680 }
681
linyuh183cb712017-12-27 17:02:37 -0800682 if (!Objects.equals(lastForwardedNumber, this.lastForwardedNumber)) {
683 this.lastForwardedNumber = lastForwardedNumber;
684 for (DialerCallListener listener : listeners) {
Eric Erfanianccca3152017-02-22 16:32:36 -0800685 listener.onDialerCallLastForwardedNumberChange();
686 }
687 }
688 }
689 }
690
691 // DialerCall subject is present in the extras at the start of call, so we do not need to
692 // notify any other listeners of this.
693 if (callExtras.containsKey(Connection.EXTRA_CALL_SUBJECT)) {
694 String callSubject = callExtras.getString(Connection.EXTRA_CALL_SUBJECT);
linyuh183cb712017-12-27 17:02:37 -0800695 if (!Objects.equals(this.callSubject, callSubject)) {
696 this.callSubject = callSubject;
Eric Erfanianccca3152017-02-22 16:32:36 -0800697 }
698 }
699 }
700
Eric Erfanianccca3152017-02-22 16:32:36 -0800701 public String getId() {
linyuh183cb712017-12-27 17:02:37 -0800702 return id;
Eric Erfanianccca3152017-02-22 16:32:36 -0800703 }
704
Eric Erfanianc857f902017-05-15 14:05:33 -0700705 /**
706 * @return name appended with a number if the number is restricted/unknown and the user has
707 * received more than one restricted/unknown call.
708 */
709 @Nullable
710 public String updateNameIfRestricted(@Nullable String name) {
linyuh183cb712017-12-27 17:02:37 -0800711 if (name != null && isHiddenNumber() && hiddenId != 0 && hiddenCounter > 1) {
712 return context.getString(R.string.unknown_counter, name, hiddenId);
Eric Erfanianc857f902017-05-15 14:05:33 -0700713 }
714 return name;
715 }
716
717 public static void clearRestrictedCount() {
linyuh183cb712017-12-27 17:02:37 -0800718 hiddenCounter = 0;
Eric Erfanianc857f902017-05-15 14:05:33 -0700719 }
720
721 private boolean isHiddenNumber() {
722 return getNumberPresentation() == TelecomManager.PRESENTATION_RESTRICTED
723 || getNumberPresentation() == TelecomManager.PRESENTATION_UNKNOWN;
724 }
725
Eric Erfanianccca3152017-02-22 16:32:36 -0800726 public boolean hasShownWiFiToLteHandoverToast() {
727 return hasShownWiFiToLteHandoverToast;
728 }
729
730 public void setHasShownWiFiToLteHandoverToast() {
731 hasShownWiFiToLteHandoverToast = true;
732 }
733
734 public boolean showWifiHandoverAlertAsToast() {
735 return doNotShowDialogForHandoffToWifiFailure;
736 }
737
738 public void setDoNotShowDialogForHandoffToWifiFailure(boolean bool) {
739 doNotShowDialogForHandoffToWifiFailure = bool;
740 }
741
wangqida410d32018-03-06 16:51:38 -0800742 public boolean showVideoChargesAlertDialog() {
743 if (carrierConfig == null) {
744 return false;
745 }
746 return carrierConfig.getBoolean(
747 TelephonyManagerCompat.CARRIER_CONFIG_KEY_SHOW_VIDEO_CALL_CHARGES_ALERT_DIALOG_BOOL);
748 }
749
Eric Erfanianccca3152017-02-22 16:32:36 -0800750 public long getTimeAddedMs() {
linyuh183cb712017-12-27 17:02:37 -0800751 return timeAddedMs;
Eric Erfanianccca3152017-02-22 16:32:36 -0800752 }
753
754 @Nullable
755 public String getNumber() {
linyuh183cb712017-12-27 17:02:37 -0800756 return TelecomCallUtil.getNumber(telecomCall);
Eric Erfanianccca3152017-02-22 16:32:36 -0800757 }
758
759 public void blockCall() {
linyuh183cb712017-12-27 17:02:37 -0800760 telecomCall.reject(false, null);
Eric Erfanianccca3152017-02-22 16:32:36 -0800761 setState(State.BLOCKED);
762 }
763
764 @Nullable
765 public Uri getHandle() {
linyuh183cb712017-12-27 17:02:37 -0800766 return telecomCall == null ? null : telecomCall.getDetails().getHandle();
Eric Erfanianccca3152017-02-22 16:32:36 -0800767 }
768
769 public boolean isEmergencyCall() {
linyuh183cb712017-12-27 17:02:37 -0800770 return isEmergencyCall;
Eric Erfanianccca3152017-02-22 16:32:36 -0800771 }
772
773 public boolean isPotentialEmergencyCallback() {
774 // The property PROPERTY_EMERGENCY_CALLBACK_MODE is only set for CDMA calls when the system
775 // is actually in emergency callback mode (ie data is disabled).
776 if (hasProperty(Details.PROPERTY_EMERGENCY_CALLBACK_MODE)) {
777 return true;
778 }
779 // We want to treat any incoming call that arrives a short time after an outgoing emergency call
780 // as a potential emergency callback.
781 if (getExtras() != null
782 && getExtras().getLong(TelecomManagerCompat.EXTRA_LAST_EMERGENCY_CALLBACK_TIME_MILLIS, 0)
783 > 0) {
784 long lastEmergencyCallMillis =
785 getExtras().getLong(TelecomManagerCompat.EXTRA_LAST_EMERGENCY_CALLBACK_TIME_MILLIS, 0);
786 if (isInEmergencyCallbackWindow(lastEmergencyCallMillis)) {
787 return true;
788 }
789 }
790 return false;
791 }
792
793 boolean isInEmergencyCallbackWindow(long timestampMillis) {
794 long emergencyCallbackWindowMillis =
linyuh183cb712017-12-27 17:02:37 -0800795 ConfigProviderBindings.get(context)
Eric Erfanianccca3152017-02-22 16:32:36 -0800796 .getLong(CONFIG_EMERGENCY_CALLBACK_WINDOW_MILLIS, TimeUnit.MINUTES.toMillis(5));
797 return System.currentTimeMillis() - timestampMillis < emergencyCallbackWindowMillis;
798 }
799
800 public int getState() {
linyuh183cb712017-12-27 17:02:37 -0800801 if (telecomCall != null && telecomCall.getParent() != null) {
Eric Erfanianccca3152017-02-22 16:32:36 -0800802 return State.CONFERENCED;
803 } else {
linyuh183cb712017-12-27 17:02:37 -0800804 return state;
Eric Erfanianccca3152017-02-22 16:32:36 -0800805 }
806 }
807
yueg265089a2017-10-06 14:35:15 -0700808 public int getNonConferenceState() {
linyuh183cb712017-12-27 17:02:37 -0800809 return state;
yueg265089a2017-10-06 14:35:15 -0700810 }
811
Eric Erfanianccca3152017-02-22 16:32:36 -0800812 public void setState(int state) {
Eric Erfanian2ca43182017-08-31 06:57:16 -0700813 if (state == State.INCOMING) {
linyuh183cb712017-12-27 17:02:37 -0800814 logState.isIncoming = true;
Eric Erfanian2ca43182017-08-31 06:57:16 -0700815 } else if (state == State.DISCONNECTED) {
816 long newDuration =
Eric Erfanianccca3152017-02-22 16:32:36 -0800817 getConnectTimeMillis() == 0 ? 0 : System.currentTimeMillis() - getConnectTimeMillis();
linyuh183cb712017-12-27 17:02:37 -0800818 if (this.state != state) {
819 logState.duration = newDuration;
Eric Erfanian2ca43182017-08-31 06:57:16 -0700820 } else {
821 LogUtil.i(
822 "DialerCall.setState",
823 "ignoring state transition from DISCONNECTED to DISCONNECTED."
824 + " Duration would have changed from %s to %s",
linyuh183cb712017-12-27 17:02:37 -0800825 logState.duration,
Eric Erfanian2ca43182017-08-31 06:57:16 -0700826 newDuration);
827 }
Eric Erfanianccca3152017-02-22 16:32:36 -0800828 }
linyuh183cb712017-12-27 17:02:37 -0800829 this.state = state;
Eric Erfanianccca3152017-02-22 16:32:36 -0800830 }
831
832 public int getNumberPresentation() {
linyuh183cb712017-12-27 17:02:37 -0800833 return telecomCall == null ? -1 : telecomCall.getDetails().getHandlePresentation();
Eric Erfanianccca3152017-02-22 16:32:36 -0800834 }
835
836 public int getCnapNamePresentation() {
linyuh183cb712017-12-27 17:02:37 -0800837 return telecomCall == null ? -1 : telecomCall.getDetails().getCallerDisplayNamePresentation();
Eric Erfanianccca3152017-02-22 16:32:36 -0800838 }
839
840 @Nullable
841 public String getCnapName() {
linyuh183cb712017-12-27 17:02:37 -0800842 return telecomCall == null ? null : getTelecomCall().getDetails().getCallerDisplayName();
Eric Erfanianccca3152017-02-22 16:32:36 -0800843 }
844
845 public Bundle getIntentExtras() {
linyuh183cb712017-12-27 17:02:37 -0800846 return telecomCall.getDetails().getIntentExtras();
Eric Erfanianccca3152017-02-22 16:32:36 -0800847 }
848
849 @Nullable
850 public Bundle getExtras() {
linyuh183cb712017-12-27 17:02:37 -0800851 return telecomCall == null ? null : telecomCall.getDetails().getExtras();
Eric Erfanianccca3152017-02-22 16:32:36 -0800852 }
853
854 /** @return The child number for the call, or {@code null} if none specified. */
855 public String getChildNumber() {
linyuh183cb712017-12-27 17:02:37 -0800856 return childNumber;
Eric Erfanianccca3152017-02-22 16:32:36 -0800857 }
858
859 /** @return The last forwarded number for the call, or {@code null} if none specified. */
860 public String getLastForwardedNumber() {
linyuh183cb712017-12-27 17:02:37 -0800861 return lastForwardedNumber;
Eric Erfanianccca3152017-02-22 16:32:36 -0800862 }
863
wangqif4ba3452018-01-09 11:26:29 -0800864 public boolean isCallForwarded() {
865 return isCallForwarded;
866 }
867
Eric Erfanianccca3152017-02-22 16:32:36 -0800868 /** @return The call subject, or {@code null} if none specified. */
869 public String getCallSubject() {
linyuh183cb712017-12-27 17:02:37 -0800870 return callSubject;
Eric Erfanianccca3152017-02-22 16:32:36 -0800871 }
872
873 /**
874 * @return {@code true} if the call's phone account supports call subjects, {@code false}
875 * otherwise.
876 */
877 public boolean isCallSubjectSupported() {
linyuh183cb712017-12-27 17:02:37 -0800878 return isCallSubjectSupported;
Eric Erfanianccca3152017-02-22 16:32:36 -0800879 }
880
881 /** Returns call disconnect cause, defined by {@link DisconnectCause}. */
882 public DisconnectCause getDisconnectCause() {
linyuh183cb712017-12-27 17:02:37 -0800883 if (state == State.DISCONNECTED || state == State.IDLE) {
884 return disconnectCause;
Eric Erfanianccca3152017-02-22 16:32:36 -0800885 }
886
887 return new DisconnectCause(DisconnectCause.UNKNOWN);
888 }
889
890 public void setDisconnectCause(DisconnectCause disconnectCause) {
linyuh183cb712017-12-27 17:02:37 -0800891 this.disconnectCause = disconnectCause;
892 logState.disconnectCause = this.disconnectCause;
Eric Erfanianccca3152017-02-22 16:32:36 -0800893 }
894
895 /** Returns the possible text message responses. */
896 public List<String> getCannedSmsResponses() {
linyuh183cb712017-12-27 17:02:37 -0800897 return telecomCall.getCannedTextResponses();
Eric Erfanianccca3152017-02-22 16:32:36 -0800898 }
899
900 /** Checks if the call supports the given set of capabilities supplied as a bit mask. */
901 public boolean can(int capabilities) {
linyuh183cb712017-12-27 17:02:37 -0800902 int supportedCapabilities = telecomCall.getDetails().getCallCapabilities();
Eric Erfanianccca3152017-02-22 16:32:36 -0800903
904 if ((capabilities & Call.Details.CAPABILITY_MERGE_CONFERENCE) != 0) {
905 // We allow you to merge if the capabilities allow it or if it is a call with
906 // conferenceable calls.
linyuh183cb712017-12-27 17:02:37 -0800907 if (telecomCall.getConferenceableCalls().isEmpty()
Eric Erfanianccca3152017-02-22 16:32:36 -0800908 && ((Call.Details.CAPABILITY_MERGE_CONFERENCE & supportedCapabilities) == 0)) {
909 // Cannot merge calls if there are no calls to merge with.
910 return false;
911 }
912 capabilities &= ~Call.Details.CAPABILITY_MERGE_CONFERENCE;
913 }
914 return (capabilities == (capabilities & supportedCapabilities));
915 }
916
917 public boolean hasProperty(int property) {
linyuh183cb712017-12-27 17:02:37 -0800918 return telecomCall.getDetails().hasProperty(property);
Eric Erfanianccca3152017-02-22 16:32:36 -0800919 }
920
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700921 @NonNull
Eric Erfanianccca3152017-02-22 16:32:36 -0800922 public String getUniqueCallId() {
923 return uniqueCallId;
924 }
925
926 /** Gets the time when the call first became active. */
927 public long getConnectTimeMillis() {
linyuh183cb712017-12-27 17:02:37 -0800928 return telecomCall.getDetails().getConnectTimeMillis();
Eric Erfanianccca3152017-02-22 16:32:36 -0800929 }
930
931 public boolean isConferenceCall() {
932 return hasProperty(Call.Details.PROPERTY_CONFERENCE);
933 }
934
935 @Nullable
936 public GatewayInfo getGatewayInfo() {
linyuh183cb712017-12-27 17:02:37 -0800937 return telecomCall == null ? null : telecomCall.getDetails().getGatewayInfo();
Eric Erfanianccca3152017-02-22 16:32:36 -0800938 }
939
940 @Nullable
941 public PhoneAccountHandle getAccountHandle() {
linyuh183cb712017-12-27 17:02:37 -0800942 return telecomCall == null ? null : telecomCall.getDetails().getAccountHandle();
Eric Erfanianccca3152017-02-22 16:32:36 -0800943 }
944
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700945 /** @return The {@link VideoCall} instance associated with the {@link Call}. */
Eric Erfanianccca3152017-02-22 16:32:36 -0800946 public VideoCall getVideoCall() {
linyuh183cb712017-12-27 17:02:37 -0800947 return telecomCall == null ? null : telecomCall.getVideoCall();
Eric Erfanianccca3152017-02-22 16:32:36 -0800948 }
949
950 public List<String> getChildCallIds() {
linyuh183cb712017-12-27 17:02:37 -0800951 return childCallIds;
Eric Erfanianccca3152017-02-22 16:32:36 -0800952 }
953
954 public String getParentId() {
linyuh183cb712017-12-27 17:02:37 -0800955 Call parentCall = telecomCall.getParent();
Eric Erfanianccca3152017-02-22 16:32:36 -0800956 if (parentCall != null) {
linyuh183cb712017-12-27 17:02:37 -0800957 return dialerCallDelegate.getDialerCallFromTelecomCall(parentCall).getId();
Eric Erfanianccca3152017-02-22 16:32:36 -0800958 }
959 return null;
960 }
961
962 public int getVideoState() {
linyuh183cb712017-12-27 17:02:37 -0800963 return telecomCall.getDetails().getVideoState();
Eric Erfanianccca3152017-02-22 16:32:36 -0800964 }
965
966 public boolean isVideoCall() {
roldenburg2cec3802017-10-11 16:26:51 -0700967 return getVideoTech().isTransmittingOrReceiving() || VideoProfile.isVideo(getVideoState());
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700968 }
969
wangqi8d407a02018-02-15 15:32:52 -0800970 @TargetApi(28)
wangqi219b8702018-02-13 09:34:41 -0800971 public boolean isRttCall() {
972 if (BuildCompat.isAtLeastP()) {
973 return getTelecomCall().isRttActive();
974 } else {
975 return false;
976 }
977 }
978
wangqi153af2f2018-02-15 16:21:49 -0800979 @TargetApi(28)
980 public RttCall getRttCall() {
981 if (!isRttCall()) {
982 return null;
983 }
984 return getTelecomCall().getRttCall();
985 }
986
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700987 public boolean hasReceivedVideoUpgradeRequest() {
988 return VideoUtils.hasReceivedVideoUpgradeRequest(getVideoTech().getSessionModificationState());
989 }
990
991 public boolean hasSentVideoUpgradeRequest() {
992 return VideoUtils.hasSentVideoUpgradeRequest(getVideoTech().getSessionModificationState());
Eric Erfanianccca3152017-02-22 16:32:36 -0800993 }
994
wangqi219b8702018-02-13 09:34:41 -0800995 public boolean hasSentRttUpgradeRequest() {
wangqi219b8702018-02-13 09:34:41 -0800996 return false;
997 }
998
Eric Erfanianccca3152017-02-22 16:32:36 -0800999 /**
1000 * Determines if the call handle is an emergency number or not and caches the result to avoid
1001 * repeated calls to isEmergencyNumber.
1002 */
1003 private void updateEmergencyCallState() {
linyuh183cb712017-12-27 17:02:37 -08001004 isEmergencyCall = TelecomCallUtil.isEmergencyCall(telecomCall);
Eric Erfanianccca3152017-02-22 16:32:36 -08001005 }
1006
Eric Erfanianccca3152017-02-22 16:32:36 -08001007 public LogState getLogState() {
linyuh183cb712017-12-27 17:02:37 -08001008 return logState;
Eric Erfanianccca3152017-02-22 16:32:36 -08001009 }
1010
1011 /**
1012 * Determines if the call is an external call.
1013 *
1014 * <p>An external call is one which does not exist locally for the {@link
1015 * android.telecom.ConnectionService} it is associated with.
1016 *
1017 * <p>External calls are only supported in N and higher.
1018 *
1019 * @return {@code true} if the call is an external call, {@code false} otherwise.
1020 */
1021 public boolean isExternalCall() {
1022 return VERSION.SDK_INT >= VERSION_CODES.N
1023 && hasProperty(CallCompat.Details.PROPERTY_IS_EXTERNAL_CALL);
1024 }
1025
1026 /**
Eric Erfanianccca3152017-02-22 16:32:36 -08001027 * Determines if answering this call will cause an ongoing video call to be dropped.
1028 *
1029 * @return {@code true} if answering this call will drop an ongoing video call, {@code false}
1030 * otherwise.
1031 */
1032 public boolean answeringDisconnectsForegroundVideoCall() {
1033 Bundle extras = getExtras();
1034 if (extras == null
1035 || !extras.containsKey(CallCompat.Details.EXTRA_ANSWERING_DROPS_FOREGROUND_CALL)) {
1036 return false;
1037 }
1038 return extras.getBoolean(CallCompat.Details.EXTRA_ANSWERING_DROPS_FOREGROUND_CALL);
1039 }
1040
1041 private void parseCallSpecificAppData() {
1042 if (isExternalCall()) {
1043 return;
1044 }
1045
linyuh183cb712017-12-27 17:02:37 -08001046 logState.callSpecificAppData = CallIntentParser.getCallSpecificAppData(getIntentExtras());
1047 if (logState.callSpecificAppData == null) {
Eric Erfanian8369df02017-05-03 10:27:13 -07001048
linyuh183cb712017-12-27 17:02:37 -08001049 logState.callSpecificAppData =
Eric Erfanian8369df02017-05-03 10:27:13 -07001050 CallSpecificAppData.newBuilder()
1051 .setCallInitiationType(CallInitiationType.Type.EXTERNAL_INITIATION)
1052 .build();
Eric Erfanianccca3152017-02-22 16:32:36 -08001053 }
1054 if (getState() == State.INCOMING) {
linyuh183cb712017-12-27 17:02:37 -08001055 logState.callSpecificAppData =
1056 logState
Eric Erfanian8369df02017-05-03 10:27:13 -07001057 .callSpecificAppData
1058 .toBuilder()
1059 .setCallInitiationType(CallInitiationType.Type.INCOMING_INITIATION)
1060 .build();
Eric Erfanianccca3152017-02-22 16:32:36 -08001061 }
1062 }
1063
1064 @Override
1065 public String toString() {
linyuh183cb712017-12-27 17:02:37 -08001066 if (telecomCall == null) {
Eric Erfanianccca3152017-02-22 16:32:36 -08001067 // This should happen only in testing since otherwise we would never have a null
1068 // Telecom call.
linyuh183cb712017-12-27 17:02:37 -08001069 return String.valueOf(id);
Eric Erfanianccca3152017-02-22 16:32:36 -08001070 }
1071
1072 return String.format(
1073 Locale.US,
1074 "[%s, %s, %s, %s, children:%s, parent:%s, "
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001075 + "conferenceable:%s, videoState:%s, mSessionModificationState:%d, CameraDir:%s]",
linyuh183cb712017-12-27 17:02:37 -08001076 id,
Eric Erfanianccca3152017-02-22 16:32:36 -08001077 State.toString(getState()),
linyuh183cb712017-12-27 17:02:37 -08001078 Details.capabilitiesToString(telecomCall.getDetails().getCallCapabilities()),
1079 Details.propertiesToString(telecomCall.getDetails().getCallProperties()),
1080 childCallIds,
Eric Erfanianccca3152017-02-22 16:32:36 -08001081 getParentId(),
linyuh183cb712017-12-27 17:02:37 -08001082 this.telecomCall.getConferenceableCalls(),
1083 VideoProfile.videoStateToString(telecomCall.getDetails().getVideoState()),
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001084 getVideoTech().getSessionModificationState(),
1085 getCameraDir());
Eric Erfanianccca3152017-02-22 16:32:36 -08001086 }
1087
1088 public String toSimpleString() {
1089 return super.toString();
1090 }
1091
1092 @CallHistoryStatus
1093 public int getCallHistoryStatus() {
linyuh183cb712017-12-27 17:02:37 -08001094 return callHistoryStatus;
Eric Erfanianccca3152017-02-22 16:32:36 -08001095 }
1096
1097 public void setCallHistoryStatus(@CallHistoryStatus int callHistoryStatus) {
linyuh183cb712017-12-27 17:02:37 -08001098 this.callHistoryStatus = callHistoryStatus;
Eric Erfanianccca3152017-02-22 16:32:36 -08001099 }
1100
1101 public boolean didShowCameraPermission() {
1102 return didShowCameraPermission;
1103 }
1104
1105 public void setDidShowCameraPermission(boolean didShow) {
1106 didShowCameraPermission = didShow;
1107 }
1108
wangqida410d32018-03-06 16:51:38 -08001109 public boolean didDismissVideoChargesAlertDialog() {
1110 return didDismissVideoChargesAlertDialog;
1111 }
1112
1113 public void setDidDismissVideoChargesAlertDialog(boolean didDismiss) {
1114 didDismissVideoChargesAlertDialog = didDismiss;
1115 }
1116
Eric Erfanian938468d2017-10-24 14:05:52 -07001117 @Nullable
1118 public Boolean isInGlobalSpamList() {
Eric Erfanianccca3152017-02-22 16:32:36 -08001119 return isInGlobalSpamList;
1120 }
1121
1122 public void setIsInGlobalSpamList(boolean inSpamList) {
1123 isInGlobalSpamList = inSpamList;
1124 }
1125
Eric Erfanian938468d2017-10-24 14:05:52 -07001126 @Nullable
1127 public Boolean isInUserSpamList() {
Eric Erfanianccca3152017-02-22 16:32:36 -08001128 return isInUserSpamList;
1129 }
1130
1131 public void setIsInUserSpamList(boolean inSpamList) {
1132 isInUserSpamList = inSpamList;
1133 }
1134
Eric Erfanian938468d2017-10-24 14:05:52 -07001135 @Nullable
1136 public Boolean isInUserWhiteList() {
Eric Erfanianccca3152017-02-22 16:32:36 -08001137 return isInUserWhiteList;
1138 }
1139
1140 public void setIsInUserWhiteList(boolean inWhiteList) {
1141 isInUserWhiteList = inWhiteList;
1142 }
1143
1144 public boolean isSpam() {
linyuh183cb712017-12-27 17:02:37 -08001145 return isSpam;
Eric Erfanianccca3152017-02-22 16:32:36 -08001146 }
1147
1148 public void setSpam(boolean isSpam) {
linyuh183cb712017-12-27 17:02:37 -08001149 this.isSpam = isSpam;
Eric Erfanianccca3152017-02-22 16:32:36 -08001150 }
1151
1152 public boolean isBlocked() {
linyuh183cb712017-12-27 17:02:37 -08001153 return isBlocked;
Eric Erfanianccca3152017-02-22 16:32:36 -08001154 }
1155
1156 public void setBlockedStatus(boolean isBlocked) {
linyuh183cb712017-12-27 17:02:37 -08001157 this.isBlocked = isBlocked;
Eric Erfanianccca3152017-02-22 16:32:36 -08001158 }
1159
1160 public boolean isRemotelyHeld() {
1161 return isRemotelyHeld;
1162 }
1163
Eric Erfanian2ca43182017-08-31 06:57:16 -07001164 public boolean isMergeInProcess() {
1165 return isMergeInProcess;
1166 }
1167
Eric Erfanianccca3152017-02-22 16:32:36 -08001168 public boolean isIncoming() {
linyuh183cb712017-12-27 17:02:37 -08001169 return logState.isIncoming;
Eric Erfanianccca3152017-02-22 16:32:36 -08001170 }
1171
erfanian2cf2c342017-12-21 12:01:33 -08001172 /**
1173 * Try and determine if the call used assisted dialing.
1174 *
1175 * <p>We will not be able to verify a call underwent assisted dialing until the Platform
1176 * implmentation is complete in P+.
1177 *
1178 * @return a boolean indicating assisted dialing may have been performed
1179 */
Eric Erfanian2ca43182017-08-31 06:57:16 -07001180 public boolean isAssistedDialed() {
1181 if (getIntentExtras() != null) {
erfaniand2e5d0b2018-03-02 14:54:35 -08001182 // P and below uses the existence of USE_ASSISTED_DIALING to indicate assisted dialing
erfanian2cf2c342017-12-21 12:01:33 -08001183 // was used. The Dialer client is responsible for performing assisted dialing before
1184 // placing the outgoing call.
1185 //
1186 // The existence of the assisted dialing extras indicates that assisted dialing took place.
1187 if (getIntentExtras().getBoolean(TelephonyManagerCompat.USE_ASSISTED_DIALING, false)
1188 && getAssistedDialingExtras() != null
1189 && Build.VERSION.SDK_INT <= ConcreteCreator.BUILD_CODE_CEILING) {
1190 return true;
1191 }
1192 }
1193
Eric Erfanian2ca43182017-08-31 06:57:16 -07001194 return false;
1195 }
1196
erfanian2cf2c342017-12-21 12:01:33 -08001197 @Nullable
erfaniand0f207f2017-10-11 12:23:29 -07001198 public TransformationInfo getAssistedDialingExtras() {
erfanian2cf2c342017-12-21 12:01:33 -08001199 if (getIntentExtras() == null) {
1200 return null;
erfaniand0f207f2017-10-11 12:23:29 -07001201 }
erfanian2cf2c342017-12-21 12:01:33 -08001202
1203 if (getIntentExtras().getBundle(TelephonyManagerCompat.ASSISTED_DIALING_EXTRAS) == null) {
1204 return null;
1205 }
1206
erfanianf2556612018-01-23 09:55:59 -08001207 // Used in N-OMR1
erfanian2cf2c342017-12-21 12:01:33 -08001208 return TransformationInfo.newInstanceFromBundle(
1209 getIntentExtras().getBundle(TelephonyManagerCompat.ASSISTED_DIALING_EXTRAS));
erfaniand0f207f2017-10-11 12:23:29 -07001210 }
1211
Eric Erfanianccca3152017-02-22 16:32:36 -08001212 public LatencyReport getLatencyReport() {
linyuh183cb712017-12-27 17:02:37 -08001213 return latencyReport;
Eric Erfanianccca3152017-02-22 16:32:36 -08001214 }
1215
Eric Erfanian2ca43182017-08-31 06:57:16 -07001216 public int getAnswerAndReleaseButtonDisplayedTimes() {
1217 return answerAndReleaseButtonDisplayedTimes;
1218 }
1219
1220 public void increaseAnswerAndReleaseButtonDisplayedTimes() {
1221 answerAndReleaseButtonDisplayedTimes++;
1222 }
1223
1224 public boolean getReleasedByAnsweringSecondCall() {
1225 return releasedByAnsweringSecondCall;
1226 }
1227
1228 public void setReleasedByAnsweringSecondCall(boolean releasedByAnsweringSecondCall) {
1229 this.releasedByAnsweringSecondCall = releasedByAnsweringSecondCall;
1230 }
1231
1232 public int getSecondCallWithoutAnswerAndReleasedButtonTimes() {
1233 return secondCallWithoutAnswerAndReleasedButtonTimes;
1234 }
1235
1236 public void increaseSecondCallWithoutAnswerAndReleasedButtonTimes() {
1237 secondCallWithoutAnswerAndReleasedButtonTimes++;
1238 }
1239
Eric Erfanian8369df02017-05-03 10:27:13 -07001240 @Nullable
1241 public EnrichedCallCapabilities getEnrichedCallCapabilities() {
linyuh183cb712017-12-27 17:02:37 -08001242 return enrichedCallCapabilities;
Eric Erfanian8369df02017-05-03 10:27:13 -07001243 }
1244
1245 public void setEnrichedCallCapabilities(
1246 @Nullable EnrichedCallCapabilities mEnrichedCallCapabilities) {
linyuh183cb712017-12-27 17:02:37 -08001247 this.enrichedCallCapabilities = mEnrichedCallCapabilities;
Eric Erfanian8369df02017-05-03 10:27:13 -07001248 }
1249
1250 @Nullable
1251 public Session getEnrichedCallSession() {
linyuh183cb712017-12-27 17:02:37 -08001252 return enrichedCallSession;
Eric Erfanian8369df02017-05-03 10:27:13 -07001253 }
1254
1255 public void setEnrichedCallSession(@Nullable Session mEnrichedCallSession) {
linyuh183cb712017-12-27 17:02:37 -08001256 this.enrichedCallSession = mEnrichedCallSession;
Eric Erfanian8369df02017-05-03 10:27:13 -07001257 }
1258
Eric Erfanianccca3152017-02-22 16:32:36 -08001259 public void unregisterCallback() {
linyuh183cb712017-12-27 17:02:37 -08001260 telecomCall.unregisterCallback(telecomCallCallback);
Eric Erfanianccca3152017-02-22 16:32:36 -08001261 }
1262
Eric Erfanianccca3152017-02-22 16:32:36 -08001263 public void phoneAccountSelected(PhoneAccountHandle accountHandle, boolean setDefault) {
1264 LogUtil.i(
1265 "DialerCall.phoneAccountSelected",
1266 "accountHandle: %s, setDefault: %b",
1267 accountHandle,
1268 setDefault);
linyuh183cb712017-12-27 17:02:37 -08001269 telecomCall.phoneAccountSelected(accountHandle, setDefault);
Eric Erfanianccca3152017-02-22 16:32:36 -08001270 }
1271
1272 public void disconnect() {
1273 LogUtil.i("DialerCall.disconnect", "");
1274 setState(DialerCall.State.DISCONNECTING);
linyuh183cb712017-12-27 17:02:37 -08001275 for (DialerCallListener listener : listeners) {
Eric Erfanianccca3152017-02-22 16:32:36 -08001276 listener.onDialerCallUpdate();
1277 }
linyuh183cb712017-12-27 17:02:37 -08001278 telecomCall.disconnect();
Eric Erfanianccca3152017-02-22 16:32:36 -08001279 }
1280
1281 public void hold() {
1282 LogUtil.i("DialerCall.hold", "");
linyuh183cb712017-12-27 17:02:37 -08001283 telecomCall.hold();
Eric Erfanianccca3152017-02-22 16:32:36 -08001284 }
1285
1286 public void unhold() {
1287 LogUtil.i("DialerCall.unhold", "");
linyuh183cb712017-12-27 17:02:37 -08001288 telecomCall.unhold();
Eric Erfanianccca3152017-02-22 16:32:36 -08001289 }
1290
1291 public void splitFromConference() {
1292 LogUtil.i("DialerCall.splitFromConference", "");
linyuh183cb712017-12-27 17:02:37 -08001293 telecomCall.splitFromConference();
Eric Erfanianccca3152017-02-22 16:32:36 -08001294 }
1295
1296 public void answer(int videoState) {
1297 LogUtil.i("DialerCall.answer", "videoState: " + videoState);
linyuh183cb712017-12-27 17:02:37 -08001298 telecomCall.answer(videoState);
Eric Erfanianccca3152017-02-22 16:32:36 -08001299 }
1300
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001301 public void answer() {
linyuh183cb712017-12-27 17:02:37 -08001302 answer(telecomCall.getDetails().getVideoState());
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001303 }
1304
Eric Erfanianccca3152017-02-22 16:32:36 -08001305 public void reject(boolean rejectWithMessage, String message) {
1306 LogUtil.i("DialerCall.reject", "");
linyuh183cb712017-12-27 17:02:37 -08001307 telecomCall.reject(rejectWithMessage, message);
Eric Erfanianccca3152017-02-22 16:32:36 -08001308 }
1309
1310 /** Return the string label to represent the call provider */
1311 public String getCallProviderLabel() {
1312 if (callProviderLabel == null) {
1313 PhoneAccount account = getPhoneAccount();
1314 if (account != null && !TextUtils.isEmpty(account.getLabel())) {
wangqi9982f0d2017-10-11 17:46:07 -07001315 if (callCapableAccounts != null && callCapableAccounts.size() > 1) {
Eric Erfanianccca3152017-02-22 16:32:36 -08001316 callProviderLabel = account.getLabel().toString();
1317 }
1318 }
1319 if (callProviderLabel == null) {
1320 callProviderLabel = "";
1321 }
1322 }
1323 return callProviderLabel;
1324 }
1325
1326 private PhoneAccount getPhoneAccount() {
1327 PhoneAccountHandle accountHandle = getAccountHandle();
1328 if (accountHandle == null) {
1329 return null;
1330 }
linyuh183cb712017-12-27 17:02:37 -08001331 return context.getSystemService(TelecomManager.class).getPhoneAccount(accountHandle);
Eric Erfanianccca3152017-02-22 16:32:36 -08001332 }
1333
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001334 public VideoTech getVideoTech() {
roldenburg7bb96232017-10-09 10:32:05 -07001335 if (videoTech == null) {
roldenburg6bd612f2018-01-18 12:57:19 -08001336 videoTech = videoTechManager.getVideoTech(getAccountHandle());
roldenburg7bb96232017-10-09 10:32:05 -07001337
1338 // Only store the first video tech type found to be available during the life of the call.
1339 if (selectedAvailableVideoTechType == com.android.dialer.logging.VideoTech.Type.NONE) {
1340 // Update the video tech.
1341 selectedAvailableVideoTechType = videoTech.getVideoTechType();
1342 }
1343 }
Eric Erfanian2ca43182017-08-31 06:57:16 -07001344 return videoTech;
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001345 }
1346
Eric Erfanianccca3152017-02-22 16:32:36 -08001347 public String getCallbackNumber() {
1348 if (callbackNumber == null) {
1349 // Show the emergency callback number if either:
1350 // 1. This is an emergency call.
1351 // 2. The phone is in Emergency Callback Mode, which means we should show the callback
1352 // number.
1353 boolean showCallbackNumber = hasProperty(Details.PROPERTY_EMERGENCY_CALLBACK_MODE);
1354
1355 if (isEmergencyCall() || showCallbackNumber) {
wangqi339b4f32017-09-18 14:32:09 -07001356 callbackNumber =
linyuh183cb712017-12-27 17:02:37 -08001357 context.getSystemService(TelecomManager.class).getLine1Number(getAccountHandle());
Eric Erfanianccca3152017-02-22 16:32:36 -08001358 }
1359
Eric Erfanianccca3152017-02-22 16:32:36 -08001360 if (callbackNumber == null) {
1361 callbackNumber = "";
1362 }
1363 }
1364 return callbackNumber;
1365 }
1366
wangqi97539352017-09-25 11:15:16 -07001367 public String getSimCountryIso() {
1368 String simCountryIso =
linyuh183cb712017-12-27 17:02:37 -08001369 TelephonyManagerCompat.getTelephonyManagerForPhoneAccountHandle(context, getAccountHandle())
wangqi97539352017-09-25 11:15:16 -07001370 .getSimCountryIso();
1371 if (!TextUtils.isEmpty(simCountryIso)) {
1372 simCountryIso = simCountryIso.toUpperCase(Locale.US);
1373 }
1374 return simCountryIso;
1375 }
1376
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001377 @Override
1378 public void onVideoTechStateChanged() {
1379 update();
1380 }
1381
1382 @Override
1383 public void onSessionModificationStateChanged() {
wangqi9982f0d2017-10-11 17:46:07 -07001384 Trace.beginSection("DialerCall.onSessionModificationStateChanged");
linyuh183cb712017-12-27 17:02:37 -08001385 for (DialerCallListener listener : listeners) {
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001386 listener.onDialerCallSessionModificationStateChange();
1387 }
wangqi9982f0d2017-10-11 17:46:07 -07001388 Trace.endSection();
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001389 }
1390
1391 @Override
1392 public void onCameraDimensionsChanged(int width, int height) {
1393 InCallVideoCallCallbackNotifier.getInstance().cameraDimensionsChanged(this, width, height);
1394 }
1395
1396 @Override
1397 public void onPeerDimensionsChanged(int width, int height) {
1398 InCallVideoCallCallbackNotifier.getInstance().peerDimensionsChanged(this, width, height);
1399 }
1400
1401 @Override
1402 public void onVideoUpgradeRequestReceived() {
1403 LogUtil.enterBlock("DialerCall.onVideoUpgradeRequestReceived");
1404
linyuh183cb712017-12-27 17:02:37 -08001405 for (DialerCallListener listener : listeners) {
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001406 listener.onDialerCallUpgradeToVideo();
1407 }
1408
1409 update();
Eric Erfanian8369df02017-05-03 10:27:13 -07001410
linyuh183cb712017-12-27 17:02:37 -08001411 Logger.get(context)
Eric Erfanian8369df02017-05-03 10:27:13 -07001412 .logCallImpression(
1413 DialerImpression.Type.VIDEO_CALL_REQUEST_RECEIVED, getUniqueCallId(), getTimeAddedMs());
1414 }
1415
1416 @Override
1417 public void onUpgradedToVideo(boolean switchToSpeaker) {
1418 LogUtil.enterBlock("DialerCall.onUpgradedToVideo");
1419
1420 if (!switchToSpeaker) {
1421 return;
1422 }
1423
1424 CallAudioState audioState = AudioModeProvider.getInstance().getAudioState();
1425
1426 if (0 != (CallAudioState.ROUTE_BLUETOOTH & audioState.getSupportedRouteMask())) {
1427 LogUtil.e(
1428 "DialerCall.onUpgradedToVideo",
1429 "toggling speakerphone not allowed when bluetooth supported.");
1430 return;
1431 }
1432
1433 if (audioState.getRoute() == CallAudioState.ROUTE_SPEAKER) {
1434 return;
1435 }
1436
1437 TelecomAdapter.getInstance().setAudioRoute(CallAudioState.ROUTE_SPEAKER);
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001438 }
1439
Eric Erfanian2ca43182017-08-31 06:57:16 -07001440 @Override
1441 public void onCapabilitiesUpdated() {
1442 if (getNumber() == null) {
1443 return;
1444 }
1445 EnrichedCallCapabilities capabilities =
linyuh183cb712017-12-27 17:02:37 -08001446 EnrichedCallComponent.get(context).getEnrichedCallManager().getCapabilities(getNumber());
Eric Erfanian2ca43182017-08-31 06:57:16 -07001447 if (capabilities != null) {
1448 setEnrichedCallCapabilities(capabilities);
1449 update();
1450 }
1451 }
1452
1453 @Override
1454 public void onEnrichedCallStateChanged() {
1455 updateEnrichedCallSession();
1456 }
1457
1458 @Override
1459 public void onImpressionLoggingNeeded(DialerImpression.Type impressionType) {
linyuh183cb712017-12-27 17:02:37 -08001460 Logger.get(context).logCallImpression(impressionType, getUniqueCallId(), getTimeAddedMs());
twyendde01c52017-09-22 10:07:31 -07001461 if (impressionType == DialerImpression.Type.LIGHTBRINGER_UPGRADE_REQUESTED) {
1462 if (getLogState().contactLookupResult == Type.NOT_FOUND) {
linyuh183cb712017-12-27 17:02:37 -08001463 Logger.get(context)
twyendde01c52017-09-22 10:07:31 -07001464 .logCallImpression(
1465 DialerImpression.Type.LIGHTBRINGER_NON_CONTACT_UPGRADE_REQUESTED,
1466 getUniqueCallId(),
1467 getTimeAddedMs());
1468 }
1469 }
Eric Erfanian2ca43182017-08-31 06:57:16 -07001470 }
1471
1472 private void updateEnrichedCallSession() {
1473 if (getNumber() == null) {
1474 return;
1475 }
1476 if (getEnrichedCallSession() != null) {
1477 // State changes to existing sessions are currently handled by the UI components (which have
1478 // their own listeners). Someday instead we could remove those and just call update() here and
1479 // have the usual onDialerCallUpdate update the UI.
1480 dispatchOnEnrichedCallSessionUpdate();
1481 return;
1482 }
1483
linyuh183cb712017-12-27 17:02:37 -08001484 EnrichedCallManager manager = EnrichedCallComponent.get(context).getEnrichedCallManager();
Eric Erfanian2ca43182017-08-31 06:57:16 -07001485
1486 Filter filter =
1487 isIncoming()
1488 ? manager.createIncomingCallComposerFilter()
1489 : manager.createOutgoingCallComposerFilter();
1490
1491 Session session = manager.getSession(getUniqueCallId(), getNumber(), filter);
1492 if (session == null) {
1493 return;
1494 }
1495
1496 session.setUniqueDialerCallId(getUniqueCallId());
1497 setEnrichedCallSession(session);
1498
1499 LogUtil.i(
1500 "DialerCall.updateEnrichedCallSession",
1501 "setting session %d's dialer id to %s",
1502 session.getSessionId(),
1503 getUniqueCallId());
1504
1505 dispatchOnEnrichedCallSessionUpdate();
1506 }
1507
1508 private void dispatchOnEnrichedCallSessionUpdate() {
linyuh183cb712017-12-27 17:02:37 -08001509 for (DialerCallListener listener : listeners) {
Eric Erfanian2ca43182017-08-31 06:57:16 -07001510 listener.onEnrichedCallSessionUpdate();
1511 }
1512 }
1513
1514 void onRemovedFromCallList() {
1515 // Ensure we clean up when this call is removed.
linyuh183cb712017-12-27 17:02:37 -08001516 videoTechManager.dispatchRemovedFromCallList();
Eric Erfanian2ca43182017-08-31 06:57:16 -07001517 }
1518
wangqi4d705e52017-09-28 12:23:35 -07001519 public com.android.dialer.logging.VideoTech.Type getSelectedAvailableVideoTechType() {
1520 return selectedAvailableVideoTechType;
yueg457b3972017-09-18 15:11:47 -07001521 }
1522
Android Dialer974fc292018-02-01 16:12:25 -08001523 public void markFeedbackRequested() {
1524 feedbackRequested = true;
1525 }
1526
1527 public boolean isFeedbackRequested() {
1528 return feedbackRequested;
1529 }
1530
Eric Erfanianccca3152017-02-22 16:32:36 -08001531 /**
1532 * Specifies whether a number is in the call history or not. {@link #CALL_HISTORY_STATUS_UNKNOWN}
1533 * means there is no result.
1534 */
1535 @IntDef({
1536 CALL_HISTORY_STATUS_UNKNOWN,
1537 CALL_HISTORY_STATUS_PRESENT,
1538 CALL_HISTORY_STATUS_NOT_PRESENT
1539 })
1540 @Retention(RetentionPolicy.SOURCE)
1541 public @interface CallHistoryStatus {}
1542
1543 /* Defines different states of this call */
1544 public static class State {
1545
1546 public static final int INVALID = 0;
1547 public static final int NEW = 1; /* The call is new. */
1548 public static final int IDLE = 2; /* The call is idle. Nothing active */
1549 public static final int ACTIVE = 3; /* There is an active call */
1550 public static final int INCOMING = 4; /* A normal incoming phone call */
1551 public static final int CALL_WAITING = 5; /* Incoming call while another is active */
1552 public static final int DIALING = 6; /* An outgoing call during dial phase */
1553 public static final int REDIALING = 7; /* Subsequent dialing attempt after a failure */
1554 public static final int ONHOLD = 8; /* An active phone call placed on hold */
1555 public static final int DISCONNECTING = 9; /* A call is being ended. */
1556 public static final int DISCONNECTED = 10; /* State after a call disconnects */
1557 public static final int CONFERENCED = 11; /* DialerCall part of a conference call */
1558 public static final int SELECT_PHONE_ACCOUNT = 12; /* Waiting for account selection */
1559 public static final int CONNECTING = 13; /* Waiting for Telecom broadcast to finish */
1560 public static final int BLOCKED = 14; /* The number was found on the block list */
1561 public static final int PULLING = 15; /* An external call being pulled to the device */
Eric Erfanian2ca43182017-08-31 06:57:16 -07001562 public static final int CALL_PENDING = 16; /* A call is pending on a long process to finish */
Eric Erfanianccca3152017-02-22 16:32:36 -08001563
1564 public static boolean isConnectingOrConnected(int state) {
1565 switch (state) {
1566 case ACTIVE:
1567 case INCOMING:
1568 case CALL_WAITING:
1569 case CONNECTING:
1570 case DIALING:
1571 case PULLING:
1572 case REDIALING:
1573 case ONHOLD:
1574 case CONFERENCED:
1575 return true;
1576 default:
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001577 return false;
Eric Erfanianccca3152017-02-22 16:32:36 -08001578 }
Eric Erfanianccca3152017-02-22 16:32:36 -08001579 }
1580
1581 public static boolean isDialing(int state) {
1582 return state == DIALING || state == PULLING || state == REDIALING;
1583 }
1584
1585 public static String toString(int state) {
1586 switch (state) {
1587 case INVALID:
1588 return "INVALID";
1589 case NEW:
1590 return "NEW";
1591 case IDLE:
1592 return "IDLE";
1593 case ACTIVE:
1594 return "ACTIVE";
1595 case INCOMING:
1596 return "INCOMING";
1597 case CALL_WAITING:
1598 return "CALL_WAITING";
1599 case DIALING:
1600 return "DIALING";
1601 case PULLING:
1602 return "PULLING";
1603 case REDIALING:
1604 return "REDIALING";
1605 case ONHOLD:
1606 return "ONHOLD";
1607 case DISCONNECTING:
1608 return "DISCONNECTING";
1609 case DISCONNECTED:
1610 return "DISCONNECTED";
1611 case CONFERENCED:
1612 return "CONFERENCED";
1613 case SELECT_PHONE_ACCOUNT:
1614 return "SELECT_PHONE_ACCOUNT";
1615 case CONNECTING:
1616 return "CONNECTING";
1617 case BLOCKED:
1618 return "BLOCKED";
1619 default:
1620 return "UNKNOWN";
1621 }
1622 }
1623 }
1624
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001625 /** Camera direction constants */
1626 public static class CameraDirection {
Eric Erfanianccca3152017-02-22 16:32:36 -08001627 public static final int CAMERA_DIRECTION_UNKNOWN = -1;
1628 public static final int CAMERA_DIRECTION_FRONT_FACING = CameraCharacteristics.LENS_FACING_FRONT;
1629 public static final int CAMERA_DIRECTION_BACK_FACING = CameraCharacteristics.LENS_FACING_BACK;
Eric Erfanianccca3152017-02-22 16:32:36 -08001630 }
1631
1632 /**
1633 * Tracks any state variables that is useful for logging. There is some amount of overlap with
1634 * existing call member variables, but this duplication helps to ensure that none of these logging
1635 * variables will interface with/and affect call logic.
1636 */
1637 public static class LogState {
1638
1639 public DisconnectCause disconnectCause;
1640 public boolean isIncoming = false;
Eric Erfanian8369df02017-05-03 10:27:13 -07001641 public ContactLookupResult.Type contactLookupResult =
1642 ContactLookupResult.Type.UNKNOWN_LOOKUP_RESULT_TYPE;
Eric Erfanianccca3152017-02-22 16:32:36 -08001643 public CallSpecificAppData callSpecificAppData;
1644 // If this was a conference call, the total number of calls involved in the conference.
1645 public int conferencedCalls = 0;
1646 public long duration = 0;
1647 public boolean isLogged = false;
1648
Eric Erfanian8369df02017-05-03 10:27:13 -07001649 private static String lookupToString(ContactLookupResult.Type lookupType) {
Eric Erfanianccca3152017-02-22 16:32:36 -08001650 switch (lookupType) {
Eric Erfanian8369df02017-05-03 10:27:13 -07001651 case LOCAL_CONTACT:
Eric Erfanianccca3152017-02-22 16:32:36 -08001652 return "Local";
Eric Erfanian8369df02017-05-03 10:27:13 -07001653 case LOCAL_CACHE:
Eric Erfanianccca3152017-02-22 16:32:36 -08001654 return "Cache";
Eric Erfanian8369df02017-05-03 10:27:13 -07001655 case REMOTE:
Eric Erfanianccca3152017-02-22 16:32:36 -08001656 return "Remote";
Eric Erfanian8369df02017-05-03 10:27:13 -07001657 case EMERGENCY:
Eric Erfanianccca3152017-02-22 16:32:36 -08001658 return "Emergency";
Eric Erfanian8369df02017-05-03 10:27:13 -07001659 case VOICEMAIL:
Eric Erfanianccca3152017-02-22 16:32:36 -08001660 return "Voicemail";
1661 default:
1662 return "Not found";
1663 }
1664 }
1665
1666 private static String initiationToString(CallSpecificAppData callSpecificAppData) {
1667 if (callSpecificAppData == null) {
1668 return "null";
1669 }
Eric Erfanian8369df02017-05-03 10:27:13 -07001670 switch (callSpecificAppData.getCallInitiationType()) {
1671 case INCOMING_INITIATION:
Eric Erfanianccca3152017-02-22 16:32:36 -08001672 return "Incoming";
Eric Erfanian8369df02017-05-03 10:27:13 -07001673 case DIALPAD:
Eric Erfanianccca3152017-02-22 16:32:36 -08001674 return "Dialpad";
Eric Erfanian8369df02017-05-03 10:27:13 -07001675 case SPEED_DIAL:
Eric Erfanianccca3152017-02-22 16:32:36 -08001676 return "Speed Dial";
Eric Erfanian8369df02017-05-03 10:27:13 -07001677 case REMOTE_DIRECTORY:
Eric Erfanianccca3152017-02-22 16:32:36 -08001678 return "Remote Directory";
Eric Erfanian8369df02017-05-03 10:27:13 -07001679 case SMART_DIAL:
Eric Erfanianccca3152017-02-22 16:32:36 -08001680 return "Smart Dial";
Eric Erfanian8369df02017-05-03 10:27:13 -07001681 case REGULAR_SEARCH:
Eric Erfanianccca3152017-02-22 16:32:36 -08001682 return "Regular Search";
Eric Erfanian8369df02017-05-03 10:27:13 -07001683 case CALL_LOG:
Eric Erfanianccca3152017-02-22 16:32:36 -08001684 return "DialerCall Log";
Eric Erfanian8369df02017-05-03 10:27:13 -07001685 case CALL_LOG_FILTER:
Eric Erfanianccca3152017-02-22 16:32:36 -08001686 return "DialerCall Log Filter";
Eric Erfanian8369df02017-05-03 10:27:13 -07001687 case VOICEMAIL_LOG:
Eric Erfanianccca3152017-02-22 16:32:36 -08001688 return "Voicemail Log";
Eric Erfanian8369df02017-05-03 10:27:13 -07001689 case CALL_DETAILS:
Eric Erfanianccca3152017-02-22 16:32:36 -08001690 return "DialerCall Details";
Eric Erfanian8369df02017-05-03 10:27:13 -07001691 case QUICK_CONTACTS:
Eric Erfanianccca3152017-02-22 16:32:36 -08001692 return "Quick Contacts";
Eric Erfanian8369df02017-05-03 10:27:13 -07001693 case EXTERNAL_INITIATION:
Eric Erfanianccca3152017-02-22 16:32:36 -08001694 return "External";
Eric Erfanian8369df02017-05-03 10:27:13 -07001695 case LAUNCHER_SHORTCUT:
Eric Erfanianccca3152017-02-22 16:32:36 -08001696 return "Launcher Shortcut";
1697 default:
Eric Erfanian8369df02017-05-03 10:27:13 -07001698 return "Unknown: " + callSpecificAppData.getCallInitiationType();
Eric Erfanianccca3152017-02-22 16:32:36 -08001699 }
1700 }
1701
1702 @Override
1703 public String toString() {
1704 return String.format(
1705 Locale.US,
1706 "["
1707 + "%s, " // DisconnectCause toString already describes the object type
1708 + "isIncoming: %s, "
1709 + "contactLookup: %s, "
1710 + "callInitiation: %s, "
1711 + "duration: %s"
1712 + "]",
1713 disconnectCause,
1714 isIncoming,
1715 lookupToString(contactLookupResult),
1716 initiationToString(callSpecificAppData),
1717 duration);
1718 }
1719 }
1720
roldenburgd7490db2018-01-09 13:51:29 -08001721 /** Coordinates the available VideoTech implementations for a call. */
1722 @VisibleForTesting
1723 public static class VideoTechManager {
Eric Erfaniand8046e52017-04-06 09:41:50 -07001724 private final Context context;
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001725 private final EmptyVideoTech emptyVideoTech = new EmptyVideoTech();
roldenburgd7490db2018-01-09 13:51:29 -08001726 private final VideoTech rcsVideoShare;
Eric Erfanian90508232017-03-24 09:31:16 -07001727 private final List<VideoTech> videoTechs;
roldenburg7bb96232017-10-09 10:32:05 -07001728 private VideoTech savedTech;
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001729
roldenburgd7490db2018-01-09 13:51:29 -08001730 @VisibleForTesting
1731 public VideoTechManager(DialerCall call) {
linyuh183cb712017-12-27 17:02:37 -08001732 this.context = call.context;
Eric Erfaniand8046e52017-04-06 09:41:50 -07001733
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001734 String phoneNumber = call.getNumber();
Eric Erfaniand8046e52017-04-06 09:41:50 -07001735 phoneNumber = phoneNumber != null ? phoneNumber : "";
Eric Erfanian2ca43182017-08-31 06:57:16 -07001736 phoneNumber = phoneNumber.replaceAll("[^+0-9]", "");
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001737
1738 // Insert order here determines the priority of that video tech option
Eric Erfanian8369df02017-05-03 10:27:13 -07001739 videoTechs = new ArrayList<>();
yueg457b3972017-09-18 15:11:47 -07001740
linyuh183cb712017-12-27 17:02:37 -08001741 videoTechs.add(new ImsVideoTech(Logger.get(call.context), call, call.telecomCall));
Eric Erfanian90508232017-03-24 09:31:16 -07001742
roldenburgd7490db2018-01-09 13:51:29 -08001743 rcsVideoShare =
linyuh183cb712017-12-27 17:02:37 -08001744 EnrichedCallComponent.get(call.context)
Eric Erfanian90508232017-03-24 09:31:16 -07001745 .getRcsVideoShareFactory()
1746 .newRcsVideoShare(
linyuh183cb712017-12-27 17:02:37 -08001747 EnrichedCallComponent.get(call.context).getEnrichedCallManager(),
Eric Erfanian90508232017-03-24 09:31:16 -07001748 call,
Eric Erfaniand8046e52017-04-06 09:41:50 -07001749 phoneNumber);
roldenburg3eca69f2018-01-16 12:07:04 -08001750 videoTechs.add(rcsVideoShare);
Eric Erfaniand8046e52017-04-06 09:41:50 -07001751
1752 videoTechs.add(
roldenburg4f026392017-10-13 18:42:20 -07001753 new DuoVideoTech(
linyuh183cb712017-12-27 17:02:37 -08001754 DuoComponent.get(call.context).getDuo(), call, call.telecomCall, phoneNumber));
roldenburgd7490db2018-01-09 13:51:29 -08001755
1756 savedTech = emptyVideoTech;
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001757 }
1758
roldenburgd7490db2018-01-09 13:51:29 -08001759 @VisibleForTesting
roldenburg6bd612f2018-01-18 12:57:19 -08001760 public VideoTech getVideoTech(PhoneAccountHandle phoneAccountHandle) {
roldenburgd7490db2018-01-09 13:51:29 -08001761 if (savedTech == emptyVideoTech) {
1762 for (VideoTech tech : videoTechs) {
roldenburg6bd612f2018-01-18 12:57:19 -08001763 if (tech.isAvailable(context, phoneAccountHandle)) {
roldenburgd7490db2018-01-09 13:51:29 -08001764 savedTech = tech;
1765 savedTech.becomePrimary();
1766 break;
1767 }
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001768 }
roldenburg6bd612f2018-01-18 12:57:19 -08001769 } else if (savedTech instanceof DuoVideoTech
1770 && rcsVideoShare.isAvailable(context, phoneAccountHandle)) {
roldenburgd7490db2018-01-09 13:51:29 -08001771 // RCS Video Share will become available after the capability exchange which is slower than
1772 // Duo reading local contacts for reachability. If Video Share becomes available and we are
1773 // not in the middle of any session changes, let it take over.
1774 savedTech = rcsVideoShare;
1775 rcsVideoShare.becomePrimary();
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001776 }
1777
roldenburgd7490db2018-01-09 13:51:29 -08001778 return savedTech;
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001779 }
1780
roldenburgd7490db2018-01-09 13:51:29 -08001781 @VisibleForTesting
roldenburg6bd612f2018-01-18 12:57:19 -08001782 public void dispatchCallStateChanged(int newState, PhoneAccountHandle phoneAccountHandle) {
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001783 for (VideoTech videoTech : videoTechs) {
roldenburg6bd612f2018-01-18 12:57:19 -08001784 videoTech.onCallStateChanged(context, newState, phoneAccountHandle);
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001785 }
1786 }
Eric Erfanian2ca43182017-08-31 06:57:16 -07001787
1788 void dispatchRemovedFromCallList() {
1789 for (VideoTech videoTech : videoTechs) {
1790 videoTech.onRemovedFromCallList();
1791 }
1792 }
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001793 }
1794
Eric Erfanianccca3152017-02-22 16:32:36 -08001795 /** Called when canned text responses have been loaded. */
1796 public interface CannedTextResponsesLoadedListener {
1797 void onCannedTextResponsesLoaded(DialerCall call);
1798 }
1799}