blob: 5d2b1471d98beec1c9f62a5870bf0410236b3884 [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
linyuh183cb712017-12-27 17:02:37 -0800139 private boolean isEmergencyCall;
140 private Uri handle;
141 private int state = State.INVALID;
142 private DisconnectCause disconnectCause;
Eric Erfanianccca3152017-02-22 16:32:36 -0800143
144 private boolean hasShownWiFiToLteHandoverToast;
145 private boolean doNotShowDialogForHandoffToWifiFailure;
146
linyuh183cb712017-12-27 17:02:37 -0800147 private String childNumber;
148 private String lastForwardedNumber;
wangqif4ba3452018-01-09 11:26:29 -0800149 private boolean isCallForwarded;
linyuh183cb712017-12-27 17:02:37 -0800150 private String callSubject;
151 private PhoneAccountHandle phoneAccountHandle;
152 @CallHistoryStatus private int callHistoryStatus = CALL_HISTORY_STATUS_UNKNOWN;
153 private boolean isSpam;
154 private boolean isBlocked;
Eric Erfanian938468d2017-10-24 14:05:52 -0700155
156 @Nullable private Boolean isInUserSpamList;
157
158 @Nullable private Boolean isInUserWhiteList;
159
160 @Nullable private Boolean isInGlobalSpamList;
Eric Erfanianccca3152017-02-22 16:32:36 -0800161 private boolean didShowCameraPermission;
wangqida410d32018-03-06 16:51:38 -0800162 private boolean didDismissVideoChargesAlertDialog;
163 private PersistableBundle carrierConfig;
Eric Erfanianccca3152017-02-22 16:32:36 -0800164 private String callProviderLabel;
165 private String callbackNumber;
linyuh183cb712017-12-27 17:02:37 -0800166 private int cameraDirection = CameraDirection.CAMERA_DIRECTION_UNKNOWN;
167 private EnrichedCallCapabilities enrichedCallCapabilities;
168 private Session enrichedCallSession;
Eric Erfanianccca3152017-02-22 16:32:36 -0800169
Eric Erfanian2ca43182017-08-31 06:57:16 -0700170 private int answerAndReleaseButtonDisplayedTimes = 0;
171 private boolean releasedByAnsweringSecondCall = false;
172 // Times when a second call is received but AnswerAndRelease button is not shown
173 // since it's not supported.
174 private int secondCallWithoutAnswerAndReleasedButtonTimes = 0;
roldenburg7bb96232017-10-09 10:32:05 -0700175 private VideoTech videoTech;
Eric Erfanian2ca43182017-08-31 06:57:16 -0700176
wangqi4d705e52017-09-28 12:23:35 -0700177 private com.android.dialer.logging.VideoTech.Type selectedAvailableVideoTechType =
178 com.android.dialer.logging.VideoTech.Type.NONE;
wangqi9982f0d2017-10-11 17:46:07 -0700179 private boolean isVoicemailNumber;
180 private List<PhoneAccountHandle> callCapableAccounts;
181 private String countryIso;
yueg457b3972017-09-18 15:11:47 -0700182
Android Dialer974fc292018-02-01 16:12:25 -0800183 private volatile boolean feedbackRequested = false;
184
twyen73a74c32018-03-07 12:12:24 -0800185 @Nullable private PreferredAccountRecorder preferredAccountRecorder;
186
Eric Erfanianccca3152017-02-22 16:32:36 -0800187 public static String getNumberFromHandle(Uri handle) {
188 return handle == null ? "" : handle.getSchemeSpecificPart();
189 }
190
191 /**
192 * Whether the call is put on hold by remote party. This is different than the {@link
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700193 * State#ONHOLD} state which indicates that the call is being held locally on the device.
Eric Erfanianccca3152017-02-22 16:32:36 -0800194 */
195 private boolean isRemotelyHeld;
196
Eric Erfanian2ca43182017-08-31 06:57:16 -0700197 /** Indicates whether this call is currently in the process of being merged into a conference. */
198 private boolean isMergeInProcess;
199
Eric Erfanianccca3152017-02-22 16:32:36 -0800200 /**
201 * Indicates whether the phone account associated with this call supports specifying a call
202 * subject.
203 */
linyuh183cb712017-12-27 17:02:37 -0800204 private boolean isCallSubjectSupported;
Eric Erfanianccca3152017-02-22 16:32:36 -0800205
linyuh183cb712017-12-27 17:02:37 -0800206 private final Call.Callback telecomCallCallback =
Eric Erfanianccca3152017-02-22 16:32:36 -0800207 new Call.Callback() {
208 @Override
209 public void onStateChanged(Call call, int newState) {
210 LogUtil.v("TelecomCallCallback.onStateChanged", "call=" + call + " newState=" + newState);
211 update();
212 }
213
214 @Override
215 public void onParentChanged(Call call, Call newParent) {
216 LogUtil.v(
217 "TelecomCallCallback.onParentChanged", "call=" + call + " newParent=" + newParent);
218 update();
219 }
220
221 @Override
222 public void onChildrenChanged(Call call, List<Call> children) {
223 update();
224 }
225
226 @Override
227 public void onDetailsChanged(Call call, Call.Details details) {
Eric Erfanian2ca43182017-08-31 06:57:16 -0700228 LogUtil.v(
229 "TelecomCallCallback.onDetailsChanged", " call=" + call + " details=" + details);
Eric Erfanianccca3152017-02-22 16:32:36 -0800230 update();
231 }
232
233 @Override
234 public void onCannedTextResponsesLoaded(Call call, List<String> cannedTextResponses) {
235 LogUtil.v(
Eric Erfanian2ca43182017-08-31 06:57:16 -0700236 "TelecomCallCallback.onCannedTextResponsesLoaded",
Eric Erfanianccca3152017-02-22 16:32:36 -0800237 "call=" + call + " cannedTextResponses=" + cannedTextResponses);
linyuh183cb712017-12-27 17:02:37 -0800238 for (CannedTextResponsesLoadedListener listener : cannedTextResponsesLoadedListeners) {
Eric Erfanianccca3152017-02-22 16:32:36 -0800239 listener.onCannedTextResponsesLoaded(DialerCall.this);
240 }
241 }
242
243 @Override
244 public void onPostDialWait(Call call, String remainingPostDialSequence) {
245 LogUtil.v(
Eric Erfanian2ca43182017-08-31 06:57:16 -0700246 "TelecomCallCallback.onPostDialWait",
Eric Erfanianccca3152017-02-22 16:32:36 -0800247 "call=" + call + " remainingPostDialSequence=" + remainingPostDialSequence);
248 update();
249 }
250
251 @Override
252 public void onVideoCallChanged(Call call, VideoCall videoCall) {
253 LogUtil.v(
Eric Erfanian2ca43182017-08-31 06:57:16 -0700254 "TelecomCallCallback.onVideoCallChanged", "call=" + call + " videoCall=" + videoCall);
Eric Erfanianccca3152017-02-22 16:32:36 -0800255 update();
256 }
257
258 @Override
259 public void onCallDestroyed(Call call) {
Eric Erfanian2ca43182017-08-31 06:57:16 -0700260 LogUtil.v("TelecomCallCallback.onCallDestroyed", "call=" + call);
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700261 unregisterCallback();
Eric Erfanianccca3152017-02-22 16:32:36 -0800262 }
263
264 @Override
265 public void onConferenceableCallsChanged(Call call, List<Call> conferenceableCalls) {
266 LogUtil.v(
Eric Erfanian2ca43182017-08-31 06:57:16 -0700267 "TelecomCallCallback.onConferenceableCallsChanged",
Eric Erfanianccca3152017-02-22 16:32:36 -0800268 "call %s, conferenceable calls: %d",
269 call,
270 conferenceableCalls.size());
271 update();
272 }
273
274 @Override
wangqi219b8702018-02-13 09:34:41 -0800275 public void onRttModeChanged(Call call, int mode) {
276 LogUtil.v("TelecomCallCallback.onRttModeChanged", "mode=%d", mode);
277 }
278
279 @Override
280 public void onRttRequest(Call call, int id) {
281 LogUtil.v("TelecomCallCallback.onRttRequest", "id=%d", id);
282 }
283
284 @Override
285 public void onRttInitiationFailure(Call call, int reason) {
286 LogUtil.v("TelecomCallCallback.onRttInitiationFailure", "reason=%d", reason);
287 update();
288 }
289
290 @Override
291 public void onRttStatusChanged(Call call, boolean enabled, RttCall rttCall) {
292 LogUtil.v("TelecomCallCallback.onRttStatusChanged", "enabled=%b", enabled);
293 update();
294 }
295
296 @Override
Eric Erfanianccca3152017-02-22 16:32:36 -0800297 public void onConnectionEvent(android.telecom.Call call, String event, Bundle extras) {
298 LogUtil.v(
Eric Erfanian2ca43182017-08-31 06:57:16 -0700299 "TelecomCallCallback.onConnectionEvent",
Eric Erfanianccca3152017-02-22 16:32:36 -0800300 "Call: " + call + ", Event: " + event + ", Extras: " + extras);
301 switch (event) {
302 // The Previous attempt to Merge two calls together has failed in Telecom. We must
303 // now update the UI to possibly re-enable the Merge button based on the number of
304 // currently conferenceable calls available or Connection Capabilities.
305 case android.telecom.Connection.EVENT_CALL_MERGE_FAILED:
306 update();
307 break;
308 case TelephonyManagerCompat.EVENT_HANDOVER_VIDEO_FROM_WIFI_TO_LTE:
309 notifyWiFiToLteHandover();
310 break;
311 case TelephonyManagerCompat.EVENT_HANDOVER_TO_WIFI_FAILED:
312 notifyHandoverToWifiFailed();
313 break;
314 case TelephonyManagerCompat.EVENT_CALL_REMOTELY_HELD:
315 isRemotelyHeld = true;
316 update();
317 break;
318 case TelephonyManagerCompat.EVENT_CALL_REMOTELY_UNHELD:
319 isRemotelyHeld = false;
320 update();
321 break;
Eric Erfanianc857f902017-05-15 14:05:33 -0700322 case TelephonyManagerCompat.EVENT_NOTIFY_INTERNATIONAL_CALL_ON_WFC:
323 notifyInternationalCallOnWifi();
324 break;
Eric Erfanian2ca43182017-08-31 06:57:16 -0700325 case TelephonyManagerCompat.EVENT_MERGE_START:
326 LogUtil.i("DialerCall.onConnectionEvent", "merge start");
327 isMergeInProcess = true;
328 break;
329 case TelephonyManagerCompat.EVENT_MERGE_COMPLETE:
330 LogUtil.i("DialerCall.onConnectionEvent", "merge complete");
331 isMergeInProcess = false;
332 break;
wangqif4ba3452018-01-09 11:26:29 -0800333 case TelephonyManagerCompat.EVENT_CALL_FORWARDED:
334 // Only handle this event for P+ since it's unreliable pre-P.
335 if (BuildCompat.isAtLeastP()) {
336 isCallForwarded = true;
337 update();
338 }
339 break;
Eric Erfanianccca3152017-02-22 16:32:36 -0800340 default:
341 break;
342 }
343 }
344 };
Eric Erfanianc857f902017-05-15 14:05:33 -0700345
linyuh183cb712017-12-27 17:02:37 -0800346 private long timeAddedMs;
Eric Erfanianccca3152017-02-22 16:32:36 -0800347
348 public DialerCall(
349 Context context,
350 DialerCallDelegate dialerCallDelegate,
351 Call telecomCall,
352 LatencyReport latencyReport,
353 boolean registerCallback) {
354 Assert.isNotNull(context);
linyuh183cb712017-12-27 17:02:37 -0800355 this.context = context;
356 this.dialerCallDelegate = dialerCallDelegate;
357 this.telecomCall = telecomCall;
358 this.latencyReport = latencyReport;
359 id = ID_PREFIX + Integer.toString(idCounter++);
Eric Erfanianccca3152017-02-22 16:32:36 -0800360
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700361 // Must be after assigning mTelecomCall
linyuh183cb712017-12-27 17:02:37 -0800362 videoTechManager = new VideoTechManager(this);
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700363
364 updateFromTelecomCall();
Eric Erfanianc857f902017-05-15 14:05:33 -0700365 if (isHiddenNumber() && TextUtils.isEmpty(getNumber())) {
linyuh183cb712017-12-27 17:02:37 -0800366 hiddenId = ++hiddenCounter;
Eric Erfanianc857f902017-05-15 14:05:33 -0700367 } else {
linyuh183cb712017-12-27 17:02:37 -0800368 hiddenId = 0;
Eric Erfanianc857f902017-05-15 14:05:33 -0700369 }
Eric Erfanianccca3152017-02-22 16:32:36 -0800370
371 if (registerCallback) {
linyuh183cb712017-12-27 17:02:37 -0800372 this.telecomCall.registerCallback(telecomCallCallback);
Eric Erfanianccca3152017-02-22 16:32:36 -0800373 }
374
linyuh183cb712017-12-27 17:02:37 -0800375 timeAddedMs = System.currentTimeMillis();
Eric Erfanianccca3152017-02-22 16:32:36 -0800376 parseCallSpecificAppData();
Eric Erfanian2ca43182017-08-31 06:57:16 -0700377
378 updateEnrichedCallSession();
Eric Erfanianccca3152017-02-22 16:32:36 -0800379 }
380
twyendde01c52017-09-22 10:07:31 -0700381 /** Test only constructor to avoid initializing dependencies. */
382 @VisibleForTesting
383 DialerCall(Context context) {
linyuh183cb712017-12-27 17:02:37 -0800384 this.context = context;
385 telecomCall = null;
386 latencyReport = null;
387 id = null;
388 hiddenId = 0;
389 dialerCallDelegate = null;
390 videoTechManager = null;
twyendde01c52017-09-22 10:07:31 -0700391 }
392
Eric Erfanianccca3152017-02-22 16:32:36 -0800393 private static int translateState(int state) {
394 switch (state) {
395 case Call.STATE_NEW:
396 case Call.STATE_CONNECTING:
397 return DialerCall.State.CONNECTING;
398 case Call.STATE_SELECT_PHONE_ACCOUNT:
399 return DialerCall.State.SELECT_PHONE_ACCOUNT;
400 case Call.STATE_DIALING:
401 return DialerCall.State.DIALING;
402 case Call.STATE_PULLING_CALL:
403 return DialerCall.State.PULLING;
404 case Call.STATE_RINGING:
405 return DialerCall.State.INCOMING;
406 case Call.STATE_ACTIVE:
407 return DialerCall.State.ACTIVE;
408 case Call.STATE_HOLDING:
409 return DialerCall.State.ONHOLD;
410 case Call.STATE_DISCONNECTED:
411 return DialerCall.State.DISCONNECTED;
412 case Call.STATE_DISCONNECTING:
413 return DialerCall.State.DISCONNECTING;
414 default:
415 return DialerCall.State.INVALID;
416 }
417 }
418
419 public static boolean areSame(DialerCall call1, DialerCall call2) {
420 if (call1 == null && call2 == null) {
421 return true;
422 } else if (call1 == null || call2 == null) {
423 return false;
424 }
425
426 // otherwise compare call Ids
427 return call1.getId().equals(call2.getId());
428 }
429
Eric Erfanianccca3152017-02-22 16:32:36 -0800430 public void addListener(DialerCallListener listener) {
431 Assert.isMainThread();
linyuh183cb712017-12-27 17:02:37 -0800432 listeners.add(listener);
Eric Erfanianccca3152017-02-22 16:32:36 -0800433 }
434
435 public void removeListener(DialerCallListener listener) {
436 Assert.isMainThread();
linyuh183cb712017-12-27 17:02:37 -0800437 listeners.remove(listener);
Eric Erfanianccca3152017-02-22 16:32:36 -0800438 }
439
440 public void addCannedTextResponsesLoadedListener(CannedTextResponsesLoadedListener listener) {
441 Assert.isMainThread();
linyuh183cb712017-12-27 17:02:37 -0800442 cannedTextResponsesLoadedListeners.add(listener);
Eric Erfanianccca3152017-02-22 16:32:36 -0800443 }
444
445 public void removeCannedTextResponsesLoadedListener(CannedTextResponsesLoadedListener listener) {
446 Assert.isMainThread();
linyuh183cb712017-12-27 17:02:37 -0800447 cannedTextResponsesLoadedListeners.remove(listener);
Eric Erfanianccca3152017-02-22 16:32:36 -0800448 }
449
450 public void notifyWiFiToLteHandover() {
451 LogUtil.i("DialerCall.notifyWiFiToLteHandover", "");
linyuh183cb712017-12-27 17:02:37 -0800452 for (DialerCallListener listener : listeners) {
Eric Erfanianccca3152017-02-22 16:32:36 -0800453 listener.onWiFiToLteHandover();
454 }
455 }
456
457 public void notifyHandoverToWifiFailed() {
458 LogUtil.i("DialerCall.notifyHandoverToWifiFailed", "");
linyuh183cb712017-12-27 17:02:37 -0800459 for (DialerCallListener listener : listeners) {
Eric Erfanianccca3152017-02-22 16:32:36 -0800460 listener.onHandoverToWifiFailure();
461 }
462 }
463
Eric Erfanianc857f902017-05-15 14:05:33 -0700464 public void notifyInternationalCallOnWifi() {
465 LogUtil.enterBlock("DialerCall.notifyInternationalCallOnWifi");
linyuh183cb712017-12-27 17:02:37 -0800466 for (DialerCallListener dialerCallListener : listeners) {
Eric Erfanianc857f902017-05-15 14:05:33 -0700467 dialerCallListener.onInternationalCallOnWifi();
468 }
469 }
470
Eric Erfanianccca3152017-02-22 16:32:36 -0800471 /* package-private */ Call getTelecomCall() {
linyuh183cb712017-12-27 17:02:37 -0800472 return telecomCall;
Eric Erfanianccca3152017-02-22 16:32:36 -0800473 }
wangqida410d32018-03-06 16:51:38 -0800474
Eric Erfanianccca3152017-02-22 16:32:36 -0800475 public StatusHints getStatusHints() {
linyuh183cb712017-12-27 17:02:37 -0800476 return telecomCall.getDetails().getStatusHints();
Eric Erfanianccca3152017-02-22 16:32:36 -0800477 }
478
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700479 public int getCameraDir() {
linyuh183cb712017-12-27 17:02:37 -0800480 return cameraDirection;
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700481 }
482
483 public void setCameraDir(int cameraDir) {
484 if (cameraDir == CameraDirection.CAMERA_DIRECTION_FRONT_FACING
485 || cameraDir == CameraDirection.CAMERA_DIRECTION_BACK_FACING) {
linyuh183cb712017-12-27 17:02:37 -0800486 cameraDirection = cameraDir;
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700487 } else {
linyuh183cb712017-12-27 17:02:37 -0800488 cameraDirection = CameraDirection.CAMERA_DIRECTION_UNKNOWN;
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700489 }
Eric Erfanianccca3152017-02-22 16:32:36 -0800490 }
491
Eric Erfanian2ca43182017-08-31 06:57:16 -0700492 public boolean wasParentCall() {
linyuh183cb712017-12-27 17:02:37 -0800493 return logState.conferencedCalls != 0;
Eric Erfanian2ca43182017-08-31 06:57:16 -0700494 }
495
wangqi9982f0d2017-10-11 17:46:07 -0700496 public boolean isVoiceMailNumber() {
497 return isVoicemailNumber;
498 }
499
500 public List<PhoneAccountHandle> getCallCapableAccounts() {
501 return callCapableAccounts;
502 }
503
504 public String getCountryIso() {
505 return countryIso;
506 }
507
508 private void updateIsVoiceMailNumber() {
509 if (getHandle() != null && PhoneAccount.SCHEME_VOICEMAIL.equals(getHandle().getScheme())) {
510 isVoicemailNumber = true;
roldenburg37a969d2018-02-22 14:46:44 -0800511 return;
wangqi9982f0d2017-10-11 17:46:07 -0700512 }
513
linyuh183cb712017-12-27 17:02:37 -0800514 if (!PermissionsUtil.hasPermission(context, permission.READ_PHONE_STATE)) {
wangqi9982f0d2017-10-11 17:46:07 -0700515 isVoicemailNumber = false;
roldenburg37a969d2018-02-22 14:46:44 -0800516 return;
wangqi9982f0d2017-10-11 17:46:07 -0700517 }
518
linyuh183cb712017-12-27 17:02:37 -0800519 isVoicemailNumber = TelecomUtil.isVoicemailNumber(context, getAccountHandle(), getNumber());
wangqi9982f0d2017-10-11 17:46:07 -0700520 }
521
Eric Erfanianccca3152017-02-22 16:32:36 -0800522 private void update() {
Eric Erfanian2ca43182017-08-31 06:57:16 -0700523 Trace.beginSection("DialerCall.update");
Eric Erfanianccca3152017-02-22 16:32:36 -0800524 int oldState = getState();
roldenburg7bb96232017-10-09 10:32:05 -0700525 // Clear any cache here that could potentially change on update.
526 videoTech = null;
Eric Erfanianccca3152017-02-22 16:32:36 -0800527 // We want to potentially register a video call callback here.
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700528 updateFromTelecomCall();
Eric Erfanianccca3152017-02-22 16:32:36 -0800529 if (oldState != getState() && getState() == DialerCall.State.DISCONNECTED) {
linyuh183cb712017-12-27 17:02:37 -0800530 for (DialerCallListener listener : listeners) {
Eric Erfanianccca3152017-02-22 16:32:36 -0800531 listener.onDialerCallDisconnect();
532 }
linyuh183cb712017-12-27 17:02:37 -0800533 EnrichedCallComponent.get(context)
Eric Erfanian2ca43182017-08-31 06:57:16 -0700534 .getEnrichedCallManager()
535 .unregisterCapabilitiesListener(this);
linyuh183cb712017-12-27 17:02:37 -0800536 EnrichedCallComponent.get(context)
Eric Erfanian2ca43182017-08-31 06:57:16 -0700537 .getEnrichedCallManager()
538 .unregisterStateChangedListener(this);
Eric Erfanianccca3152017-02-22 16:32:36 -0800539 } else {
linyuh183cb712017-12-27 17:02:37 -0800540 for (DialerCallListener listener : listeners) {
Eric Erfanianccca3152017-02-22 16:32:36 -0800541 listener.onDialerCallUpdate();
542 }
543 }
544 Trace.endSection();
545 }
546
wangqi9982f0d2017-10-11 17:46:07 -0700547 @SuppressWarnings("MissingPermission")
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700548 private void updateFromTelecomCall() {
Eric Erfanian2ca43182017-08-31 06:57:16 -0700549 Trace.beginSection("DialerCall.updateFromTelecomCall");
linyuh183cb712017-12-27 17:02:37 -0800550 LogUtil.v("DialerCall.updateFromTelecomCall", telecomCall.toString());
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700551
roldenburg6bd612f2018-01-18 12:57:19 -0800552 videoTechManager.dispatchCallStateChanged(telecomCall.getState(), getAccountHandle());
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700553
linyuh183cb712017-12-27 17:02:37 -0800554 final int translatedState = translateState(telecomCall.getState());
555 if (state != State.BLOCKED) {
Eric Erfanianccca3152017-02-22 16:32:36 -0800556 setState(translatedState);
linyuh183cb712017-12-27 17:02:37 -0800557 setDisconnectCause(telecomCall.getDetails().getDisconnectCause());
Eric Erfanianccca3152017-02-22 16:32:36 -0800558 }
559
linyuh183cb712017-12-27 17:02:37 -0800560 childCallIds.clear();
561 final int numChildCalls = telecomCall.getChildren().size();
Eric Erfanianccca3152017-02-22 16:32:36 -0800562 for (int i = 0; i < numChildCalls; i++) {
linyuh183cb712017-12-27 17:02:37 -0800563 childCallIds.add(
564 dialerCallDelegate
565 .getDialerCallFromTelecomCall(telecomCall.getChildren().get(i))
Eric Erfanianccca3152017-02-22 16:32:36 -0800566 .getId());
567 }
568
569 // The number of conferenced calls can change over the course of the call, so use the
570 // maximum number of conferenced child calls as the metric for conference call usage.
linyuh183cb712017-12-27 17:02:37 -0800571 logState.conferencedCalls = Math.max(numChildCalls, logState.conferencedCalls);
Eric Erfanianccca3152017-02-22 16:32:36 -0800572
linyuh183cb712017-12-27 17:02:37 -0800573 updateFromCallExtras(telecomCall.getDetails().getExtras());
Eric Erfanianccca3152017-02-22 16:32:36 -0800574
575 // If the handle of the call has changed, update state for the call determining if it is an
576 // emergency call.
linyuh183cb712017-12-27 17:02:37 -0800577 Uri newHandle = telecomCall.getDetails().getHandle();
578 if (!Objects.equals(handle, newHandle)) {
579 handle = newHandle;
Eric Erfanianccca3152017-02-22 16:32:36 -0800580 updateEmergencyCallState();
581 }
582
linyuh183cb712017-12-27 17:02:37 -0800583 TelecomManager telecomManager = context.getSystemService(TelecomManager.class);
Eric Erfanianccca3152017-02-22 16:32:36 -0800584 // If the phone account handle of the call is set, cache capability bit indicating whether
585 // the phone account supports call subjects.
linyuh183cb712017-12-27 17:02:37 -0800586 PhoneAccountHandle newPhoneAccountHandle = telecomCall.getDetails().getAccountHandle();
587 if (!Objects.equals(phoneAccountHandle, newPhoneAccountHandle)) {
588 phoneAccountHandle = newPhoneAccountHandle;
Eric Erfanianccca3152017-02-22 16:32:36 -0800589
linyuh183cb712017-12-27 17:02:37 -0800590 if (phoneAccountHandle != null) {
591 PhoneAccount phoneAccount = telecomManager.getPhoneAccount(phoneAccountHandle);
Eric Erfanianccca3152017-02-22 16:32:36 -0800592 if (phoneAccount != null) {
linyuh183cb712017-12-27 17:02:37 -0800593 isCallSubjectSupported =
Eric Erfanianccca3152017-02-22 16:32:36 -0800594 phoneAccount.hasCapabilities(PhoneAccount.CAPABILITY_CALL_SUBJECT);
wangqida410d32018-03-06 16:51:38 -0800595 if (phoneAccount.hasCapabilities(PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION)) {
596 cacheCarrierConfiguration(phoneAccountHandle);
597 }
Eric Erfanianccca3152017-02-22 16:32:36 -0800598 }
599 }
600 }
linyuh183cb712017-12-27 17:02:37 -0800601 if (PermissionsUtil.hasPermission(context, permission.READ_PHONE_STATE)) {
wangqi9982f0d2017-10-11 17:46:07 -0700602 updateIsVoiceMailNumber();
603 callCapableAccounts = telecomManager.getCallCapablePhoneAccounts();
linyuh183cb712017-12-27 17:02:37 -0800604 countryIso = GeoUtil.getCurrentCountryIso(context);
wangqi9982f0d2017-10-11 17:46:07 -0700605 }
Eric Erfanian2ca43182017-08-31 06:57:16 -0700606 Trace.endSection();
Eric Erfanianccca3152017-02-22 16:32:36 -0800607 }
608
609 /**
wangqida410d32018-03-06 16:51:38 -0800610 * Caches frequently used carrier configuration locally.
611 *
612 * @param accountHandle The PhoneAccount handle.
613 */
614 @SuppressLint("MissingPermission")
615 private void cacheCarrierConfiguration(PhoneAccountHandle accountHandle) {
616 if (!PermissionsUtil.hasPermission(context, permission.READ_PHONE_STATE)) {
617 return;
618 }
619 if (VERSION.SDK_INT < VERSION_CODES.O) {
620 return;
621 }
622 // TODO(a bug): This may take several seconds to complete, revisit it to move it to worker
623 // thread.
624 carrierConfig =
625 TelephonyManagerCompat.getTelephonyManagerForPhoneAccountHandle(context, accountHandle)
626 .getCarrierConfig();
627 }
628
629 /**
Eric Erfanianccca3152017-02-22 16:32:36 -0800630 * Tests corruption of the {@code callExtras} bundle by calling {@link
631 * Bundle#containsKey(String)}. If the bundle is corrupted a {@link IllegalArgumentException} will
632 * be thrown and caught by this function.
633 *
634 * @param callExtras the bundle to verify
635 * @return {@code true} if the bundle is corrupted, {@code false} otherwise.
636 */
637 protected boolean areCallExtrasCorrupted(Bundle callExtras) {
638 /**
Eric Erfanian938468d2017-10-24 14:05:52 -0700639 * There's currently a bug in Telephony service (a bug) that could corrupt the extras
Eric Erfanianccca3152017-02-22 16:32:36 -0800640 * bundle, resulting in a IllegalArgumentException while validating data under {@link
641 * Bundle#containsKey(String)}.
642 */
643 try {
644 callExtras.containsKey(Connection.EXTRA_CHILD_ADDRESS);
645 return false;
646 } catch (IllegalArgumentException e) {
647 LogUtil.e(
648 "DialerCall.areCallExtrasCorrupted", "callExtras is corrupted, ignoring exception", e);
649 return true;
650 }
651 }
652
653 protected void updateFromCallExtras(Bundle callExtras) {
654 if (callExtras == null || areCallExtrasCorrupted(callExtras)) {
655 /**
656 * If the bundle is corrupted, abandon information update as a work around. These are not
657 * critical for the dialer to function.
658 */
659 return;
660 }
661 // Check for a change in the child address and notify any listeners.
662 if (callExtras.containsKey(Connection.EXTRA_CHILD_ADDRESS)) {
663 String childNumber = callExtras.getString(Connection.EXTRA_CHILD_ADDRESS);
linyuh183cb712017-12-27 17:02:37 -0800664 if (!Objects.equals(childNumber, this.childNumber)) {
665 this.childNumber = childNumber;
666 for (DialerCallListener listener : listeners) {
Eric Erfanianccca3152017-02-22 16:32:36 -0800667 listener.onDialerCallChildNumberChange();
668 }
669 }
670 }
671
672 // Last forwarded number comes in as an array of strings. We want to choose the
673 // last item in the array. The forwarding numbers arrive independently of when the
674 // call is originally set up, so we need to notify the the UI of the change.
675 if (callExtras.containsKey(Connection.EXTRA_LAST_FORWARDED_NUMBER)) {
676 ArrayList<String> lastForwardedNumbers =
677 callExtras.getStringArrayList(Connection.EXTRA_LAST_FORWARDED_NUMBER);
678
679 if (lastForwardedNumbers != null) {
680 String lastForwardedNumber = null;
681 if (!lastForwardedNumbers.isEmpty()) {
682 lastForwardedNumber = lastForwardedNumbers.get(lastForwardedNumbers.size() - 1);
683 }
684
linyuh183cb712017-12-27 17:02:37 -0800685 if (!Objects.equals(lastForwardedNumber, this.lastForwardedNumber)) {
686 this.lastForwardedNumber = lastForwardedNumber;
687 for (DialerCallListener listener : listeners) {
Eric Erfanianccca3152017-02-22 16:32:36 -0800688 listener.onDialerCallLastForwardedNumberChange();
689 }
690 }
691 }
692 }
693
694 // DialerCall subject is present in the extras at the start of call, so we do not need to
695 // notify any other listeners of this.
696 if (callExtras.containsKey(Connection.EXTRA_CALL_SUBJECT)) {
697 String callSubject = callExtras.getString(Connection.EXTRA_CALL_SUBJECT);
linyuh183cb712017-12-27 17:02:37 -0800698 if (!Objects.equals(this.callSubject, callSubject)) {
699 this.callSubject = callSubject;
Eric Erfanianccca3152017-02-22 16:32:36 -0800700 }
701 }
702 }
703
Eric Erfanianccca3152017-02-22 16:32:36 -0800704 public String getId() {
linyuh183cb712017-12-27 17:02:37 -0800705 return id;
Eric Erfanianccca3152017-02-22 16:32:36 -0800706 }
707
Eric Erfanianc857f902017-05-15 14:05:33 -0700708 /**
709 * @return name appended with a number if the number is restricted/unknown and the user has
710 * received more than one restricted/unknown call.
711 */
712 @Nullable
713 public String updateNameIfRestricted(@Nullable String name) {
linyuh183cb712017-12-27 17:02:37 -0800714 if (name != null && isHiddenNumber() && hiddenId != 0 && hiddenCounter > 1) {
715 return context.getString(R.string.unknown_counter, name, hiddenId);
Eric Erfanianc857f902017-05-15 14:05:33 -0700716 }
717 return name;
718 }
719
720 public static void clearRestrictedCount() {
linyuh183cb712017-12-27 17:02:37 -0800721 hiddenCounter = 0;
Eric Erfanianc857f902017-05-15 14:05:33 -0700722 }
723
724 private boolean isHiddenNumber() {
725 return getNumberPresentation() == TelecomManager.PRESENTATION_RESTRICTED
726 || getNumberPresentation() == TelecomManager.PRESENTATION_UNKNOWN;
727 }
728
Eric Erfanianccca3152017-02-22 16:32:36 -0800729 public boolean hasShownWiFiToLteHandoverToast() {
730 return hasShownWiFiToLteHandoverToast;
731 }
732
733 public void setHasShownWiFiToLteHandoverToast() {
734 hasShownWiFiToLteHandoverToast = true;
735 }
736
737 public boolean showWifiHandoverAlertAsToast() {
738 return doNotShowDialogForHandoffToWifiFailure;
739 }
740
741 public void setDoNotShowDialogForHandoffToWifiFailure(boolean bool) {
742 doNotShowDialogForHandoffToWifiFailure = bool;
743 }
744
wangqida410d32018-03-06 16:51:38 -0800745 public boolean showVideoChargesAlertDialog() {
746 if (carrierConfig == null) {
747 return false;
748 }
749 return carrierConfig.getBoolean(
750 TelephonyManagerCompat.CARRIER_CONFIG_KEY_SHOW_VIDEO_CALL_CHARGES_ALERT_DIALOG_BOOL);
751 }
752
Eric Erfanianccca3152017-02-22 16:32:36 -0800753 public long getTimeAddedMs() {
linyuh183cb712017-12-27 17:02:37 -0800754 return timeAddedMs;
Eric Erfanianccca3152017-02-22 16:32:36 -0800755 }
756
757 @Nullable
758 public String getNumber() {
linyuh183cb712017-12-27 17:02:37 -0800759 return TelecomCallUtil.getNumber(telecomCall);
Eric Erfanianccca3152017-02-22 16:32:36 -0800760 }
761
762 public void blockCall() {
linyuh183cb712017-12-27 17:02:37 -0800763 telecomCall.reject(false, null);
Eric Erfanianccca3152017-02-22 16:32:36 -0800764 setState(State.BLOCKED);
765 }
766
767 @Nullable
768 public Uri getHandle() {
linyuh183cb712017-12-27 17:02:37 -0800769 return telecomCall == null ? null : telecomCall.getDetails().getHandle();
Eric Erfanianccca3152017-02-22 16:32:36 -0800770 }
771
772 public boolean isEmergencyCall() {
linyuh183cb712017-12-27 17:02:37 -0800773 return isEmergencyCall;
Eric Erfanianccca3152017-02-22 16:32:36 -0800774 }
775
776 public boolean isPotentialEmergencyCallback() {
777 // The property PROPERTY_EMERGENCY_CALLBACK_MODE is only set for CDMA calls when the system
778 // is actually in emergency callback mode (ie data is disabled).
779 if (hasProperty(Details.PROPERTY_EMERGENCY_CALLBACK_MODE)) {
780 return true;
781 }
782 // We want to treat any incoming call that arrives a short time after an outgoing emergency call
783 // as a potential emergency callback.
784 if (getExtras() != null
785 && getExtras().getLong(TelecomManagerCompat.EXTRA_LAST_EMERGENCY_CALLBACK_TIME_MILLIS, 0)
786 > 0) {
787 long lastEmergencyCallMillis =
788 getExtras().getLong(TelecomManagerCompat.EXTRA_LAST_EMERGENCY_CALLBACK_TIME_MILLIS, 0);
789 if (isInEmergencyCallbackWindow(lastEmergencyCallMillis)) {
790 return true;
791 }
792 }
793 return false;
794 }
795
796 boolean isInEmergencyCallbackWindow(long timestampMillis) {
797 long emergencyCallbackWindowMillis =
linyuh183cb712017-12-27 17:02:37 -0800798 ConfigProviderBindings.get(context)
Eric Erfanianccca3152017-02-22 16:32:36 -0800799 .getLong(CONFIG_EMERGENCY_CALLBACK_WINDOW_MILLIS, TimeUnit.MINUTES.toMillis(5));
800 return System.currentTimeMillis() - timestampMillis < emergencyCallbackWindowMillis;
801 }
802
803 public int getState() {
linyuh183cb712017-12-27 17:02:37 -0800804 if (telecomCall != null && telecomCall.getParent() != null) {
Eric Erfanianccca3152017-02-22 16:32:36 -0800805 return State.CONFERENCED;
806 } else {
linyuh183cb712017-12-27 17:02:37 -0800807 return state;
Eric Erfanianccca3152017-02-22 16:32:36 -0800808 }
809 }
810
yueg265089a2017-10-06 14:35:15 -0700811 public int getNonConferenceState() {
linyuh183cb712017-12-27 17:02:37 -0800812 return state;
yueg265089a2017-10-06 14:35:15 -0700813 }
814
Eric Erfanianccca3152017-02-22 16:32:36 -0800815 public void setState(int state) {
Eric Erfanian2ca43182017-08-31 06:57:16 -0700816 if (state == State.INCOMING) {
linyuh183cb712017-12-27 17:02:37 -0800817 logState.isIncoming = true;
Eric Erfanian2ca43182017-08-31 06:57:16 -0700818 } else if (state == State.DISCONNECTED) {
819 long newDuration =
Eric Erfanianccca3152017-02-22 16:32:36 -0800820 getConnectTimeMillis() == 0 ? 0 : System.currentTimeMillis() - getConnectTimeMillis();
linyuh183cb712017-12-27 17:02:37 -0800821 if (this.state != state) {
822 logState.duration = newDuration;
Eric Erfanian2ca43182017-08-31 06:57:16 -0700823 } else {
824 LogUtil.i(
825 "DialerCall.setState",
826 "ignoring state transition from DISCONNECTED to DISCONNECTED."
827 + " Duration would have changed from %s to %s",
linyuh183cb712017-12-27 17:02:37 -0800828 logState.duration,
Eric Erfanian2ca43182017-08-31 06:57:16 -0700829 newDuration);
830 }
Eric Erfanianccca3152017-02-22 16:32:36 -0800831 }
linyuh183cb712017-12-27 17:02:37 -0800832 this.state = state;
Eric Erfanianccca3152017-02-22 16:32:36 -0800833 }
834
835 public int getNumberPresentation() {
linyuh183cb712017-12-27 17:02:37 -0800836 return telecomCall == null ? -1 : telecomCall.getDetails().getHandlePresentation();
Eric Erfanianccca3152017-02-22 16:32:36 -0800837 }
838
839 public int getCnapNamePresentation() {
linyuh183cb712017-12-27 17:02:37 -0800840 return telecomCall == null ? -1 : telecomCall.getDetails().getCallerDisplayNamePresentation();
Eric Erfanianccca3152017-02-22 16:32:36 -0800841 }
842
843 @Nullable
844 public String getCnapName() {
linyuh183cb712017-12-27 17:02:37 -0800845 return telecomCall == null ? null : getTelecomCall().getDetails().getCallerDisplayName();
Eric Erfanianccca3152017-02-22 16:32:36 -0800846 }
847
848 public Bundle getIntentExtras() {
linyuh183cb712017-12-27 17:02:37 -0800849 return telecomCall.getDetails().getIntentExtras();
Eric Erfanianccca3152017-02-22 16:32:36 -0800850 }
851
852 @Nullable
853 public Bundle getExtras() {
linyuh183cb712017-12-27 17:02:37 -0800854 return telecomCall == null ? null : telecomCall.getDetails().getExtras();
Eric Erfanianccca3152017-02-22 16:32:36 -0800855 }
856
857 /** @return The child number for the call, or {@code null} if none specified. */
858 public String getChildNumber() {
linyuh183cb712017-12-27 17:02:37 -0800859 return childNumber;
Eric Erfanianccca3152017-02-22 16:32:36 -0800860 }
861
862 /** @return The last forwarded number for the call, or {@code null} if none specified. */
863 public String getLastForwardedNumber() {
linyuh183cb712017-12-27 17:02:37 -0800864 return lastForwardedNumber;
Eric Erfanianccca3152017-02-22 16:32:36 -0800865 }
866
wangqif4ba3452018-01-09 11:26:29 -0800867 public boolean isCallForwarded() {
868 return isCallForwarded;
869 }
870
Eric Erfanianccca3152017-02-22 16:32:36 -0800871 /** @return The call subject, or {@code null} if none specified. */
872 public String getCallSubject() {
linyuh183cb712017-12-27 17:02:37 -0800873 return callSubject;
Eric Erfanianccca3152017-02-22 16:32:36 -0800874 }
875
876 /**
877 * @return {@code true} if the call's phone account supports call subjects, {@code false}
878 * otherwise.
879 */
880 public boolean isCallSubjectSupported() {
linyuh183cb712017-12-27 17:02:37 -0800881 return isCallSubjectSupported;
Eric Erfanianccca3152017-02-22 16:32:36 -0800882 }
883
884 /** Returns call disconnect cause, defined by {@link DisconnectCause}. */
885 public DisconnectCause getDisconnectCause() {
linyuh183cb712017-12-27 17:02:37 -0800886 if (state == State.DISCONNECTED || state == State.IDLE) {
887 return disconnectCause;
Eric Erfanianccca3152017-02-22 16:32:36 -0800888 }
889
890 return new DisconnectCause(DisconnectCause.UNKNOWN);
891 }
892
893 public void setDisconnectCause(DisconnectCause disconnectCause) {
linyuh183cb712017-12-27 17:02:37 -0800894 this.disconnectCause = disconnectCause;
895 logState.disconnectCause = this.disconnectCause;
Eric Erfanianccca3152017-02-22 16:32:36 -0800896 }
897
898 /** Returns the possible text message responses. */
899 public List<String> getCannedSmsResponses() {
linyuh183cb712017-12-27 17:02:37 -0800900 return telecomCall.getCannedTextResponses();
Eric Erfanianccca3152017-02-22 16:32:36 -0800901 }
902
903 /** Checks if the call supports the given set of capabilities supplied as a bit mask. */
904 public boolean can(int capabilities) {
linyuh183cb712017-12-27 17:02:37 -0800905 int supportedCapabilities = telecomCall.getDetails().getCallCapabilities();
Eric Erfanianccca3152017-02-22 16:32:36 -0800906
907 if ((capabilities & Call.Details.CAPABILITY_MERGE_CONFERENCE) != 0) {
908 // We allow you to merge if the capabilities allow it or if it is a call with
909 // conferenceable calls.
linyuh183cb712017-12-27 17:02:37 -0800910 if (telecomCall.getConferenceableCalls().isEmpty()
Eric Erfanianccca3152017-02-22 16:32:36 -0800911 && ((Call.Details.CAPABILITY_MERGE_CONFERENCE & supportedCapabilities) == 0)) {
912 // Cannot merge calls if there are no calls to merge with.
913 return false;
914 }
915 capabilities &= ~Call.Details.CAPABILITY_MERGE_CONFERENCE;
916 }
917 return (capabilities == (capabilities & supportedCapabilities));
918 }
919
920 public boolean hasProperty(int property) {
linyuh183cb712017-12-27 17:02:37 -0800921 return telecomCall.getDetails().hasProperty(property);
Eric Erfanianccca3152017-02-22 16:32:36 -0800922 }
923
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700924 @NonNull
Eric Erfanianccca3152017-02-22 16:32:36 -0800925 public String getUniqueCallId() {
926 return uniqueCallId;
927 }
928
929 /** Gets the time when the call first became active. */
930 public long getConnectTimeMillis() {
linyuh183cb712017-12-27 17:02:37 -0800931 return telecomCall.getDetails().getConnectTimeMillis();
Eric Erfanianccca3152017-02-22 16:32:36 -0800932 }
933
934 public boolean isConferenceCall() {
935 return hasProperty(Call.Details.PROPERTY_CONFERENCE);
936 }
937
938 @Nullable
939 public GatewayInfo getGatewayInfo() {
linyuh183cb712017-12-27 17:02:37 -0800940 return telecomCall == null ? null : telecomCall.getDetails().getGatewayInfo();
Eric Erfanianccca3152017-02-22 16:32:36 -0800941 }
942
943 @Nullable
944 public PhoneAccountHandle getAccountHandle() {
linyuh183cb712017-12-27 17:02:37 -0800945 return telecomCall == null ? null : telecomCall.getDetails().getAccountHandle();
Eric Erfanianccca3152017-02-22 16:32:36 -0800946 }
947
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700948 /** @return The {@link VideoCall} instance associated with the {@link Call}. */
Eric Erfanianccca3152017-02-22 16:32:36 -0800949 public VideoCall getVideoCall() {
linyuh183cb712017-12-27 17:02:37 -0800950 return telecomCall == null ? null : telecomCall.getVideoCall();
Eric Erfanianccca3152017-02-22 16:32:36 -0800951 }
952
953 public List<String> getChildCallIds() {
linyuh183cb712017-12-27 17:02:37 -0800954 return childCallIds;
Eric Erfanianccca3152017-02-22 16:32:36 -0800955 }
956
957 public String getParentId() {
linyuh183cb712017-12-27 17:02:37 -0800958 Call parentCall = telecomCall.getParent();
Eric Erfanianccca3152017-02-22 16:32:36 -0800959 if (parentCall != null) {
linyuh183cb712017-12-27 17:02:37 -0800960 return dialerCallDelegate.getDialerCallFromTelecomCall(parentCall).getId();
Eric Erfanianccca3152017-02-22 16:32:36 -0800961 }
962 return null;
963 }
964
965 public int getVideoState() {
linyuh183cb712017-12-27 17:02:37 -0800966 return telecomCall.getDetails().getVideoState();
Eric Erfanianccca3152017-02-22 16:32:36 -0800967 }
968
969 public boolean isVideoCall() {
roldenburg2cec3802017-10-11 16:26:51 -0700970 return getVideoTech().isTransmittingOrReceiving() || VideoProfile.isVideo(getVideoState());
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700971 }
972
wangqi8d407a02018-02-15 15:32:52 -0800973 @TargetApi(28)
wangqi219b8702018-02-13 09:34:41 -0800974 public boolean isRttCall() {
975 if (BuildCompat.isAtLeastP()) {
976 return getTelecomCall().isRttActive();
977 } else {
978 return false;
979 }
980 }
981
wangqi153af2f2018-02-15 16:21:49 -0800982 @TargetApi(28)
983 public RttCall getRttCall() {
984 if (!isRttCall()) {
985 return null;
986 }
987 return getTelecomCall().getRttCall();
988 }
989
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700990 public boolean hasReceivedVideoUpgradeRequest() {
991 return VideoUtils.hasReceivedVideoUpgradeRequest(getVideoTech().getSessionModificationState());
992 }
993
994 public boolean hasSentVideoUpgradeRequest() {
995 return VideoUtils.hasSentVideoUpgradeRequest(getVideoTech().getSessionModificationState());
Eric Erfanianccca3152017-02-22 16:32:36 -0800996 }
997
wangqi219b8702018-02-13 09:34:41 -0800998 public boolean hasSentRttUpgradeRequest() {
wangqi219b8702018-02-13 09:34:41 -0800999 return false;
1000 }
1001
Eric Erfanianccca3152017-02-22 16:32:36 -08001002 /**
1003 * Determines if the call handle is an emergency number or not and caches the result to avoid
1004 * repeated calls to isEmergencyNumber.
1005 */
1006 private void updateEmergencyCallState() {
linyuh183cb712017-12-27 17:02:37 -08001007 isEmergencyCall = TelecomCallUtil.isEmergencyCall(telecomCall);
Eric Erfanianccca3152017-02-22 16:32:36 -08001008 }
1009
Eric Erfanianccca3152017-02-22 16:32:36 -08001010 public LogState getLogState() {
linyuh183cb712017-12-27 17:02:37 -08001011 return logState;
Eric Erfanianccca3152017-02-22 16:32:36 -08001012 }
1013
1014 /**
1015 * Determines if the call is an external call.
1016 *
1017 * <p>An external call is one which does not exist locally for the {@link
1018 * android.telecom.ConnectionService} it is associated with.
1019 *
1020 * <p>External calls are only supported in N and higher.
1021 *
1022 * @return {@code true} if the call is an external call, {@code false} otherwise.
1023 */
1024 public boolean isExternalCall() {
1025 return VERSION.SDK_INT >= VERSION_CODES.N
1026 && hasProperty(CallCompat.Details.PROPERTY_IS_EXTERNAL_CALL);
1027 }
1028
1029 /**
Eric Erfanianccca3152017-02-22 16:32:36 -08001030 * Determines if answering this call will cause an ongoing video call to be dropped.
1031 *
1032 * @return {@code true} if answering this call will drop an ongoing video call, {@code false}
1033 * otherwise.
1034 */
1035 public boolean answeringDisconnectsForegroundVideoCall() {
1036 Bundle extras = getExtras();
1037 if (extras == null
1038 || !extras.containsKey(CallCompat.Details.EXTRA_ANSWERING_DROPS_FOREGROUND_CALL)) {
1039 return false;
1040 }
1041 return extras.getBoolean(CallCompat.Details.EXTRA_ANSWERING_DROPS_FOREGROUND_CALL);
1042 }
1043
1044 private void parseCallSpecificAppData() {
1045 if (isExternalCall()) {
1046 return;
1047 }
1048
linyuh183cb712017-12-27 17:02:37 -08001049 logState.callSpecificAppData = CallIntentParser.getCallSpecificAppData(getIntentExtras());
1050 if (logState.callSpecificAppData == null) {
Eric Erfanian8369df02017-05-03 10:27:13 -07001051
linyuh183cb712017-12-27 17:02:37 -08001052 logState.callSpecificAppData =
Eric Erfanian8369df02017-05-03 10:27:13 -07001053 CallSpecificAppData.newBuilder()
1054 .setCallInitiationType(CallInitiationType.Type.EXTERNAL_INITIATION)
1055 .build();
Eric Erfanianccca3152017-02-22 16:32:36 -08001056 }
1057 if (getState() == State.INCOMING) {
linyuh183cb712017-12-27 17:02:37 -08001058 logState.callSpecificAppData =
1059 logState
Eric Erfanian8369df02017-05-03 10:27:13 -07001060 .callSpecificAppData
1061 .toBuilder()
1062 .setCallInitiationType(CallInitiationType.Type.INCOMING_INITIATION)
1063 .build();
Eric Erfanianccca3152017-02-22 16:32:36 -08001064 }
1065 }
1066
1067 @Override
1068 public String toString() {
linyuh183cb712017-12-27 17:02:37 -08001069 if (telecomCall == null) {
Eric Erfanianccca3152017-02-22 16:32:36 -08001070 // This should happen only in testing since otherwise we would never have a null
1071 // Telecom call.
linyuh183cb712017-12-27 17:02:37 -08001072 return String.valueOf(id);
Eric Erfanianccca3152017-02-22 16:32:36 -08001073 }
1074
1075 return String.format(
1076 Locale.US,
1077 "[%s, %s, %s, %s, children:%s, parent:%s, "
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001078 + "conferenceable:%s, videoState:%s, mSessionModificationState:%d, CameraDir:%s]",
linyuh183cb712017-12-27 17:02:37 -08001079 id,
Eric Erfanianccca3152017-02-22 16:32:36 -08001080 State.toString(getState()),
linyuh183cb712017-12-27 17:02:37 -08001081 Details.capabilitiesToString(telecomCall.getDetails().getCallCapabilities()),
1082 Details.propertiesToString(telecomCall.getDetails().getCallProperties()),
1083 childCallIds,
Eric Erfanianccca3152017-02-22 16:32:36 -08001084 getParentId(),
linyuh183cb712017-12-27 17:02:37 -08001085 this.telecomCall.getConferenceableCalls(),
1086 VideoProfile.videoStateToString(telecomCall.getDetails().getVideoState()),
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001087 getVideoTech().getSessionModificationState(),
1088 getCameraDir());
Eric Erfanianccca3152017-02-22 16:32:36 -08001089 }
1090
1091 public String toSimpleString() {
1092 return super.toString();
1093 }
1094
1095 @CallHistoryStatus
1096 public int getCallHistoryStatus() {
linyuh183cb712017-12-27 17:02:37 -08001097 return callHistoryStatus;
Eric Erfanianccca3152017-02-22 16:32:36 -08001098 }
1099
1100 public void setCallHistoryStatus(@CallHistoryStatus int callHistoryStatus) {
linyuh183cb712017-12-27 17:02:37 -08001101 this.callHistoryStatus = callHistoryStatus;
Eric Erfanianccca3152017-02-22 16:32:36 -08001102 }
1103
1104 public boolean didShowCameraPermission() {
1105 return didShowCameraPermission;
1106 }
1107
1108 public void setDidShowCameraPermission(boolean didShow) {
1109 didShowCameraPermission = didShow;
1110 }
1111
wangqida410d32018-03-06 16:51:38 -08001112 public boolean didDismissVideoChargesAlertDialog() {
1113 return didDismissVideoChargesAlertDialog;
1114 }
1115
1116 public void setDidDismissVideoChargesAlertDialog(boolean didDismiss) {
1117 didDismissVideoChargesAlertDialog = didDismiss;
1118 }
1119
Eric Erfanian938468d2017-10-24 14:05:52 -07001120 @Nullable
1121 public Boolean isInGlobalSpamList() {
Eric Erfanianccca3152017-02-22 16:32:36 -08001122 return isInGlobalSpamList;
1123 }
1124
1125 public void setIsInGlobalSpamList(boolean inSpamList) {
1126 isInGlobalSpamList = inSpamList;
1127 }
1128
Eric Erfanian938468d2017-10-24 14:05:52 -07001129 @Nullable
1130 public Boolean isInUserSpamList() {
Eric Erfanianccca3152017-02-22 16:32:36 -08001131 return isInUserSpamList;
1132 }
1133
1134 public void setIsInUserSpamList(boolean inSpamList) {
1135 isInUserSpamList = inSpamList;
1136 }
1137
Eric Erfanian938468d2017-10-24 14:05:52 -07001138 @Nullable
1139 public Boolean isInUserWhiteList() {
Eric Erfanianccca3152017-02-22 16:32:36 -08001140 return isInUserWhiteList;
1141 }
1142
1143 public void setIsInUserWhiteList(boolean inWhiteList) {
1144 isInUserWhiteList = inWhiteList;
1145 }
1146
1147 public boolean isSpam() {
linyuh183cb712017-12-27 17:02:37 -08001148 return isSpam;
Eric Erfanianccca3152017-02-22 16:32:36 -08001149 }
1150
1151 public void setSpam(boolean isSpam) {
linyuh183cb712017-12-27 17:02:37 -08001152 this.isSpam = isSpam;
Eric Erfanianccca3152017-02-22 16:32:36 -08001153 }
1154
1155 public boolean isBlocked() {
linyuh183cb712017-12-27 17:02:37 -08001156 return isBlocked;
Eric Erfanianccca3152017-02-22 16:32:36 -08001157 }
1158
1159 public void setBlockedStatus(boolean isBlocked) {
linyuh183cb712017-12-27 17:02:37 -08001160 this.isBlocked = isBlocked;
Eric Erfanianccca3152017-02-22 16:32:36 -08001161 }
1162
1163 public boolean isRemotelyHeld() {
1164 return isRemotelyHeld;
1165 }
1166
Eric Erfanian2ca43182017-08-31 06:57:16 -07001167 public boolean isMergeInProcess() {
1168 return isMergeInProcess;
1169 }
1170
Eric Erfanianccca3152017-02-22 16:32:36 -08001171 public boolean isIncoming() {
linyuh183cb712017-12-27 17:02:37 -08001172 return logState.isIncoming;
Eric Erfanianccca3152017-02-22 16:32:36 -08001173 }
1174
erfanian2cf2c342017-12-21 12:01:33 -08001175 /**
1176 * Try and determine if the call used assisted dialing.
1177 *
1178 * <p>We will not be able to verify a call underwent assisted dialing until the Platform
1179 * implmentation is complete in P+.
1180 *
1181 * @return a boolean indicating assisted dialing may have been performed
1182 */
Eric Erfanian2ca43182017-08-31 06:57:16 -07001183 public boolean isAssistedDialed() {
1184 if (getIntentExtras() != null) {
erfaniand2e5d0b2018-03-02 14:54:35 -08001185 // P and below uses the existence of USE_ASSISTED_DIALING to indicate assisted dialing
erfanian2cf2c342017-12-21 12:01:33 -08001186 // was used. The Dialer client is responsible for performing assisted dialing before
1187 // placing the outgoing call.
1188 //
1189 // The existence of the assisted dialing extras indicates that assisted dialing took place.
1190 if (getIntentExtras().getBoolean(TelephonyManagerCompat.USE_ASSISTED_DIALING, false)
1191 && getAssistedDialingExtras() != null
1192 && Build.VERSION.SDK_INT <= ConcreteCreator.BUILD_CODE_CEILING) {
1193 return true;
1194 }
1195 }
1196
Eric Erfanian2ca43182017-08-31 06:57:16 -07001197 return false;
1198 }
1199
erfanian2cf2c342017-12-21 12:01:33 -08001200 @Nullable
erfaniand0f207f2017-10-11 12:23:29 -07001201 public TransformationInfo getAssistedDialingExtras() {
erfanian2cf2c342017-12-21 12:01:33 -08001202 if (getIntentExtras() == null) {
1203 return null;
erfaniand0f207f2017-10-11 12:23:29 -07001204 }
erfanian2cf2c342017-12-21 12:01:33 -08001205
1206 if (getIntentExtras().getBundle(TelephonyManagerCompat.ASSISTED_DIALING_EXTRAS) == null) {
1207 return null;
1208 }
1209
erfanianf2556612018-01-23 09:55:59 -08001210 // Used in N-OMR1
erfanian2cf2c342017-12-21 12:01:33 -08001211 return TransformationInfo.newInstanceFromBundle(
1212 getIntentExtras().getBundle(TelephonyManagerCompat.ASSISTED_DIALING_EXTRAS));
erfaniand0f207f2017-10-11 12:23:29 -07001213 }
1214
Eric Erfanianccca3152017-02-22 16:32:36 -08001215 public LatencyReport getLatencyReport() {
linyuh183cb712017-12-27 17:02:37 -08001216 return latencyReport;
Eric Erfanianccca3152017-02-22 16:32:36 -08001217 }
1218
Eric Erfanian2ca43182017-08-31 06:57:16 -07001219 public int getAnswerAndReleaseButtonDisplayedTimes() {
1220 return answerAndReleaseButtonDisplayedTimes;
1221 }
1222
1223 public void increaseAnswerAndReleaseButtonDisplayedTimes() {
1224 answerAndReleaseButtonDisplayedTimes++;
1225 }
1226
1227 public boolean getReleasedByAnsweringSecondCall() {
1228 return releasedByAnsweringSecondCall;
1229 }
1230
1231 public void setReleasedByAnsweringSecondCall(boolean releasedByAnsweringSecondCall) {
1232 this.releasedByAnsweringSecondCall = releasedByAnsweringSecondCall;
1233 }
1234
1235 public int getSecondCallWithoutAnswerAndReleasedButtonTimes() {
1236 return secondCallWithoutAnswerAndReleasedButtonTimes;
1237 }
1238
1239 public void increaseSecondCallWithoutAnswerAndReleasedButtonTimes() {
1240 secondCallWithoutAnswerAndReleasedButtonTimes++;
1241 }
1242
Eric Erfanian8369df02017-05-03 10:27:13 -07001243 @Nullable
1244 public EnrichedCallCapabilities getEnrichedCallCapabilities() {
linyuh183cb712017-12-27 17:02:37 -08001245 return enrichedCallCapabilities;
Eric Erfanian8369df02017-05-03 10:27:13 -07001246 }
1247
1248 public void setEnrichedCallCapabilities(
1249 @Nullable EnrichedCallCapabilities mEnrichedCallCapabilities) {
linyuh183cb712017-12-27 17:02:37 -08001250 this.enrichedCallCapabilities = mEnrichedCallCapabilities;
Eric Erfanian8369df02017-05-03 10:27:13 -07001251 }
1252
1253 @Nullable
1254 public Session getEnrichedCallSession() {
linyuh183cb712017-12-27 17:02:37 -08001255 return enrichedCallSession;
Eric Erfanian8369df02017-05-03 10:27:13 -07001256 }
1257
1258 public void setEnrichedCallSession(@Nullable Session mEnrichedCallSession) {
linyuh183cb712017-12-27 17:02:37 -08001259 this.enrichedCallSession = mEnrichedCallSession;
Eric Erfanian8369df02017-05-03 10:27:13 -07001260 }
1261
Eric Erfanianccca3152017-02-22 16:32:36 -08001262 public void unregisterCallback() {
linyuh183cb712017-12-27 17:02:37 -08001263 telecomCall.unregisterCallback(telecomCallCallback);
Eric Erfanianccca3152017-02-22 16:32:36 -08001264 }
1265
Eric Erfanianccca3152017-02-22 16:32:36 -08001266 public void phoneAccountSelected(PhoneAccountHandle accountHandle, boolean setDefault) {
1267 LogUtil.i(
1268 "DialerCall.phoneAccountSelected",
1269 "accountHandle: %s, setDefault: %b",
1270 accountHandle,
1271 setDefault);
linyuh183cb712017-12-27 17:02:37 -08001272 telecomCall.phoneAccountSelected(accountHandle, setDefault);
Eric Erfanianccca3152017-02-22 16:32:36 -08001273 }
1274
1275 public void disconnect() {
1276 LogUtil.i("DialerCall.disconnect", "");
1277 setState(DialerCall.State.DISCONNECTING);
linyuh183cb712017-12-27 17:02:37 -08001278 for (DialerCallListener listener : listeners) {
Eric Erfanianccca3152017-02-22 16:32:36 -08001279 listener.onDialerCallUpdate();
1280 }
linyuh183cb712017-12-27 17:02:37 -08001281 telecomCall.disconnect();
Eric Erfanianccca3152017-02-22 16:32:36 -08001282 }
1283
1284 public void hold() {
1285 LogUtil.i("DialerCall.hold", "");
linyuh183cb712017-12-27 17:02:37 -08001286 telecomCall.hold();
Eric Erfanianccca3152017-02-22 16:32:36 -08001287 }
1288
1289 public void unhold() {
1290 LogUtil.i("DialerCall.unhold", "");
linyuh183cb712017-12-27 17:02:37 -08001291 telecomCall.unhold();
Eric Erfanianccca3152017-02-22 16:32:36 -08001292 }
1293
1294 public void splitFromConference() {
1295 LogUtil.i("DialerCall.splitFromConference", "");
linyuh183cb712017-12-27 17:02:37 -08001296 telecomCall.splitFromConference();
Eric Erfanianccca3152017-02-22 16:32:36 -08001297 }
1298
1299 public void answer(int videoState) {
1300 LogUtil.i("DialerCall.answer", "videoState: " + videoState);
linyuh183cb712017-12-27 17:02:37 -08001301 telecomCall.answer(videoState);
Eric Erfanianccca3152017-02-22 16:32:36 -08001302 }
1303
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001304 public void answer() {
linyuh183cb712017-12-27 17:02:37 -08001305 answer(telecomCall.getDetails().getVideoState());
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001306 }
1307
Eric Erfanianccca3152017-02-22 16:32:36 -08001308 public void reject(boolean rejectWithMessage, String message) {
1309 LogUtil.i("DialerCall.reject", "");
linyuh183cb712017-12-27 17:02:37 -08001310 telecomCall.reject(rejectWithMessage, message);
Eric Erfanianccca3152017-02-22 16:32:36 -08001311 }
1312
1313 /** Return the string label to represent the call provider */
1314 public String getCallProviderLabel() {
1315 if (callProviderLabel == null) {
1316 PhoneAccount account = getPhoneAccount();
1317 if (account != null && !TextUtils.isEmpty(account.getLabel())) {
wangqi9982f0d2017-10-11 17:46:07 -07001318 if (callCapableAccounts != null && callCapableAccounts.size() > 1) {
Eric Erfanianccca3152017-02-22 16:32:36 -08001319 callProviderLabel = account.getLabel().toString();
1320 }
1321 }
1322 if (callProviderLabel == null) {
1323 callProviderLabel = "";
1324 }
1325 }
1326 return callProviderLabel;
1327 }
1328
1329 private PhoneAccount getPhoneAccount() {
1330 PhoneAccountHandle accountHandle = getAccountHandle();
1331 if (accountHandle == null) {
1332 return null;
1333 }
linyuh183cb712017-12-27 17:02:37 -08001334 return context.getSystemService(TelecomManager.class).getPhoneAccount(accountHandle);
Eric Erfanianccca3152017-02-22 16:32:36 -08001335 }
1336
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001337 public VideoTech getVideoTech() {
roldenburg7bb96232017-10-09 10:32:05 -07001338 if (videoTech == null) {
roldenburg6bd612f2018-01-18 12:57:19 -08001339 videoTech = videoTechManager.getVideoTech(getAccountHandle());
roldenburg7bb96232017-10-09 10:32:05 -07001340
1341 // Only store the first video tech type found to be available during the life of the call.
1342 if (selectedAvailableVideoTechType == com.android.dialer.logging.VideoTech.Type.NONE) {
1343 // Update the video tech.
1344 selectedAvailableVideoTechType = videoTech.getVideoTechType();
1345 }
1346 }
Eric Erfanian2ca43182017-08-31 06:57:16 -07001347 return videoTech;
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001348 }
1349
Eric Erfanianccca3152017-02-22 16:32:36 -08001350 public String getCallbackNumber() {
1351 if (callbackNumber == null) {
1352 // Show the emergency callback number if either:
1353 // 1. This is an emergency call.
1354 // 2. The phone is in Emergency Callback Mode, which means we should show the callback
1355 // number.
1356 boolean showCallbackNumber = hasProperty(Details.PROPERTY_EMERGENCY_CALLBACK_MODE);
1357
1358 if (isEmergencyCall() || showCallbackNumber) {
wangqi339b4f32017-09-18 14:32:09 -07001359 callbackNumber =
linyuh183cb712017-12-27 17:02:37 -08001360 context.getSystemService(TelecomManager.class).getLine1Number(getAccountHandle());
Eric Erfanianccca3152017-02-22 16:32:36 -08001361 }
1362
Eric Erfanianccca3152017-02-22 16:32:36 -08001363 if (callbackNumber == null) {
1364 callbackNumber = "";
1365 }
1366 }
1367 return callbackNumber;
1368 }
1369
wangqi97539352017-09-25 11:15:16 -07001370 public String getSimCountryIso() {
1371 String simCountryIso =
linyuh183cb712017-12-27 17:02:37 -08001372 TelephonyManagerCompat.getTelephonyManagerForPhoneAccountHandle(context, getAccountHandle())
wangqi97539352017-09-25 11:15:16 -07001373 .getSimCountryIso();
1374 if (!TextUtils.isEmpty(simCountryIso)) {
1375 simCountryIso = simCountryIso.toUpperCase(Locale.US);
1376 }
1377 return simCountryIso;
1378 }
1379
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001380 @Override
1381 public void onVideoTechStateChanged() {
1382 update();
1383 }
1384
1385 @Override
1386 public void onSessionModificationStateChanged() {
wangqi9982f0d2017-10-11 17:46:07 -07001387 Trace.beginSection("DialerCall.onSessionModificationStateChanged");
linyuh183cb712017-12-27 17:02:37 -08001388 for (DialerCallListener listener : listeners) {
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001389 listener.onDialerCallSessionModificationStateChange();
1390 }
wangqi9982f0d2017-10-11 17:46:07 -07001391 Trace.endSection();
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001392 }
1393
1394 @Override
1395 public void onCameraDimensionsChanged(int width, int height) {
1396 InCallVideoCallCallbackNotifier.getInstance().cameraDimensionsChanged(this, width, height);
1397 }
1398
1399 @Override
1400 public void onPeerDimensionsChanged(int width, int height) {
1401 InCallVideoCallCallbackNotifier.getInstance().peerDimensionsChanged(this, width, height);
1402 }
1403
1404 @Override
1405 public void onVideoUpgradeRequestReceived() {
1406 LogUtil.enterBlock("DialerCall.onVideoUpgradeRequestReceived");
1407
linyuh183cb712017-12-27 17:02:37 -08001408 for (DialerCallListener listener : listeners) {
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001409 listener.onDialerCallUpgradeToVideo();
1410 }
1411
1412 update();
Eric Erfanian8369df02017-05-03 10:27:13 -07001413
linyuh183cb712017-12-27 17:02:37 -08001414 Logger.get(context)
Eric Erfanian8369df02017-05-03 10:27:13 -07001415 .logCallImpression(
1416 DialerImpression.Type.VIDEO_CALL_REQUEST_RECEIVED, getUniqueCallId(), getTimeAddedMs());
1417 }
1418
1419 @Override
1420 public void onUpgradedToVideo(boolean switchToSpeaker) {
1421 LogUtil.enterBlock("DialerCall.onUpgradedToVideo");
1422
1423 if (!switchToSpeaker) {
1424 return;
1425 }
1426
1427 CallAudioState audioState = AudioModeProvider.getInstance().getAudioState();
1428
1429 if (0 != (CallAudioState.ROUTE_BLUETOOTH & audioState.getSupportedRouteMask())) {
1430 LogUtil.e(
1431 "DialerCall.onUpgradedToVideo",
1432 "toggling speakerphone not allowed when bluetooth supported.");
1433 return;
1434 }
1435
1436 if (audioState.getRoute() == CallAudioState.ROUTE_SPEAKER) {
1437 return;
1438 }
1439
1440 TelecomAdapter.getInstance().setAudioRoute(CallAudioState.ROUTE_SPEAKER);
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001441 }
1442
Eric Erfanian2ca43182017-08-31 06:57:16 -07001443 @Override
1444 public void onCapabilitiesUpdated() {
1445 if (getNumber() == null) {
1446 return;
1447 }
1448 EnrichedCallCapabilities capabilities =
linyuh183cb712017-12-27 17:02:37 -08001449 EnrichedCallComponent.get(context).getEnrichedCallManager().getCapabilities(getNumber());
Eric Erfanian2ca43182017-08-31 06:57:16 -07001450 if (capabilities != null) {
1451 setEnrichedCallCapabilities(capabilities);
1452 update();
1453 }
1454 }
1455
1456 @Override
1457 public void onEnrichedCallStateChanged() {
1458 updateEnrichedCallSession();
1459 }
1460
1461 @Override
1462 public void onImpressionLoggingNeeded(DialerImpression.Type impressionType) {
linyuh183cb712017-12-27 17:02:37 -08001463 Logger.get(context).logCallImpression(impressionType, getUniqueCallId(), getTimeAddedMs());
twyendde01c52017-09-22 10:07:31 -07001464 if (impressionType == DialerImpression.Type.LIGHTBRINGER_UPGRADE_REQUESTED) {
1465 if (getLogState().contactLookupResult == Type.NOT_FOUND) {
linyuh183cb712017-12-27 17:02:37 -08001466 Logger.get(context)
twyendde01c52017-09-22 10:07:31 -07001467 .logCallImpression(
1468 DialerImpression.Type.LIGHTBRINGER_NON_CONTACT_UPGRADE_REQUESTED,
1469 getUniqueCallId(),
1470 getTimeAddedMs());
1471 }
1472 }
Eric Erfanian2ca43182017-08-31 06:57:16 -07001473 }
1474
1475 private void updateEnrichedCallSession() {
1476 if (getNumber() == null) {
1477 return;
1478 }
1479 if (getEnrichedCallSession() != null) {
1480 // State changes to existing sessions are currently handled by the UI components (which have
1481 // their own listeners). Someday instead we could remove those and just call update() here and
1482 // have the usual onDialerCallUpdate update the UI.
1483 dispatchOnEnrichedCallSessionUpdate();
1484 return;
1485 }
1486
linyuh183cb712017-12-27 17:02:37 -08001487 EnrichedCallManager manager = EnrichedCallComponent.get(context).getEnrichedCallManager();
Eric Erfanian2ca43182017-08-31 06:57:16 -07001488
1489 Filter filter =
1490 isIncoming()
1491 ? manager.createIncomingCallComposerFilter()
1492 : manager.createOutgoingCallComposerFilter();
1493
1494 Session session = manager.getSession(getUniqueCallId(), getNumber(), filter);
1495 if (session == null) {
1496 return;
1497 }
1498
1499 session.setUniqueDialerCallId(getUniqueCallId());
1500 setEnrichedCallSession(session);
1501
1502 LogUtil.i(
1503 "DialerCall.updateEnrichedCallSession",
1504 "setting session %d's dialer id to %s",
1505 session.getSessionId(),
1506 getUniqueCallId());
1507
1508 dispatchOnEnrichedCallSessionUpdate();
1509 }
1510
1511 private void dispatchOnEnrichedCallSessionUpdate() {
linyuh183cb712017-12-27 17:02:37 -08001512 for (DialerCallListener listener : listeners) {
Eric Erfanian2ca43182017-08-31 06:57:16 -07001513 listener.onEnrichedCallSessionUpdate();
1514 }
1515 }
1516
1517 void onRemovedFromCallList() {
1518 // Ensure we clean up when this call is removed.
linyuh183cb712017-12-27 17:02:37 -08001519 videoTechManager.dispatchRemovedFromCallList();
Eric Erfanian2ca43182017-08-31 06:57:16 -07001520 }
1521
wangqi4d705e52017-09-28 12:23:35 -07001522 public com.android.dialer.logging.VideoTech.Type getSelectedAvailableVideoTechType() {
1523 return selectedAvailableVideoTechType;
yueg457b3972017-09-18 15:11:47 -07001524 }
1525
Android Dialer974fc292018-02-01 16:12:25 -08001526 public void markFeedbackRequested() {
1527 feedbackRequested = true;
1528 }
1529
1530 public boolean isFeedbackRequested() {
1531 return feedbackRequested;
1532 }
1533
Eric Erfanianccca3152017-02-22 16:32:36 -08001534 /**
twyen73a74c32018-03-07 12:12:24 -08001535 * If the in call UI has shown the phone account selection dialog for the call, the {@link
1536 * PreferredAccountRecorder} to record the result from the dialog.
1537 */
1538 @Nullable
1539 public PreferredAccountRecorder getPreferredAccountRecorder() {
1540 return preferredAccountRecorder;
1541 }
1542
1543 public void setPreferredAccountRecorder(PreferredAccountRecorder preferredAccountRecorder) {
1544 this.preferredAccountRecorder = preferredAccountRecorder;
1545 }
1546
1547 /**
Eric Erfanianccca3152017-02-22 16:32:36 -08001548 * Specifies whether a number is in the call history or not. {@link #CALL_HISTORY_STATUS_UNKNOWN}
1549 * means there is no result.
1550 */
1551 @IntDef({
1552 CALL_HISTORY_STATUS_UNKNOWN,
1553 CALL_HISTORY_STATUS_PRESENT,
1554 CALL_HISTORY_STATUS_NOT_PRESENT
1555 })
1556 @Retention(RetentionPolicy.SOURCE)
1557 public @interface CallHistoryStatus {}
1558
1559 /* Defines different states of this call */
1560 public static class State {
1561
1562 public static final int INVALID = 0;
1563 public static final int NEW = 1; /* The call is new. */
1564 public static final int IDLE = 2; /* The call is idle. Nothing active */
1565 public static final int ACTIVE = 3; /* There is an active call */
1566 public static final int INCOMING = 4; /* A normal incoming phone call */
1567 public static final int CALL_WAITING = 5; /* Incoming call while another is active */
1568 public static final int DIALING = 6; /* An outgoing call during dial phase */
1569 public static final int REDIALING = 7; /* Subsequent dialing attempt after a failure */
1570 public static final int ONHOLD = 8; /* An active phone call placed on hold */
1571 public static final int DISCONNECTING = 9; /* A call is being ended. */
1572 public static final int DISCONNECTED = 10; /* State after a call disconnects */
1573 public static final int CONFERENCED = 11; /* DialerCall part of a conference call */
1574 public static final int SELECT_PHONE_ACCOUNT = 12; /* Waiting for account selection */
1575 public static final int CONNECTING = 13; /* Waiting for Telecom broadcast to finish */
1576 public static final int BLOCKED = 14; /* The number was found on the block list */
1577 public static final int PULLING = 15; /* An external call being pulled to the device */
Eric Erfanian2ca43182017-08-31 06:57:16 -07001578 public static final int CALL_PENDING = 16; /* A call is pending on a long process to finish */
Eric Erfanianccca3152017-02-22 16:32:36 -08001579
1580 public static boolean isConnectingOrConnected(int state) {
1581 switch (state) {
1582 case ACTIVE:
1583 case INCOMING:
1584 case CALL_WAITING:
1585 case CONNECTING:
1586 case DIALING:
1587 case PULLING:
1588 case REDIALING:
1589 case ONHOLD:
1590 case CONFERENCED:
1591 return true;
1592 default:
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001593 return false;
Eric Erfanianccca3152017-02-22 16:32:36 -08001594 }
Eric Erfanianccca3152017-02-22 16:32:36 -08001595 }
1596
1597 public static boolean isDialing(int state) {
1598 return state == DIALING || state == PULLING || state == REDIALING;
1599 }
1600
1601 public static String toString(int state) {
1602 switch (state) {
1603 case INVALID:
1604 return "INVALID";
1605 case NEW:
1606 return "NEW";
1607 case IDLE:
1608 return "IDLE";
1609 case ACTIVE:
1610 return "ACTIVE";
1611 case INCOMING:
1612 return "INCOMING";
1613 case CALL_WAITING:
1614 return "CALL_WAITING";
1615 case DIALING:
1616 return "DIALING";
1617 case PULLING:
1618 return "PULLING";
1619 case REDIALING:
1620 return "REDIALING";
1621 case ONHOLD:
1622 return "ONHOLD";
1623 case DISCONNECTING:
1624 return "DISCONNECTING";
1625 case DISCONNECTED:
1626 return "DISCONNECTED";
1627 case CONFERENCED:
1628 return "CONFERENCED";
1629 case SELECT_PHONE_ACCOUNT:
1630 return "SELECT_PHONE_ACCOUNT";
1631 case CONNECTING:
1632 return "CONNECTING";
1633 case BLOCKED:
1634 return "BLOCKED";
1635 default:
1636 return "UNKNOWN";
1637 }
1638 }
1639 }
1640
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001641 /** Camera direction constants */
1642 public static class CameraDirection {
Eric Erfanianccca3152017-02-22 16:32:36 -08001643 public static final int CAMERA_DIRECTION_UNKNOWN = -1;
1644 public static final int CAMERA_DIRECTION_FRONT_FACING = CameraCharacteristics.LENS_FACING_FRONT;
1645 public static final int CAMERA_DIRECTION_BACK_FACING = CameraCharacteristics.LENS_FACING_BACK;
Eric Erfanianccca3152017-02-22 16:32:36 -08001646 }
1647
1648 /**
1649 * Tracks any state variables that is useful for logging. There is some amount of overlap with
1650 * existing call member variables, but this duplication helps to ensure that none of these logging
1651 * variables will interface with/and affect call logic.
1652 */
1653 public static class LogState {
1654
1655 public DisconnectCause disconnectCause;
1656 public boolean isIncoming = false;
Eric Erfanian8369df02017-05-03 10:27:13 -07001657 public ContactLookupResult.Type contactLookupResult =
1658 ContactLookupResult.Type.UNKNOWN_LOOKUP_RESULT_TYPE;
Eric Erfanianccca3152017-02-22 16:32:36 -08001659 public CallSpecificAppData callSpecificAppData;
1660 // If this was a conference call, the total number of calls involved in the conference.
1661 public int conferencedCalls = 0;
1662 public long duration = 0;
1663 public boolean isLogged = false;
1664
Eric Erfanian8369df02017-05-03 10:27:13 -07001665 private static String lookupToString(ContactLookupResult.Type lookupType) {
Eric Erfanianccca3152017-02-22 16:32:36 -08001666 switch (lookupType) {
Eric Erfanian8369df02017-05-03 10:27:13 -07001667 case LOCAL_CONTACT:
Eric Erfanianccca3152017-02-22 16:32:36 -08001668 return "Local";
Eric Erfanian8369df02017-05-03 10:27:13 -07001669 case LOCAL_CACHE:
Eric Erfanianccca3152017-02-22 16:32:36 -08001670 return "Cache";
Eric Erfanian8369df02017-05-03 10:27:13 -07001671 case REMOTE:
Eric Erfanianccca3152017-02-22 16:32:36 -08001672 return "Remote";
Eric Erfanian8369df02017-05-03 10:27:13 -07001673 case EMERGENCY:
Eric Erfanianccca3152017-02-22 16:32:36 -08001674 return "Emergency";
Eric Erfanian8369df02017-05-03 10:27:13 -07001675 case VOICEMAIL:
Eric Erfanianccca3152017-02-22 16:32:36 -08001676 return "Voicemail";
1677 default:
1678 return "Not found";
1679 }
1680 }
1681
1682 private static String initiationToString(CallSpecificAppData callSpecificAppData) {
1683 if (callSpecificAppData == null) {
1684 return "null";
1685 }
Eric Erfanian8369df02017-05-03 10:27:13 -07001686 switch (callSpecificAppData.getCallInitiationType()) {
1687 case INCOMING_INITIATION:
Eric Erfanianccca3152017-02-22 16:32:36 -08001688 return "Incoming";
Eric Erfanian8369df02017-05-03 10:27:13 -07001689 case DIALPAD:
Eric Erfanianccca3152017-02-22 16:32:36 -08001690 return "Dialpad";
Eric Erfanian8369df02017-05-03 10:27:13 -07001691 case SPEED_DIAL:
Eric Erfanianccca3152017-02-22 16:32:36 -08001692 return "Speed Dial";
Eric Erfanian8369df02017-05-03 10:27:13 -07001693 case REMOTE_DIRECTORY:
Eric Erfanianccca3152017-02-22 16:32:36 -08001694 return "Remote Directory";
Eric Erfanian8369df02017-05-03 10:27:13 -07001695 case SMART_DIAL:
Eric Erfanianccca3152017-02-22 16:32:36 -08001696 return "Smart Dial";
Eric Erfanian8369df02017-05-03 10:27:13 -07001697 case REGULAR_SEARCH:
Eric Erfanianccca3152017-02-22 16:32:36 -08001698 return "Regular Search";
Eric Erfanian8369df02017-05-03 10:27:13 -07001699 case CALL_LOG:
Eric Erfanianccca3152017-02-22 16:32:36 -08001700 return "DialerCall Log";
Eric Erfanian8369df02017-05-03 10:27:13 -07001701 case CALL_LOG_FILTER:
Eric Erfanianccca3152017-02-22 16:32:36 -08001702 return "DialerCall Log Filter";
Eric Erfanian8369df02017-05-03 10:27:13 -07001703 case VOICEMAIL_LOG:
Eric Erfanianccca3152017-02-22 16:32:36 -08001704 return "Voicemail Log";
Eric Erfanian8369df02017-05-03 10:27:13 -07001705 case CALL_DETAILS:
Eric Erfanianccca3152017-02-22 16:32:36 -08001706 return "DialerCall Details";
Eric Erfanian8369df02017-05-03 10:27:13 -07001707 case QUICK_CONTACTS:
Eric Erfanianccca3152017-02-22 16:32:36 -08001708 return "Quick Contacts";
Eric Erfanian8369df02017-05-03 10:27:13 -07001709 case EXTERNAL_INITIATION:
Eric Erfanianccca3152017-02-22 16:32:36 -08001710 return "External";
Eric Erfanian8369df02017-05-03 10:27:13 -07001711 case LAUNCHER_SHORTCUT:
Eric Erfanianccca3152017-02-22 16:32:36 -08001712 return "Launcher Shortcut";
1713 default:
Eric Erfanian8369df02017-05-03 10:27:13 -07001714 return "Unknown: " + callSpecificAppData.getCallInitiationType();
Eric Erfanianccca3152017-02-22 16:32:36 -08001715 }
1716 }
1717
1718 @Override
1719 public String toString() {
1720 return String.format(
1721 Locale.US,
1722 "["
1723 + "%s, " // DisconnectCause toString already describes the object type
1724 + "isIncoming: %s, "
1725 + "contactLookup: %s, "
1726 + "callInitiation: %s, "
1727 + "duration: %s"
1728 + "]",
1729 disconnectCause,
1730 isIncoming,
1731 lookupToString(contactLookupResult),
1732 initiationToString(callSpecificAppData),
1733 duration);
1734 }
1735 }
1736
roldenburgd7490db2018-01-09 13:51:29 -08001737 /** Coordinates the available VideoTech implementations for a call. */
1738 @VisibleForTesting
1739 public static class VideoTechManager {
Eric Erfaniand8046e52017-04-06 09:41:50 -07001740 private final Context context;
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001741 private final EmptyVideoTech emptyVideoTech = new EmptyVideoTech();
roldenburgd7490db2018-01-09 13:51:29 -08001742 private final VideoTech rcsVideoShare;
Eric Erfanian90508232017-03-24 09:31:16 -07001743 private final List<VideoTech> videoTechs;
roldenburg7bb96232017-10-09 10:32:05 -07001744 private VideoTech savedTech;
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001745
roldenburgd7490db2018-01-09 13:51:29 -08001746 @VisibleForTesting
1747 public VideoTechManager(DialerCall call) {
linyuh183cb712017-12-27 17:02:37 -08001748 this.context = call.context;
Eric Erfaniand8046e52017-04-06 09:41:50 -07001749
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001750 String phoneNumber = call.getNumber();
Eric Erfaniand8046e52017-04-06 09:41:50 -07001751 phoneNumber = phoneNumber != null ? phoneNumber : "";
Eric Erfanian2ca43182017-08-31 06:57:16 -07001752 phoneNumber = phoneNumber.replaceAll("[^+0-9]", "");
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001753
1754 // Insert order here determines the priority of that video tech option
Eric Erfanian8369df02017-05-03 10:27:13 -07001755 videoTechs = new ArrayList<>();
yueg457b3972017-09-18 15:11:47 -07001756
linyuh183cb712017-12-27 17:02:37 -08001757 videoTechs.add(new ImsVideoTech(Logger.get(call.context), call, call.telecomCall));
Eric Erfanian90508232017-03-24 09:31:16 -07001758
roldenburgd7490db2018-01-09 13:51:29 -08001759 rcsVideoShare =
linyuh183cb712017-12-27 17:02:37 -08001760 EnrichedCallComponent.get(call.context)
Eric Erfanian90508232017-03-24 09:31:16 -07001761 .getRcsVideoShareFactory()
1762 .newRcsVideoShare(
linyuh183cb712017-12-27 17:02:37 -08001763 EnrichedCallComponent.get(call.context).getEnrichedCallManager(),
Eric Erfanian90508232017-03-24 09:31:16 -07001764 call,
Eric Erfaniand8046e52017-04-06 09:41:50 -07001765 phoneNumber);
roldenburg3eca69f2018-01-16 12:07:04 -08001766 videoTechs.add(rcsVideoShare);
Eric Erfaniand8046e52017-04-06 09:41:50 -07001767
1768 videoTechs.add(
roldenburg4f026392017-10-13 18:42:20 -07001769 new DuoVideoTech(
linyuh183cb712017-12-27 17:02:37 -08001770 DuoComponent.get(call.context).getDuo(), call, call.telecomCall, phoneNumber));
roldenburgd7490db2018-01-09 13:51:29 -08001771
1772 savedTech = emptyVideoTech;
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001773 }
1774
roldenburgd7490db2018-01-09 13:51:29 -08001775 @VisibleForTesting
roldenburg6bd612f2018-01-18 12:57:19 -08001776 public VideoTech getVideoTech(PhoneAccountHandle phoneAccountHandle) {
roldenburgd7490db2018-01-09 13:51:29 -08001777 if (savedTech == emptyVideoTech) {
1778 for (VideoTech tech : videoTechs) {
roldenburg6bd612f2018-01-18 12:57:19 -08001779 if (tech.isAvailable(context, phoneAccountHandle)) {
roldenburgd7490db2018-01-09 13:51:29 -08001780 savedTech = tech;
1781 savedTech.becomePrimary();
1782 break;
1783 }
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001784 }
roldenburg6bd612f2018-01-18 12:57:19 -08001785 } else if (savedTech instanceof DuoVideoTech
1786 && rcsVideoShare.isAvailable(context, phoneAccountHandle)) {
roldenburgd7490db2018-01-09 13:51:29 -08001787 // RCS Video Share will become available after the capability exchange which is slower than
1788 // Duo reading local contacts for reachability. If Video Share becomes available and we are
1789 // not in the middle of any session changes, let it take over.
1790 savedTech = rcsVideoShare;
1791 rcsVideoShare.becomePrimary();
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001792 }
1793
roldenburgd7490db2018-01-09 13:51:29 -08001794 return savedTech;
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001795 }
1796
roldenburgd7490db2018-01-09 13:51:29 -08001797 @VisibleForTesting
roldenburg6bd612f2018-01-18 12:57:19 -08001798 public void dispatchCallStateChanged(int newState, PhoneAccountHandle phoneAccountHandle) {
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001799 for (VideoTech videoTech : videoTechs) {
roldenburg6bd612f2018-01-18 12:57:19 -08001800 videoTech.onCallStateChanged(context, newState, phoneAccountHandle);
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001801 }
1802 }
Eric Erfanian2ca43182017-08-31 06:57:16 -07001803
1804 void dispatchRemovedFromCallList() {
1805 for (VideoTech videoTech : videoTechs) {
1806 videoTech.onRemovedFromCallList();
1807 }
1808 }
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001809 }
1810
Eric Erfanianccca3152017-02-22 16:32:36 -08001811 /** Called when canned text responses have been loaded. */
1812 public interface CannedTextResponsesLoadedListener {
1813 void onCannedTextResponsesLoaded(DialerCall call);
1814 }
1815}