blob: 50bc691b71a1311c1bdaf57ef38530d588d67dd5 [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;
wangqi8d407a02018-02-15 15:32:52 -080020import android.annotation.TargetApi;
Eric Erfanianccca3152017-02-22 16:32:36 -080021import android.content.Context;
22import android.hardware.camera2.CameraCharacteristics;
23import android.net.Uri;
erfanian2cf2c342017-12-21 12:01:33 -080024import android.os.Build;
Eric Erfanianccca3152017-02-22 16:32:36 -080025import android.os.Build.VERSION;
26import android.os.Build.VERSION_CODES;
27import android.os.Bundle;
28import android.os.Trace;
29import android.support.annotation.IntDef;
Eric Erfaniand5e47f62017-03-15 14:41:07 -070030import android.support.annotation.NonNull;
Eric Erfanianccca3152017-02-22 16:32:36 -080031import android.support.annotation.Nullable;
twyendde01c52017-09-22 10:07:31 -070032import android.support.annotation.VisibleForTesting;
wangqif4ba3452018-01-09 11:26:29 -080033import android.support.v4.os.BuildCompat;
Eric Erfanianccca3152017-02-22 16:32:36 -080034import android.telecom.Call;
35import android.telecom.Call.Details;
wangqi219b8702018-02-13 09:34:41 -080036import android.telecom.Call.RttCall;
Eric Erfanian8369df02017-05-03 10:27:13 -070037import android.telecom.CallAudioState;
Eric Erfanianccca3152017-02-22 16:32:36 -080038import android.telecom.Connection;
39import android.telecom.DisconnectCause;
40import android.telecom.GatewayInfo;
41import android.telecom.InCallService.VideoCall;
42import android.telecom.PhoneAccount;
43import android.telecom.PhoneAccountHandle;
44import android.telecom.StatusHints;
45import android.telecom.TelecomManager;
46import android.telecom.VideoProfile;
Eric Erfanianccca3152017-02-22 16:32:36 -080047import android.text.TextUtils;
48import com.android.contacts.common.compat.CallCompat;
Eric Erfanianccca3152017-02-22 16:32:36 -080049import com.android.contacts.common.compat.telecom.TelecomManagerCompat;
erfanian2cf2c342017-12-21 12:01:33 -080050import com.android.dialer.assisteddialing.ConcreteCreator;
erfaniand0f207f2017-10-11 12:23:29 -070051import com.android.dialer.assisteddialing.TransformationInfo;
Eric Erfanian8369df02017-05-03 10:27:13 -070052import com.android.dialer.callintent.CallInitiationType;
Eric Erfanianccca3152017-02-22 16:32:36 -080053import com.android.dialer.callintent.CallIntentParser;
Eric Erfanian8369df02017-05-03 10:27:13 -070054import com.android.dialer.callintent.CallSpecificAppData;
Eric Erfanianccca3152017-02-22 16:32:36 -080055import com.android.dialer.common.Assert;
Eric Erfanianccca3152017-02-22 16:32:36 -080056import com.android.dialer.common.LogUtil;
Eric Erfanian2ca43182017-08-31 06:57:16 -070057import com.android.dialer.compat.telephony.TelephonyManagerCompat;
58import com.android.dialer.configprovider.ConfigProviderBindings;
roldenburg4f026392017-10-13 18:42:20 -070059import com.android.dialer.duo.DuoComponent;
Eric Erfanian8369df02017-05-03 10:27:13 -070060import com.android.dialer.enrichedcall.EnrichedCallCapabilities;
Eric Erfaniand5e47f62017-03-15 14:41:07 -070061import com.android.dialer.enrichedcall.EnrichedCallComponent;
Eric Erfanian2ca43182017-08-31 06:57:16 -070062import com.android.dialer.enrichedcall.EnrichedCallManager;
63import com.android.dialer.enrichedcall.EnrichedCallManager.CapabilitiesListener;
64import com.android.dialer.enrichedcall.EnrichedCallManager.Filter;
65import com.android.dialer.enrichedcall.EnrichedCallManager.StateChangedListener;
Eric Erfanian8369df02017-05-03 10:27:13 -070066import com.android.dialer.enrichedcall.Session;
wangqi9982f0d2017-10-11 17:46:07 -070067import com.android.dialer.location.GeoUtil;
Eric Erfanian8369df02017-05-03 10:27:13 -070068import com.android.dialer.logging.ContactLookupResult;
twyendde01c52017-09-22 10:07:31 -070069import com.android.dialer.logging.ContactLookupResult.Type;
Eric Erfanian8369df02017-05-03 10:27:13 -070070import com.android.dialer.logging.DialerImpression;
71import com.android.dialer.logging.Logger;
twyena4745bd2017-12-12 18:40:11 -080072import com.android.dialer.telecom.TelecomCallUtil;
wangqi9982f0d2017-10-11 17:46:07 -070073import com.android.dialer.telecom.TelecomUtil;
Eric Erfanianc857f902017-05-15 14:05:33 -070074import com.android.dialer.theme.R;
wangqi9982f0d2017-10-11 17:46:07 -070075import com.android.dialer.util.PermissionsUtil;
Eric Erfanian8369df02017-05-03 10:27:13 -070076import com.android.incallui.audiomode.AudioModeProvider;
Eric Erfanianccca3152017-02-22 16:32:36 -080077import com.android.incallui.latencyreport.LatencyReport;
Eric Erfaniand5e47f62017-03-15 14:41:07 -070078import com.android.incallui.videotech.VideoTech;
79import com.android.incallui.videotech.VideoTech.VideoTechListener;
roldenburg4f026392017-10-13 18:42:20 -070080import com.android.incallui.videotech.duo.DuoVideoTech;
Eric Erfaniand5e47f62017-03-15 14:41:07 -070081import com.android.incallui.videotech.empty.EmptyVideoTech;
82import com.android.incallui.videotech.ims.ImsVideoTech;
Eric Erfanian90508232017-03-24 09:31:16 -070083import com.android.incallui.videotech.utils.VideoUtils;
Eric Erfanianccca3152017-02-22 16:32:36 -080084import java.lang.annotation.Retention;
85import java.lang.annotation.RetentionPolicy;
86import java.util.ArrayList;
87import java.util.List;
88import java.util.Locale;
89import java.util.Objects;
90import java.util.UUID;
91import java.util.concurrent.CopyOnWriteArrayList;
92import java.util.concurrent.TimeUnit;
93
94/** Describes a single call and its state. */
Eric Erfanian2ca43182017-08-31 06:57:16 -070095public class DialerCall implements VideoTechListener, StateChangedListener, CapabilitiesListener {
Eric Erfanianccca3152017-02-22 16:32:36 -080096
97 public static final int CALL_HISTORY_STATUS_UNKNOWN = 0;
98 public static final int CALL_HISTORY_STATUS_PRESENT = 1;
99 public static final int CALL_HISTORY_STATUS_NOT_PRESENT = 2;
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700100
101 // Hard coded property for {@code Call}. Upstreamed change from Motorola.
Eric Erfanian938468d2017-10-24 14:05:52 -0700102 // TODO(a bug): Move it to Telecom in framework.
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700103 public static final int PROPERTY_CODEC_KNOWN = 0x04000000;
104
Eric Erfanianccca3152017-02-22 16:32:36 -0800105 private static final String ID_PREFIX = "DialerCall_";
106 private static final String CONFIG_EMERGENCY_CALLBACK_WINDOW_MILLIS =
107 "emergency_callback_window_millis";
linyuh183cb712017-12-27 17:02:37 -0800108 private static int idCounter = 0;
Eric Erfanianccca3152017-02-22 16:32:36 -0800109
110 /**
Eric Erfanianc857f902017-05-15 14:05:33 -0700111 * A counter used to append to restricted/private/hidden calls so that users can identify them in
112 * a conversation. This value is reset in {@link CallList#onCallRemoved(Context, Call)} when there
113 * are no live calls.
114 */
linyuh183cb712017-12-27 17:02:37 -0800115 private static int hiddenCounter;
Eric Erfanianc857f902017-05-15 14:05:33 -0700116
117 /**
Eric Erfanianccca3152017-02-22 16:32:36 -0800118 * The unique call ID for every call. This will help us to identify each call and allow us the
119 * ability to stitch impressions to calls if needed.
120 */
121 private final String uniqueCallId = UUID.randomUUID().toString();
122
linyuh183cb712017-12-27 17:02:37 -0800123 private final Call telecomCall;
124 private final LatencyReport latencyReport;
125 private final String id;
126 private final int hiddenId;
127 private final List<String> childCallIds = new ArrayList<>();
128 private final LogState logState = new LogState();
129 private final Context context;
130 private final DialerCallDelegate dialerCallDelegate;
131 private final List<DialerCallListener> listeners = new CopyOnWriteArrayList<>();
132 private final List<CannedTextResponsesLoadedListener> cannedTextResponsesLoadedListeners =
Eric Erfanianccca3152017-02-22 16:32:36 -0800133 new CopyOnWriteArrayList<>();
linyuh183cb712017-12-27 17:02:37 -0800134 private final VideoTechManager videoTechManager;
Eric Erfanianccca3152017-02-22 16:32:36 -0800135
linyuh183cb712017-12-27 17:02:37 -0800136 private boolean isEmergencyCall;
137 private Uri handle;
138 private int state = State.INVALID;
139 private DisconnectCause disconnectCause;
Eric Erfanianccca3152017-02-22 16:32:36 -0800140
141 private boolean hasShownWiFiToLteHandoverToast;
142 private boolean doNotShowDialogForHandoffToWifiFailure;
143
linyuh183cb712017-12-27 17:02:37 -0800144 private String childNumber;
145 private String lastForwardedNumber;
wangqif4ba3452018-01-09 11:26:29 -0800146 private boolean isCallForwarded;
linyuh183cb712017-12-27 17:02:37 -0800147 private String callSubject;
148 private PhoneAccountHandle phoneAccountHandle;
149 @CallHistoryStatus private int callHistoryStatus = CALL_HISTORY_STATUS_UNKNOWN;
150 private boolean isSpam;
151 private boolean isBlocked;
Eric Erfanian938468d2017-10-24 14:05:52 -0700152
153 @Nullable private Boolean isInUserSpamList;
154
155 @Nullable private Boolean isInUserWhiteList;
156
157 @Nullable private Boolean isInGlobalSpamList;
Eric Erfanianccca3152017-02-22 16:32:36 -0800158 private boolean didShowCameraPermission;
159 private String callProviderLabel;
160 private String callbackNumber;
linyuh183cb712017-12-27 17:02:37 -0800161 private int cameraDirection = CameraDirection.CAMERA_DIRECTION_UNKNOWN;
162 private EnrichedCallCapabilities enrichedCallCapabilities;
163 private Session enrichedCallSession;
Eric Erfanianccca3152017-02-22 16:32:36 -0800164
Eric Erfanian2ca43182017-08-31 06:57:16 -0700165 private int answerAndReleaseButtonDisplayedTimes = 0;
166 private boolean releasedByAnsweringSecondCall = false;
167 // Times when a second call is received but AnswerAndRelease button is not shown
168 // since it's not supported.
169 private int secondCallWithoutAnswerAndReleasedButtonTimes = 0;
roldenburg7bb96232017-10-09 10:32:05 -0700170 private VideoTech videoTech;
Eric Erfanian2ca43182017-08-31 06:57:16 -0700171
wangqi4d705e52017-09-28 12:23:35 -0700172 private com.android.dialer.logging.VideoTech.Type selectedAvailableVideoTechType =
173 com.android.dialer.logging.VideoTech.Type.NONE;
wangqi9982f0d2017-10-11 17:46:07 -0700174 private boolean isVoicemailNumber;
175 private List<PhoneAccountHandle> callCapableAccounts;
176 private String countryIso;
yueg457b3972017-09-18 15:11:47 -0700177
Android Dialer974fc292018-02-01 16:12:25 -0800178 private volatile boolean feedbackRequested = false;
179
Eric Erfanianccca3152017-02-22 16:32:36 -0800180 public static String getNumberFromHandle(Uri handle) {
181 return handle == null ? "" : handle.getSchemeSpecificPart();
182 }
183
184 /**
185 * Whether the call is put on hold by remote party. This is different than the {@link
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700186 * State#ONHOLD} state which indicates that the call is being held locally on the device.
Eric Erfanianccca3152017-02-22 16:32:36 -0800187 */
188 private boolean isRemotelyHeld;
189
Eric Erfanian2ca43182017-08-31 06:57:16 -0700190 /** Indicates whether this call is currently in the process of being merged into a conference. */
191 private boolean isMergeInProcess;
192
Eric Erfanianccca3152017-02-22 16:32:36 -0800193 /**
194 * Indicates whether the phone account associated with this call supports specifying a call
195 * subject.
196 */
linyuh183cb712017-12-27 17:02:37 -0800197 private boolean isCallSubjectSupported;
Eric Erfanianccca3152017-02-22 16:32:36 -0800198
linyuh183cb712017-12-27 17:02:37 -0800199 private final Call.Callback telecomCallCallback =
Eric Erfanianccca3152017-02-22 16:32:36 -0800200 new Call.Callback() {
201 @Override
202 public void onStateChanged(Call call, int newState) {
203 LogUtil.v("TelecomCallCallback.onStateChanged", "call=" + call + " newState=" + newState);
204 update();
205 }
206
207 @Override
208 public void onParentChanged(Call call, Call newParent) {
209 LogUtil.v(
210 "TelecomCallCallback.onParentChanged", "call=" + call + " newParent=" + newParent);
211 update();
212 }
213
214 @Override
215 public void onChildrenChanged(Call call, List<Call> children) {
216 update();
217 }
218
219 @Override
220 public void onDetailsChanged(Call call, Call.Details details) {
Eric Erfanian2ca43182017-08-31 06:57:16 -0700221 LogUtil.v(
222 "TelecomCallCallback.onDetailsChanged", " call=" + call + " details=" + details);
Eric Erfanianccca3152017-02-22 16:32:36 -0800223 update();
224 }
225
226 @Override
227 public void onCannedTextResponsesLoaded(Call call, List<String> cannedTextResponses) {
228 LogUtil.v(
Eric Erfanian2ca43182017-08-31 06:57:16 -0700229 "TelecomCallCallback.onCannedTextResponsesLoaded",
Eric Erfanianccca3152017-02-22 16:32:36 -0800230 "call=" + call + " cannedTextResponses=" + cannedTextResponses);
linyuh183cb712017-12-27 17:02:37 -0800231 for (CannedTextResponsesLoadedListener listener : cannedTextResponsesLoadedListeners) {
Eric Erfanianccca3152017-02-22 16:32:36 -0800232 listener.onCannedTextResponsesLoaded(DialerCall.this);
233 }
234 }
235
236 @Override
237 public void onPostDialWait(Call call, String remainingPostDialSequence) {
238 LogUtil.v(
Eric Erfanian2ca43182017-08-31 06:57:16 -0700239 "TelecomCallCallback.onPostDialWait",
Eric Erfanianccca3152017-02-22 16:32:36 -0800240 "call=" + call + " remainingPostDialSequence=" + remainingPostDialSequence);
241 update();
242 }
243
244 @Override
245 public void onVideoCallChanged(Call call, VideoCall videoCall) {
246 LogUtil.v(
Eric Erfanian2ca43182017-08-31 06:57:16 -0700247 "TelecomCallCallback.onVideoCallChanged", "call=" + call + " videoCall=" + videoCall);
Eric Erfanianccca3152017-02-22 16:32:36 -0800248 update();
249 }
250
251 @Override
252 public void onCallDestroyed(Call call) {
Eric Erfanian2ca43182017-08-31 06:57:16 -0700253 LogUtil.v("TelecomCallCallback.onCallDestroyed", "call=" + call);
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700254 unregisterCallback();
Eric Erfanianccca3152017-02-22 16:32:36 -0800255 }
256
257 @Override
258 public void onConferenceableCallsChanged(Call call, List<Call> conferenceableCalls) {
259 LogUtil.v(
Eric Erfanian2ca43182017-08-31 06:57:16 -0700260 "TelecomCallCallback.onConferenceableCallsChanged",
Eric Erfanianccca3152017-02-22 16:32:36 -0800261 "call %s, conferenceable calls: %d",
262 call,
263 conferenceableCalls.size());
264 update();
265 }
266
267 @Override
wangqi219b8702018-02-13 09:34:41 -0800268 public void onRttModeChanged(Call call, int mode) {
269 LogUtil.v("TelecomCallCallback.onRttModeChanged", "mode=%d", mode);
270 }
271
272 @Override
273 public void onRttRequest(Call call, int id) {
274 LogUtil.v("TelecomCallCallback.onRttRequest", "id=%d", id);
275 }
276
277 @Override
278 public void onRttInitiationFailure(Call call, int reason) {
279 LogUtil.v("TelecomCallCallback.onRttInitiationFailure", "reason=%d", reason);
280 update();
281 }
282
283 @Override
284 public void onRttStatusChanged(Call call, boolean enabled, RttCall rttCall) {
285 LogUtil.v("TelecomCallCallback.onRttStatusChanged", "enabled=%b", enabled);
286 update();
287 }
288
289 @Override
Eric Erfanianccca3152017-02-22 16:32:36 -0800290 public void onConnectionEvent(android.telecom.Call call, String event, Bundle extras) {
291 LogUtil.v(
Eric Erfanian2ca43182017-08-31 06:57:16 -0700292 "TelecomCallCallback.onConnectionEvent",
Eric Erfanianccca3152017-02-22 16:32:36 -0800293 "Call: " + call + ", Event: " + event + ", Extras: " + extras);
294 switch (event) {
295 // The Previous attempt to Merge two calls together has failed in Telecom. We must
296 // now update the UI to possibly re-enable the Merge button based on the number of
297 // currently conferenceable calls available or Connection Capabilities.
298 case android.telecom.Connection.EVENT_CALL_MERGE_FAILED:
299 update();
300 break;
301 case TelephonyManagerCompat.EVENT_HANDOVER_VIDEO_FROM_WIFI_TO_LTE:
302 notifyWiFiToLteHandover();
303 break;
304 case TelephonyManagerCompat.EVENT_HANDOVER_TO_WIFI_FAILED:
305 notifyHandoverToWifiFailed();
306 break;
307 case TelephonyManagerCompat.EVENT_CALL_REMOTELY_HELD:
308 isRemotelyHeld = true;
309 update();
310 break;
311 case TelephonyManagerCompat.EVENT_CALL_REMOTELY_UNHELD:
312 isRemotelyHeld = false;
313 update();
314 break;
Eric Erfanianc857f902017-05-15 14:05:33 -0700315 case TelephonyManagerCompat.EVENT_NOTIFY_INTERNATIONAL_CALL_ON_WFC:
316 notifyInternationalCallOnWifi();
317 break;
Eric Erfanian2ca43182017-08-31 06:57:16 -0700318 case TelephonyManagerCompat.EVENT_MERGE_START:
319 LogUtil.i("DialerCall.onConnectionEvent", "merge start");
320 isMergeInProcess = true;
321 break;
322 case TelephonyManagerCompat.EVENT_MERGE_COMPLETE:
323 LogUtil.i("DialerCall.onConnectionEvent", "merge complete");
324 isMergeInProcess = false;
325 break;
wangqif4ba3452018-01-09 11:26:29 -0800326 case TelephonyManagerCompat.EVENT_CALL_FORWARDED:
327 // Only handle this event for P+ since it's unreliable pre-P.
328 if (BuildCompat.isAtLeastP()) {
329 isCallForwarded = true;
330 update();
331 }
332 break;
Eric Erfanianccca3152017-02-22 16:32:36 -0800333 default:
334 break;
335 }
336 }
337 };
Eric Erfanianc857f902017-05-15 14:05:33 -0700338
linyuh183cb712017-12-27 17:02:37 -0800339 private long timeAddedMs;
Eric Erfanianccca3152017-02-22 16:32:36 -0800340
341 public DialerCall(
342 Context context,
343 DialerCallDelegate dialerCallDelegate,
344 Call telecomCall,
345 LatencyReport latencyReport,
346 boolean registerCallback) {
347 Assert.isNotNull(context);
linyuh183cb712017-12-27 17:02:37 -0800348 this.context = context;
349 this.dialerCallDelegate = dialerCallDelegate;
350 this.telecomCall = telecomCall;
351 this.latencyReport = latencyReport;
352 id = ID_PREFIX + Integer.toString(idCounter++);
Eric Erfanianccca3152017-02-22 16:32:36 -0800353
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700354 // Must be after assigning mTelecomCall
linyuh183cb712017-12-27 17:02:37 -0800355 videoTechManager = new VideoTechManager(this);
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700356
357 updateFromTelecomCall();
Eric Erfanianc857f902017-05-15 14:05:33 -0700358 if (isHiddenNumber() && TextUtils.isEmpty(getNumber())) {
linyuh183cb712017-12-27 17:02:37 -0800359 hiddenId = ++hiddenCounter;
Eric Erfanianc857f902017-05-15 14:05:33 -0700360 } else {
linyuh183cb712017-12-27 17:02:37 -0800361 hiddenId = 0;
Eric Erfanianc857f902017-05-15 14:05:33 -0700362 }
Eric Erfanianccca3152017-02-22 16:32:36 -0800363
364 if (registerCallback) {
linyuh183cb712017-12-27 17:02:37 -0800365 this.telecomCall.registerCallback(telecomCallCallback);
Eric Erfanianccca3152017-02-22 16:32:36 -0800366 }
367
linyuh183cb712017-12-27 17:02:37 -0800368 timeAddedMs = System.currentTimeMillis();
Eric Erfanianccca3152017-02-22 16:32:36 -0800369 parseCallSpecificAppData();
Eric Erfanian2ca43182017-08-31 06:57:16 -0700370
371 updateEnrichedCallSession();
Eric Erfanianccca3152017-02-22 16:32:36 -0800372 }
373
twyendde01c52017-09-22 10:07:31 -0700374 /** Test only constructor to avoid initializing dependencies. */
375 @VisibleForTesting
376 DialerCall(Context context) {
linyuh183cb712017-12-27 17:02:37 -0800377 this.context = context;
378 telecomCall = null;
379 latencyReport = null;
380 id = null;
381 hiddenId = 0;
382 dialerCallDelegate = null;
383 videoTechManager = null;
twyendde01c52017-09-22 10:07:31 -0700384 }
385
Eric Erfanianccca3152017-02-22 16:32:36 -0800386 private static int translateState(int state) {
387 switch (state) {
388 case Call.STATE_NEW:
389 case Call.STATE_CONNECTING:
390 return DialerCall.State.CONNECTING;
391 case Call.STATE_SELECT_PHONE_ACCOUNT:
392 return DialerCall.State.SELECT_PHONE_ACCOUNT;
393 case Call.STATE_DIALING:
394 return DialerCall.State.DIALING;
395 case Call.STATE_PULLING_CALL:
396 return DialerCall.State.PULLING;
397 case Call.STATE_RINGING:
398 return DialerCall.State.INCOMING;
399 case Call.STATE_ACTIVE:
400 return DialerCall.State.ACTIVE;
401 case Call.STATE_HOLDING:
402 return DialerCall.State.ONHOLD;
403 case Call.STATE_DISCONNECTED:
404 return DialerCall.State.DISCONNECTED;
405 case Call.STATE_DISCONNECTING:
406 return DialerCall.State.DISCONNECTING;
407 default:
408 return DialerCall.State.INVALID;
409 }
410 }
411
412 public static boolean areSame(DialerCall call1, DialerCall call2) {
413 if (call1 == null && call2 == null) {
414 return true;
415 } else if (call1 == null || call2 == null) {
416 return false;
417 }
418
419 // otherwise compare call Ids
420 return call1.getId().equals(call2.getId());
421 }
422
Eric Erfanianccca3152017-02-22 16:32:36 -0800423 public void addListener(DialerCallListener listener) {
424 Assert.isMainThread();
linyuh183cb712017-12-27 17:02:37 -0800425 listeners.add(listener);
Eric Erfanianccca3152017-02-22 16:32:36 -0800426 }
427
428 public void removeListener(DialerCallListener listener) {
429 Assert.isMainThread();
linyuh183cb712017-12-27 17:02:37 -0800430 listeners.remove(listener);
Eric Erfanianccca3152017-02-22 16:32:36 -0800431 }
432
433 public void addCannedTextResponsesLoadedListener(CannedTextResponsesLoadedListener listener) {
434 Assert.isMainThread();
linyuh183cb712017-12-27 17:02:37 -0800435 cannedTextResponsesLoadedListeners.add(listener);
Eric Erfanianccca3152017-02-22 16:32:36 -0800436 }
437
438 public void removeCannedTextResponsesLoadedListener(CannedTextResponsesLoadedListener listener) {
439 Assert.isMainThread();
linyuh183cb712017-12-27 17:02:37 -0800440 cannedTextResponsesLoadedListeners.remove(listener);
Eric Erfanianccca3152017-02-22 16:32:36 -0800441 }
442
443 public void notifyWiFiToLteHandover() {
444 LogUtil.i("DialerCall.notifyWiFiToLteHandover", "");
linyuh183cb712017-12-27 17:02:37 -0800445 for (DialerCallListener listener : listeners) {
Eric Erfanianccca3152017-02-22 16:32:36 -0800446 listener.onWiFiToLteHandover();
447 }
448 }
449
450 public void notifyHandoverToWifiFailed() {
451 LogUtil.i("DialerCall.notifyHandoverToWifiFailed", "");
linyuh183cb712017-12-27 17:02:37 -0800452 for (DialerCallListener listener : listeners) {
Eric Erfanianccca3152017-02-22 16:32:36 -0800453 listener.onHandoverToWifiFailure();
454 }
455 }
456
Eric Erfanianc857f902017-05-15 14:05:33 -0700457 public void notifyInternationalCallOnWifi() {
458 LogUtil.enterBlock("DialerCall.notifyInternationalCallOnWifi");
linyuh183cb712017-12-27 17:02:37 -0800459 for (DialerCallListener dialerCallListener : listeners) {
Eric Erfanianc857f902017-05-15 14:05:33 -0700460 dialerCallListener.onInternationalCallOnWifi();
461 }
462 }
463
Eric Erfanianccca3152017-02-22 16:32:36 -0800464 /* package-private */ Call getTelecomCall() {
linyuh183cb712017-12-27 17:02:37 -0800465 return telecomCall;
Eric Erfanianccca3152017-02-22 16:32:36 -0800466 }
Android Dialer974fc292018-02-01 16:12:25 -0800467
Eric Erfanianccca3152017-02-22 16:32:36 -0800468 public StatusHints getStatusHints() {
linyuh183cb712017-12-27 17:02:37 -0800469 return telecomCall.getDetails().getStatusHints();
Eric Erfanianccca3152017-02-22 16:32:36 -0800470 }
471
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700472 public int getCameraDir() {
linyuh183cb712017-12-27 17:02:37 -0800473 return cameraDirection;
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700474 }
475
476 public void setCameraDir(int cameraDir) {
477 if (cameraDir == CameraDirection.CAMERA_DIRECTION_FRONT_FACING
478 || cameraDir == CameraDirection.CAMERA_DIRECTION_BACK_FACING) {
linyuh183cb712017-12-27 17:02:37 -0800479 cameraDirection = cameraDir;
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700480 } else {
linyuh183cb712017-12-27 17:02:37 -0800481 cameraDirection = CameraDirection.CAMERA_DIRECTION_UNKNOWN;
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700482 }
Eric Erfanianccca3152017-02-22 16:32:36 -0800483 }
484
Eric Erfanian2ca43182017-08-31 06:57:16 -0700485 public boolean wasParentCall() {
linyuh183cb712017-12-27 17:02:37 -0800486 return logState.conferencedCalls != 0;
Eric Erfanian2ca43182017-08-31 06:57:16 -0700487 }
488
wangqi9982f0d2017-10-11 17:46:07 -0700489 public boolean isVoiceMailNumber() {
490 return isVoicemailNumber;
491 }
492
493 public List<PhoneAccountHandle> getCallCapableAccounts() {
494 return callCapableAccounts;
495 }
496
497 public String getCountryIso() {
498 return countryIso;
499 }
500
501 private void updateIsVoiceMailNumber() {
502 if (getHandle() != null && PhoneAccount.SCHEME_VOICEMAIL.equals(getHandle().getScheme())) {
503 isVoicemailNumber = true;
roldenburg37a969d2018-02-22 14:46:44 -0800504 return;
wangqi9982f0d2017-10-11 17:46:07 -0700505 }
506
linyuh183cb712017-12-27 17:02:37 -0800507 if (!PermissionsUtil.hasPermission(context, permission.READ_PHONE_STATE)) {
wangqi9982f0d2017-10-11 17:46:07 -0700508 isVoicemailNumber = false;
roldenburg37a969d2018-02-22 14:46:44 -0800509 return;
wangqi9982f0d2017-10-11 17:46:07 -0700510 }
511
linyuh183cb712017-12-27 17:02:37 -0800512 isVoicemailNumber = TelecomUtil.isVoicemailNumber(context, getAccountHandle(), getNumber());
wangqi9982f0d2017-10-11 17:46:07 -0700513 }
514
Eric Erfanianccca3152017-02-22 16:32:36 -0800515 private void update() {
Eric Erfanian2ca43182017-08-31 06:57:16 -0700516 Trace.beginSection("DialerCall.update");
Eric Erfanianccca3152017-02-22 16:32:36 -0800517 int oldState = getState();
roldenburg7bb96232017-10-09 10:32:05 -0700518 // Clear any cache here that could potentially change on update.
519 videoTech = null;
Eric Erfanianccca3152017-02-22 16:32:36 -0800520 // We want to potentially register a video call callback here.
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700521 updateFromTelecomCall();
Eric Erfanianccca3152017-02-22 16:32:36 -0800522 if (oldState != getState() && getState() == DialerCall.State.DISCONNECTED) {
linyuh183cb712017-12-27 17:02:37 -0800523 for (DialerCallListener listener : listeners) {
Eric Erfanianccca3152017-02-22 16:32:36 -0800524 listener.onDialerCallDisconnect();
525 }
linyuh183cb712017-12-27 17:02:37 -0800526 EnrichedCallComponent.get(context)
Eric Erfanian2ca43182017-08-31 06:57:16 -0700527 .getEnrichedCallManager()
528 .unregisterCapabilitiesListener(this);
linyuh183cb712017-12-27 17:02:37 -0800529 EnrichedCallComponent.get(context)
Eric Erfanian2ca43182017-08-31 06:57:16 -0700530 .getEnrichedCallManager()
531 .unregisterStateChangedListener(this);
Eric Erfanianccca3152017-02-22 16:32:36 -0800532 } else {
linyuh183cb712017-12-27 17:02:37 -0800533 for (DialerCallListener listener : listeners) {
Eric Erfanianccca3152017-02-22 16:32:36 -0800534 listener.onDialerCallUpdate();
535 }
536 }
537 Trace.endSection();
538 }
539
wangqi9982f0d2017-10-11 17:46:07 -0700540 @SuppressWarnings("MissingPermission")
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700541 private void updateFromTelecomCall() {
Eric Erfanian2ca43182017-08-31 06:57:16 -0700542 Trace.beginSection("DialerCall.updateFromTelecomCall");
linyuh183cb712017-12-27 17:02:37 -0800543 LogUtil.v("DialerCall.updateFromTelecomCall", telecomCall.toString());
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700544
roldenburg6bd612f2018-01-18 12:57:19 -0800545 videoTechManager.dispatchCallStateChanged(telecomCall.getState(), getAccountHandle());
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700546
linyuh183cb712017-12-27 17:02:37 -0800547 final int translatedState = translateState(telecomCall.getState());
548 if (state != State.BLOCKED) {
Eric Erfanianccca3152017-02-22 16:32:36 -0800549 setState(translatedState);
linyuh183cb712017-12-27 17:02:37 -0800550 setDisconnectCause(telecomCall.getDetails().getDisconnectCause());
Eric Erfanianccca3152017-02-22 16:32:36 -0800551 }
552
linyuh183cb712017-12-27 17:02:37 -0800553 childCallIds.clear();
554 final int numChildCalls = telecomCall.getChildren().size();
Eric Erfanianccca3152017-02-22 16:32:36 -0800555 for (int i = 0; i < numChildCalls; i++) {
linyuh183cb712017-12-27 17:02:37 -0800556 childCallIds.add(
557 dialerCallDelegate
558 .getDialerCallFromTelecomCall(telecomCall.getChildren().get(i))
Eric Erfanianccca3152017-02-22 16:32:36 -0800559 .getId());
560 }
561
562 // The number of conferenced calls can change over the course of the call, so use the
563 // maximum number of conferenced child calls as the metric for conference call usage.
linyuh183cb712017-12-27 17:02:37 -0800564 logState.conferencedCalls = Math.max(numChildCalls, logState.conferencedCalls);
Eric Erfanianccca3152017-02-22 16:32:36 -0800565
linyuh183cb712017-12-27 17:02:37 -0800566 updateFromCallExtras(telecomCall.getDetails().getExtras());
Eric Erfanianccca3152017-02-22 16:32:36 -0800567
568 // If the handle of the call has changed, update state for the call determining if it is an
569 // emergency call.
linyuh183cb712017-12-27 17:02:37 -0800570 Uri newHandle = telecomCall.getDetails().getHandle();
571 if (!Objects.equals(handle, newHandle)) {
572 handle = newHandle;
Eric Erfanianccca3152017-02-22 16:32:36 -0800573 updateEmergencyCallState();
574 }
575
linyuh183cb712017-12-27 17:02:37 -0800576 TelecomManager telecomManager = context.getSystemService(TelecomManager.class);
Eric Erfanianccca3152017-02-22 16:32:36 -0800577 // If the phone account handle of the call is set, cache capability bit indicating whether
578 // the phone account supports call subjects.
linyuh183cb712017-12-27 17:02:37 -0800579 PhoneAccountHandle newPhoneAccountHandle = telecomCall.getDetails().getAccountHandle();
580 if (!Objects.equals(phoneAccountHandle, newPhoneAccountHandle)) {
581 phoneAccountHandle = newPhoneAccountHandle;
Eric Erfanianccca3152017-02-22 16:32:36 -0800582
linyuh183cb712017-12-27 17:02:37 -0800583 if (phoneAccountHandle != null) {
584 PhoneAccount phoneAccount = telecomManager.getPhoneAccount(phoneAccountHandle);
Eric Erfanianccca3152017-02-22 16:32:36 -0800585 if (phoneAccount != null) {
linyuh183cb712017-12-27 17:02:37 -0800586 isCallSubjectSupported =
Eric Erfanianccca3152017-02-22 16:32:36 -0800587 phoneAccount.hasCapabilities(PhoneAccount.CAPABILITY_CALL_SUBJECT);
588 }
589 }
590 }
linyuh183cb712017-12-27 17:02:37 -0800591 if (PermissionsUtil.hasPermission(context, permission.READ_PHONE_STATE)) {
wangqi9982f0d2017-10-11 17:46:07 -0700592 updateIsVoiceMailNumber();
593 callCapableAccounts = telecomManager.getCallCapablePhoneAccounts();
linyuh183cb712017-12-27 17:02:37 -0800594 countryIso = GeoUtil.getCurrentCountryIso(context);
wangqi9982f0d2017-10-11 17:46:07 -0700595 }
Eric Erfanian2ca43182017-08-31 06:57:16 -0700596 Trace.endSection();
Eric Erfanianccca3152017-02-22 16:32:36 -0800597 }
598
599 /**
600 * Tests corruption of the {@code callExtras} bundle by calling {@link
601 * Bundle#containsKey(String)}. If the bundle is corrupted a {@link IllegalArgumentException} will
602 * be thrown and caught by this function.
603 *
604 * @param callExtras the bundle to verify
605 * @return {@code true} if the bundle is corrupted, {@code false} otherwise.
606 */
607 protected boolean areCallExtrasCorrupted(Bundle callExtras) {
608 /**
Eric Erfanian938468d2017-10-24 14:05:52 -0700609 * There's currently a bug in Telephony service (a bug) that could corrupt the extras
Eric Erfanianccca3152017-02-22 16:32:36 -0800610 * bundle, resulting in a IllegalArgumentException while validating data under {@link
611 * Bundle#containsKey(String)}.
612 */
613 try {
614 callExtras.containsKey(Connection.EXTRA_CHILD_ADDRESS);
615 return false;
616 } catch (IllegalArgumentException e) {
617 LogUtil.e(
618 "DialerCall.areCallExtrasCorrupted", "callExtras is corrupted, ignoring exception", e);
619 return true;
620 }
621 }
622
623 protected void updateFromCallExtras(Bundle callExtras) {
624 if (callExtras == null || areCallExtrasCorrupted(callExtras)) {
625 /**
626 * If the bundle is corrupted, abandon information update as a work around. These are not
627 * critical for the dialer to function.
628 */
629 return;
630 }
631 // Check for a change in the child address and notify any listeners.
632 if (callExtras.containsKey(Connection.EXTRA_CHILD_ADDRESS)) {
633 String childNumber = callExtras.getString(Connection.EXTRA_CHILD_ADDRESS);
linyuh183cb712017-12-27 17:02:37 -0800634 if (!Objects.equals(childNumber, this.childNumber)) {
635 this.childNumber = childNumber;
636 for (DialerCallListener listener : listeners) {
Eric Erfanianccca3152017-02-22 16:32:36 -0800637 listener.onDialerCallChildNumberChange();
638 }
639 }
640 }
641
642 // Last forwarded number comes in as an array of strings. We want to choose the
643 // last item in the array. The forwarding numbers arrive independently of when the
644 // call is originally set up, so we need to notify the the UI of the change.
645 if (callExtras.containsKey(Connection.EXTRA_LAST_FORWARDED_NUMBER)) {
646 ArrayList<String> lastForwardedNumbers =
647 callExtras.getStringArrayList(Connection.EXTRA_LAST_FORWARDED_NUMBER);
648
649 if (lastForwardedNumbers != null) {
650 String lastForwardedNumber = null;
651 if (!lastForwardedNumbers.isEmpty()) {
652 lastForwardedNumber = lastForwardedNumbers.get(lastForwardedNumbers.size() - 1);
653 }
654
linyuh183cb712017-12-27 17:02:37 -0800655 if (!Objects.equals(lastForwardedNumber, this.lastForwardedNumber)) {
656 this.lastForwardedNumber = lastForwardedNumber;
657 for (DialerCallListener listener : listeners) {
Eric Erfanianccca3152017-02-22 16:32:36 -0800658 listener.onDialerCallLastForwardedNumberChange();
659 }
660 }
661 }
662 }
663
664 // DialerCall subject is present in the extras at the start of call, so we do not need to
665 // notify any other listeners of this.
666 if (callExtras.containsKey(Connection.EXTRA_CALL_SUBJECT)) {
667 String callSubject = callExtras.getString(Connection.EXTRA_CALL_SUBJECT);
linyuh183cb712017-12-27 17:02:37 -0800668 if (!Objects.equals(this.callSubject, callSubject)) {
669 this.callSubject = callSubject;
Eric Erfanianccca3152017-02-22 16:32:36 -0800670 }
671 }
672 }
673
Eric Erfanianccca3152017-02-22 16:32:36 -0800674 public String getId() {
linyuh183cb712017-12-27 17:02:37 -0800675 return id;
Eric Erfanianccca3152017-02-22 16:32:36 -0800676 }
677
Eric Erfanianc857f902017-05-15 14:05:33 -0700678 /**
679 * @return name appended with a number if the number is restricted/unknown and the user has
680 * received more than one restricted/unknown call.
681 */
682 @Nullable
683 public String updateNameIfRestricted(@Nullable String name) {
linyuh183cb712017-12-27 17:02:37 -0800684 if (name != null && isHiddenNumber() && hiddenId != 0 && hiddenCounter > 1) {
685 return context.getString(R.string.unknown_counter, name, hiddenId);
Eric Erfanianc857f902017-05-15 14:05:33 -0700686 }
687 return name;
688 }
689
690 public static void clearRestrictedCount() {
linyuh183cb712017-12-27 17:02:37 -0800691 hiddenCounter = 0;
Eric Erfanianc857f902017-05-15 14:05:33 -0700692 }
693
694 private boolean isHiddenNumber() {
695 return getNumberPresentation() == TelecomManager.PRESENTATION_RESTRICTED
696 || getNumberPresentation() == TelecomManager.PRESENTATION_UNKNOWN;
697 }
698
Eric Erfanianccca3152017-02-22 16:32:36 -0800699 public boolean hasShownWiFiToLteHandoverToast() {
700 return hasShownWiFiToLteHandoverToast;
701 }
702
703 public void setHasShownWiFiToLteHandoverToast() {
704 hasShownWiFiToLteHandoverToast = true;
705 }
706
707 public boolean showWifiHandoverAlertAsToast() {
708 return doNotShowDialogForHandoffToWifiFailure;
709 }
710
711 public void setDoNotShowDialogForHandoffToWifiFailure(boolean bool) {
712 doNotShowDialogForHandoffToWifiFailure = bool;
713 }
714
715 public long getTimeAddedMs() {
linyuh183cb712017-12-27 17:02:37 -0800716 return timeAddedMs;
Eric Erfanianccca3152017-02-22 16:32:36 -0800717 }
718
719 @Nullable
720 public String getNumber() {
linyuh183cb712017-12-27 17:02:37 -0800721 return TelecomCallUtil.getNumber(telecomCall);
Eric Erfanianccca3152017-02-22 16:32:36 -0800722 }
723
724 public void blockCall() {
linyuh183cb712017-12-27 17:02:37 -0800725 telecomCall.reject(false, null);
Eric Erfanianccca3152017-02-22 16:32:36 -0800726 setState(State.BLOCKED);
727 }
728
729 @Nullable
730 public Uri getHandle() {
linyuh183cb712017-12-27 17:02:37 -0800731 return telecomCall == null ? null : telecomCall.getDetails().getHandle();
Eric Erfanianccca3152017-02-22 16:32:36 -0800732 }
733
734 public boolean isEmergencyCall() {
linyuh183cb712017-12-27 17:02:37 -0800735 return isEmergencyCall;
Eric Erfanianccca3152017-02-22 16:32:36 -0800736 }
737
738 public boolean isPotentialEmergencyCallback() {
739 // The property PROPERTY_EMERGENCY_CALLBACK_MODE is only set for CDMA calls when the system
740 // is actually in emergency callback mode (ie data is disabled).
741 if (hasProperty(Details.PROPERTY_EMERGENCY_CALLBACK_MODE)) {
742 return true;
743 }
744 // We want to treat any incoming call that arrives a short time after an outgoing emergency call
745 // as a potential emergency callback.
746 if (getExtras() != null
747 && getExtras().getLong(TelecomManagerCompat.EXTRA_LAST_EMERGENCY_CALLBACK_TIME_MILLIS, 0)
748 > 0) {
749 long lastEmergencyCallMillis =
750 getExtras().getLong(TelecomManagerCompat.EXTRA_LAST_EMERGENCY_CALLBACK_TIME_MILLIS, 0);
751 if (isInEmergencyCallbackWindow(lastEmergencyCallMillis)) {
752 return true;
753 }
754 }
755 return false;
756 }
757
758 boolean isInEmergencyCallbackWindow(long timestampMillis) {
759 long emergencyCallbackWindowMillis =
linyuh183cb712017-12-27 17:02:37 -0800760 ConfigProviderBindings.get(context)
Eric Erfanianccca3152017-02-22 16:32:36 -0800761 .getLong(CONFIG_EMERGENCY_CALLBACK_WINDOW_MILLIS, TimeUnit.MINUTES.toMillis(5));
762 return System.currentTimeMillis() - timestampMillis < emergencyCallbackWindowMillis;
763 }
764
765 public int getState() {
linyuh183cb712017-12-27 17:02:37 -0800766 if (telecomCall != null && telecomCall.getParent() != null) {
Eric Erfanianccca3152017-02-22 16:32:36 -0800767 return State.CONFERENCED;
768 } else {
linyuh183cb712017-12-27 17:02:37 -0800769 return state;
Eric Erfanianccca3152017-02-22 16:32:36 -0800770 }
771 }
772
yueg265089a2017-10-06 14:35:15 -0700773 public int getNonConferenceState() {
linyuh183cb712017-12-27 17:02:37 -0800774 return state;
yueg265089a2017-10-06 14:35:15 -0700775 }
776
Eric Erfanianccca3152017-02-22 16:32:36 -0800777 public void setState(int state) {
Eric Erfanian2ca43182017-08-31 06:57:16 -0700778 if (state == State.INCOMING) {
linyuh183cb712017-12-27 17:02:37 -0800779 logState.isIncoming = true;
Eric Erfanian2ca43182017-08-31 06:57:16 -0700780 } else if (state == State.DISCONNECTED) {
781 long newDuration =
Eric Erfanianccca3152017-02-22 16:32:36 -0800782 getConnectTimeMillis() == 0 ? 0 : System.currentTimeMillis() - getConnectTimeMillis();
linyuh183cb712017-12-27 17:02:37 -0800783 if (this.state != state) {
784 logState.duration = newDuration;
Eric Erfanian2ca43182017-08-31 06:57:16 -0700785 } else {
786 LogUtil.i(
787 "DialerCall.setState",
788 "ignoring state transition from DISCONNECTED to DISCONNECTED."
789 + " Duration would have changed from %s to %s",
linyuh183cb712017-12-27 17:02:37 -0800790 logState.duration,
Eric Erfanian2ca43182017-08-31 06:57:16 -0700791 newDuration);
792 }
Eric Erfanianccca3152017-02-22 16:32:36 -0800793 }
linyuh183cb712017-12-27 17:02:37 -0800794 this.state = state;
Eric Erfanianccca3152017-02-22 16:32:36 -0800795 }
796
797 public int getNumberPresentation() {
linyuh183cb712017-12-27 17:02:37 -0800798 return telecomCall == null ? -1 : telecomCall.getDetails().getHandlePresentation();
Eric Erfanianccca3152017-02-22 16:32:36 -0800799 }
800
801 public int getCnapNamePresentation() {
linyuh183cb712017-12-27 17:02:37 -0800802 return telecomCall == null ? -1 : telecomCall.getDetails().getCallerDisplayNamePresentation();
Eric Erfanianccca3152017-02-22 16:32:36 -0800803 }
804
805 @Nullable
806 public String getCnapName() {
linyuh183cb712017-12-27 17:02:37 -0800807 return telecomCall == null ? null : getTelecomCall().getDetails().getCallerDisplayName();
Eric Erfanianccca3152017-02-22 16:32:36 -0800808 }
809
810 public Bundle getIntentExtras() {
linyuh183cb712017-12-27 17:02:37 -0800811 return telecomCall.getDetails().getIntentExtras();
Eric Erfanianccca3152017-02-22 16:32:36 -0800812 }
813
814 @Nullable
815 public Bundle getExtras() {
linyuh183cb712017-12-27 17:02:37 -0800816 return telecomCall == null ? null : telecomCall.getDetails().getExtras();
Eric Erfanianccca3152017-02-22 16:32:36 -0800817 }
818
819 /** @return The child number for the call, or {@code null} if none specified. */
820 public String getChildNumber() {
linyuh183cb712017-12-27 17:02:37 -0800821 return childNumber;
Eric Erfanianccca3152017-02-22 16:32:36 -0800822 }
823
824 /** @return The last forwarded number for the call, or {@code null} if none specified. */
825 public String getLastForwardedNumber() {
linyuh183cb712017-12-27 17:02:37 -0800826 return lastForwardedNumber;
Eric Erfanianccca3152017-02-22 16:32:36 -0800827 }
828
wangqif4ba3452018-01-09 11:26:29 -0800829 public boolean isCallForwarded() {
830 return isCallForwarded;
831 }
832
Eric Erfanianccca3152017-02-22 16:32:36 -0800833 /** @return The call subject, or {@code null} if none specified. */
834 public String getCallSubject() {
linyuh183cb712017-12-27 17:02:37 -0800835 return callSubject;
Eric Erfanianccca3152017-02-22 16:32:36 -0800836 }
837
838 /**
839 * @return {@code true} if the call's phone account supports call subjects, {@code false}
840 * otherwise.
841 */
842 public boolean isCallSubjectSupported() {
linyuh183cb712017-12-27 17:02:37 -0800843 return isCallSubjectSupported;
Eric Erfanianccca3152017-02-22 16:32:36 -0800844 }
845
846 /** Returns call disconnect cause, defined by {@link DisconnectCause}. */
847 public DisconnectCause getDisconnectCause() {
linyuh183cb712017-12-27 17:02:37 -0800848 if (state == State.DISCONNECTED || state == State.IDLE) {
849 return disconnectCause;
Eric Erfanianccca3152017-02-22 16:32:36 -0800850 }
851
852 return new DisconnectCause(DisconnectCause.UNKNOWN);
853 }
854
855 public void setDisconnectCause(DisconnectCause disconnectCause) {
linyuh183cb712017-12-27 17:02:37 -0800856 this.disconnectCause = disconnectCause;
857 logState.disconnectCause = this.disconnectCause;
Eric Erfanianccca3152017-02-22 16:32:36 -0800858 }
859
860 /** Returns the possible text message responses. */
861 public List<String> getCannedSmsResponses() {
linyuh183cb712017-12-27 17:02:37 -0800862 return telecomCall.getCannedTextResponses();
Eric Erfanianccca3152017-02-22 16:32:36 -0800863 }
864
865 /** Checks if the call supports the given set of capabilities supplied as a bit mask. */
866 public boolean can(int capabilities) {
linyuh183cb712017-12-27 17:02:37 -0800867 int supportedCapabilities = telecomCall.getDetails().getCallCapabilities();
Eric Erfanianccca3152017-02-22 16:32:36 -0800868
869 if ((capabilities & Call.Details.CAPABILITY_MERGE_CONFERENCE) != 0) {
870 // We allow you to merge if the capabilities allow it or if it is a call with
871 // conferenceable calls.
linyuh183cb712017-12-27 17:02:37 -0800872 if (telecomCall.getConferenceableCalls().isEmpty()
Eric Erfanianccca3152017-02-22 16:32:36 -0800873 && ((Call.Details.CAPABILITY_MERGE_CONFERENCE & supportedCapabilities) == 0)) {
874 // Cannot merge calls if there are no calls to merge with.
875 return false;
876 }
877 capabilities &= ~Call.Details.CAPABILITY_MERGE_CONFERENCE;
878 }
879 return (capabilities == (capabilities & supportedCapabilities));
880 }
881
882 public boolean hasProperty(int property) {
linyuh183cb712017-12-27 17:02:37 -0800883 return telecomCall.getDetails().hasProperty(property);
Eric Erfanianccca3152017-02-22 16:32:36 -0800884 }
885
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700886 @NonNull
Eric Erfanianccca3152017-02-22 16:32:36 -0800887 public String getUniqueCallId() {
888 return uniqueCallId;
889 }
890
891 /** Gets the time when the call first became active. */
892 public long getConnectTimeMillis() {
linyuh183cb712017-12-27 17:02:37 -0800893 return telecomCall.getDetails().getConnectTimeMillis();
Eric Erfanianccca3152017-02-22 16:32:36 -0800894 }
895
896 public boolean isConferenceCall() {
897 return hasProperty(Call.Details.PROPERTY_CONFERENCE);
898 }
899
900 @Nullable
901 public GatewayInfo getGatewayInfo() {
linyuh183cb712017-12-27 17:02:37 -0800902 return telecomCall == null ? null : telecomCall.getDetails().getGatewayInfo();
Eric Erfanianccca3152017-02-22 16:32:36 -0800903 }
904
905 @Nullable
906 public PhoneAccountHandle getAccountHandle() {
linyuh183cb712017-12-27 17:02:37 -0800907 return telecomCall == null ? null : telecomCall.getDetails().getAccountHandle();
Eric Erfanianccca3152017-02-22 16:32:36 -0800908 }
909
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700910 /** @return The {@link VideoCall} instance associated with the {@link Call}. */
Eric Erfanianccca3152017-02-22 16:32:36 -0800911 public VideoCall getVideoCall() {
linyuh183cb712017-12-27 17:02:37 -0800912 return telecomCall == null ? null : telecomCall.getVideoCall();
Eric Erfanianccca3152017-02-22 16:32:36 -0800913 }
914
915 public List<String> getChildCallIds() {
linyuh183cb712017-12-27 17:02:37 -0800916 return childCallIds;
Eric Erfanianccca3152017-02-22 16:32:36 -0800917 }
918
919 public String getParentId() {
linyuh183cb712017-12-27 17:02:37 -0800920 Call parentCall = telecomCall.getParent();
Eric Erfanianccca3152017-02-22 16:32:36 -0800921 if (parentCall != null) {
linyuh183cb712017-12-27 17:02:37 -0800922 return dialerCallDelegate.getDialerCallFromTelecomCall(parentCall).getId();
Eric Erfanianccca3152017-02-22 16:32:36 -0800923 }
924 return null;
925 }
926
927 public int getVideoState() {
linyuh183cb712017-12-27 17:02:37 -0800928 return telecomCall.getDetails().getVideoState();
Eric Erfanianccca3152017-02-22 16:32:36 -0800929 }
930
931 public boolean isVideoCall() {
roldenburg2cec3802017-10-11 16:26:51 -0700932 return getVideoTech().isTransmittingOrReceiving() || VideoProfile.isVideo(getVideoState());
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700933 }
934
wangqi8d407a02018-02-15 15:32:52 -0800935 @TargetApi(28)
wangqi219b8702018-02-13 09:34:41 -0800936 public boolean isRttCall() {
937 if (BuildCompat.isAtLeastP()) {
938 return getTelecomCall().isRttActive();
939 } else {
940 return false;
941 }
942 }
943
wangqi153af2f2018-02-15 16:21:49 -0800944 @TargetApi(28)
945 public RttCall getRttCall() {
946 if (!isRttCall()) {
947 return null;
948 }
949 return getTelecomCall().getRttCall();
950 }
951
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700952 public boolean hasReceivedVideoUpgradeRequest() {
953 return VideoUtils.hasReceivedVideoUpgradeRequest(getVideoTech().getSessionModificationState());
954 }
955
956 public boolean hasSentVideoUpgradeRequest() {
957 return VideoUtils.hasSentVideoUpgradeRequest(getVideoTech().getSessionModificationState());
Eric Erfanianccca3152017-02-22 16:32:36 -0800958 }
959
wangqi219b8702018-02-13 09:34:41 -0800960 public boolean hasSentRttUpgradeRequest() {
wangqi219b8702018-02-13 09:34:41 -0800961 return false;
962 }
963
Eric Erfanianccca3152017-02-22 16:32:36 -0800964 /**
965 * Determines if the call handle is an emergency number or not and caches the result to avoid
966 * repeated calls to isEmergencyNumber.
967 */
968 private void updateEmergencyCallState() {
linyuh183cb712017-12-27 17:02:37 -0800969 isEmergencyCall = TelecomCallUtil.isEmergencyCall(telecomCall);
Eric Erfanianccca3152017-02-22 16:32:36 -0800970 }
971
Eric Erfanianccca3152017-02-22 16:32:36 -0800972 public LogState getLogState() {
linyuh183cb712017-12-27 17:02:37 -0800973 return logState;
Eric Erfanianccca3152017-02-22 16:32:36 -0800974 }
975
976 /**
977 * Determines if the call is an external call.
978 *
979 * <p>An external call is one which does not exist locally for the {@link
980 * android.telecom.ConnectionService} it is associated with.
981 *
982 * <p>External calls are only supported in N and higher.
983 *
984 * @return {@code true} if the call is an external call, {@code false} otherwise.
985 */
986 public boolean isExternalCall() {
987 return VERSION.SDK_INT >= VERSION_CODES.N
988 && hasProperty(CallCompat.Details.PROPERTY_IS_EXTERNAL_CALL);
989 }
990
991 /**
Eric Erfanianccca3152017-02-22 16:32:36 -0800992 * Determines if answering this call will cause an ongoing video call to be dropped.
993 *
994 * @return {@code true} if answering this call will drop an ongoing video call, {@code false}
995 * otherwise.
996 */
997 public boolean answeringDisconnectsForegroundVideoCall() {
998 Bundle extras = getExtras();
999 if (extras == null
1000 || !extras.containsKey(CallCompat.Details.EXTRA_ANSWERING_DROPS_FOREGROUND_CALL)) {
1001 return false;
1002 }
1003 return extras.getBoolean(CallCompat.Details.EXTRA_ANSWERING_DROPS_FOREGROUND_CALL);
1004 }
1005
1006 private void parseCallSpecificAppData() {
1007 if (isExternalCall()) {
1008 return;
1009 }
1010
linyuh183cb712017-12-27 17:02:37 -08001011 logState.callSpecificAppData = CallIntentParser.getCallSpecificAppData(getIntentExtras());
1012 if (logState.callSpecificAppData == null) {
Eric Erfanian8369df02017-05-03 10:27:13 -07001013
linyuh183cb712017-12-27 17:02:37 -08001014 logState.callSpecificAppData =
Eric Erfanian8369df02017-05-03 10:27:13 -07001015 CallSpecificAppData.newBuilder()
1016 .setCallInitiationType(CallInitiationType.Type.EXTERNAL_INITIATION)
1017 .build();
Eric Erfanianccca3152017-02-22 16:32:36 -08001018 }
1019 if (getState() == State.INCOMING) {
linyuh183cb712017-12-27 17:02:37 -08001020 logState.callSpecificAppData =
1021 logState
Eric Erfanian8369df02017-05-03 10:27:13 -07001022 .callSpecificAppData
1023 .toBuilder()
1024 .setCallInitiationType(CallInitiationType.Type.INCOMING_INITIATION)
1025 .build();
Eric Erfanianccca3152017-02-22 16:32:36 -08001026 }
1027 }
1028
1029 @Override
1030 public String toString() {
linyuh183cb712017-12-27 17:02:37 -08001031 if (telecomCall == null) {
Eric Erfanianccca3152017-02-22 16:32:36 -08001032 // This should happen only in testing since otherwise we would never have a null
1033 // Telecom call.
linyuh183cb712017-12-27 17:02:37 -08001034 return String.valueOf(id);
Eric Erfanianccca3152017-02-22 16:32:36 -08001035 }
1036
1037 return String.format(
1038 Locale.US,
1039 "[%s, %s, %s, %s, children:%s, parent:%s, "
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001040 + "conferenceable:%s, videoState:%s, mSessionModificationState:%d, CameraDir:%s]",
linyuh183cb712017-12-27 17:02:37 -08001041 id,
Eric Erfanianccca3152017-02-22 16:32:36 -08001042 State.toString(getState()),
linyuh183cb712017-12-27 17:02:37 -08001043 Details.capabilitiesToString(telecomCall.getDetails().getCallCapabilities()),
1044 Details.propertiesToString(telecomCall.getDetails().getCallProperties()),
1045 childCallIds,
Eric Erfanianccca3152017-02-22 16:32:36 -08001046 getParentId(),
linyuh183cb712017-12-27 17:02:37 -08001047 this.telecomCall.getConferenceableCalls(),
1048 VideoProfile.videoStateToString(telecomCall.getDetails().getVideoState()),
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001049 getVideoTech().getSessionModificationState(),
1050 getCameraDir());
Eric Erfanianccca3152017-02-22 16:32:36 -08001051 }
1052
1053 public String toSimpleString() {
1054 return super.toString();
1055 }
1056
1057 @CallHistoryStatus
1058 public int getCallHistoryStatus() {
linyuh183cb712017-12-27 17:02:37 -08001059 return callHistoryStatus;
Eric Erfanianccca3152017-02-22 16:32:36 -08001060 }
1061
1062 public void setCallHistoryStatus(@CallHistoryStatus int callHistoryStatus) {
linyuh183cb712017-12-27 17:02:37 -08001063 this.callHistoryStatus = callHistoryStatus;
Eric Erfanianccca3152017-02-22 16:32:36 -08001064 }
1065
1066 public boolean didShowCameraPermission() {
1067 return didShowCameraPermission;
1068 }
1069
1070 public void setDidShowCameraPermission(boolean didShow) {
1071 didShowCameraPermission = didShow;
1072 }
1073
Eric Erfanian938468d2017-10-24 14:05:52 -07001074 @Nullable
1075 public Boolean isInGlobalSpamList() {
Eric Erfanianccca3152017-02-22 16:32:36 -08001076 return isInGlobalSpamList;
1077 }
1078
1079 public void setIsInGlobalSpamList(boolean inSpamList) {
1080 isInGlobalSpamList = inSpamList;
1081 }
1082
Eric Erfanian938468d2017-10-24 14:05:52 -07001083 @Nullable
1084 public Boolean isInUserSpamList() {
Eric Erfanianccca3152017-02-22 16:32:36 -08001085 return isInUserSpamList;
1086 }
1087
1088 public void setIsInUserSpamList(boolean inSpamList) {
1089 isInUserSpamList = inSpamList;
1090 }
1091
Eric Erfanian938468d2017-10-24 14:05:52 -07001092 @Nullable
1093 public Boolean isInUserWhiteList() {
Eric Erfanianccca3152017-02-22 16:32:36 -08001094 return isInUserWhiteList;
1095 }
1096
1097 public void setIsInUserWhiteList(boolean inWhiteList) {
1098 isInUserWhiteList = inWhiteList;
1099 }
1100
1101 public boolean isSpam() {
linyuh183cb712017-12-27 17:02:37 -08001102 return isSpam;
Eric Erfanianccca3152017-02-22 16:32:36 -08001103 }
1104
1105 public void setSpam(boolean isSpam) {
linyuh183cb712017-12-27 17:02:37 -08001106 this.isSpam = isSpam;
Eric Erfanianccca3152017-02-22 16:32:36 -08001107 }
1108
1109 public boolean isBlocked() {
linyuh183cb712017-12-27 17:02:37 -08001110 return isBlocked;
Eric Erfanianccca3152017-02-22 16:32:36 -08001111 }
1112
1113 public void setBlockedStatus(boolean isBlocked) {
linyuh183cb712017-12-27 17:02:37 -08001114 this.isBlocked = isBlocked;
Eric Erfanianccca3152017-02-22 16:32:36 -08001115 }
1116
1117 public boolean isRemotelyHeld() {
1118 return isRemotelyHeld;
1119 }
1120
Eric Erfanian2ca43182017-08-31 06:57:16 -07001121 public boolean isMergeInProcess() {
1122 return isMergeInProcess;
1123 }
1124
Eric Erfanianccca3152017-02-22 16:32:36 -08001125 public boolean isIncoming() {
linyuh183cb712017-12-27 17:02:37 -08001126 return logState.isIncoming;
Eric Erfanianccca3152017-02-22 16:32:36 -08001127 }
1128
erfanian2cf2c342017-12-21 12:01:33 -08001129 /**
1130 * Try and determine if the call used assisted dialing.
1131 *
1132 * <p>We will not be able to verify a call underwent assisted dialing until the Platform
1133 * implmentation is complete in P+.
1134 *
1135 * @return a boolean indicating assisted dialing may have been performed
1136 */
Eric Erfanian2ca43182017-08-31 06:57:16 -07001137 public boolean isAssistedDialed() {
1138 if (getIntentExtras() != null) {
erfanian2cf2c342017-12-21 12:01:33 -08001139 // O_MR1 and below uses the existence of USE_ASSISTED_DIALING to indicate assisted dialing
1140 // was used. The Dialer client is responsible for performing assisted dialing before
1141 // placing the outgoing call.
1142 //
1143 // The existence of the assisted dialing extras indicates that assisted dialing took place.
1144 if (getIntentExtras().getBoolean(TelephonyManagerCompat.USE_ASSISTED_DIALING, false)
1145 && getAssistedDialingExtras() != null
1146 && Build.VERSION.SDK_INT <= ConcreteCreator.BUILD_CODE_CEILING) {
1147 return true;
1148 }
1149 }
1150
1151 // Starting in P+ USE_ASSISTED_DIALING indicates that the client requested the platform
1152 // perform assisted dialing. PROPERTY_ASSISTED_DIALING_USED indicates assisted dialing took
1153 // place.
1154 if (hasProperty(TelephonyManagerCompat.PROPERTY_ASSISTED_DIALING_USED)
erfanianf2556612018-01-23 09:55:59 -08001155 && BuildCompat.isAtLeastP()) {
erfanian2cf2c342017-12-21 12:01:33 -08001156 return true;
Eric Erfanian2ca43182017-08-31 06:57:16 -07001157 }
1158 return false;
1159 }
1160
erfanian2cf2c342017-12-21 12:01:33 -08001161 @Nullable
erfaniand0f207f2017-10-11 12:23:29 -07001162 public TransformationInfo getAssistedDialingExtras() {
erfanian2cf2c342017-12-21 12:01:33 -08001163 if (getIntentExtras() == null) {
1164 return null;
erfaniand0f207f2017-10-11 12:23:29 -07001165 }
erfanian2cf2c342017-12-21 12:01:33 -08001166
erfanianf2556612018-01-23 09:55:59 -08001167 if (BuildCompat.isAtLeastP()) {
1168 if (getExtras() == null) {
1169 return null;
1170 }
1171
1172 if (getExtras()
1173 .getParcelable(TelephonyManagerCompat.EXTRA_ASSISTED_DIALING_TRANSFORMATION_INFO)
1174 == null) {
1175 return null;
1176 }
1177
1178 // TODO(erfanian): Use the framework transformation info when we can link against it
1179 return null;
1180 }
1181
erfanian2cf2c342017-12-21 12:01:33 -08001182 if (getIntentExtras().getBundle(TelephonyManagerCompat.ASSISTED_DIALING_EXTRAS) == null) {
1183 return null;
1184 }
1185
erfanianf2556612018-01-23 09:55:59 -08001186 // Used in N-OMR1
erfanian2cf2c342017-12-21 12:01:33 -08001187 return TransformationInfo.newInstanceFromBundle(
1188 getIntentExtras().getBundle(TelephonyManagerCompat.ASSISTED_DIALING_EXTRAS));
erfaniand0f207f2017-10-11 12:23:29 -07001189 }
1190
Eric Erfanianccca3152017-02-22 16:32:36 -08001191 public LatencyReport getLatencyReport() {
linyuh183cb712017-12-27 17:02:37 -08001192 return latencyReport;
Eric Erfanianccca3152017-02-22 16:32:36 -08001193 }
1194
Eric Erfanian2ca43182017-08-31 06:57:16 -07001195 public int getAnswerAndReleaseButtonDisplayedTimes() {
1196 return answerAndReleaseButtonDisplayedTimes;
1197 }
1198
1199 public void increaseAnswerAndReleaseButtonDisplayedTimes() {
1200 answerAndReleaseButtonDisplayedTimes++;
1201 }
1202
1203 public boolean getReleasedByAnsweringSecondCall() {
1204 return releasedByAnsweringSecondCall;
1205 }
1206
1207 public void setReleasedByAnsweringSecondCall(boolean releasedByAnsweringSecondCall) {
1208 this.releasedByAnsweringSecondCall = releasedByAnsweringSecondCall;
1209 }
1210
1211 public int getSecondCallWithoutAnswerAndReleasedButtonTimes() {
1212 return secondCallWithoutAnswerAndReleasedButtonTimes;
1213 }
1214
1215 public void increaseSecondCallWithoutAnswerAndReleasedButtonTimes() {
1216 secondCallWithoutAnswerAndReleasedButtonTimes++;
1217 }
1218
Eric Erfanian8369df02017-05-03 10:27:13 -07001219 @Nullable
1220 public EnrichedCallCapabilities getEnrichedCallCapabilities() {
linyuh183cb712017-12-27 17:02:37 -08001221 return enrichedCallCapabilities;
Eric Erfanian8369df02017-05-03 10:27:13 -07001222 }
1223
1224 public void setEnrichedCallCapabilities(
1225 @Nullable EnrichedCallCapabilities mEnrichedCallCapabilities) {
linyuh183cb712017-12-27 17:02:37 -08001226 this.enrichedCallCapabilities = mEnrichedCallCapabilities;
Eric Erfanian8369df02017-05-03 10:27:13 -07001227 }
1228
1229 @Nullable
1230 public Session getEnrichedCallSession() {
linyuh183cb712017-12-27 17:02:37 -08001231 return enrichedCallSession;
Eric Erfanian8369df02017-05-03 10:27:13 -07001232 }
1233
1234 public void setEnrichedCallSession(@Nullable Session mEnrichedCallSession) {
linyuh183cb712017-12-27 17:02:37 -08001235 this.enrichedCallSession = mEnrichedCallSession;
Eric Erfanian8369df02017-05-03 10:27:13 -07001236 }
1237
Eric Erfanianccca3152017-02-22 16:32:36 -08001238 public void unregisterCallback() {
linyuh183cb712017-12-27 17:02:37 -08001239 telecomCall.unregisterCallback(telecomCallCallback);
Eric Erfanianccca3152017-02-22 16:32:36 -08001240 }
1241
Eric Erfanianccca3152017-02-22 16:32:36 -08001242 public void phoneAccountSelected(PhoneAccountHandle accountHandle, boolean setDefault) {
1243 LogUtil.i(
1244 "DialerCall.phoneAccountSelected",
1245 "accountHandle: %s, setDefault: %b",
1246 accountHandle,
1247 setDefault);
linyuh183cb712017-12-27 17:02:37 -08001248 telecomCall.phoneAccountSelected(accountHandle, setDefault);
Eric Erfanianccca3152017-02-22 16:32:36 -08001249 }
1250
1251 public void disconnect() {
1252 LogUtil.i("DialerCall.disconnect", "");
1253 setState(DialerCall.State.DISCONNECTING);
linyuh183cb712017-12-27 17:02:37 -08001254 for (DialerCallListener listener : listeners) {
Eric Erfanianccca3152017-02-22 16:32:36 -08001255 listener.onDialerCallUpdate();
1256 }
linyuh183cb712017-12-27 17:02:37 -08001257 telecomCall.disconnect();
Eric Erfanianccca3152017-02-22 16:32:36 -08001258 }
1259
1260 public void hold() {
1261 LogUtil.i("DialerCall.hold", "");
linyuh183cb712017-12-27 17:02:37 -08001262 telecomCall.hold();
Eric Erfanianccca3152017-02-22 16:32:36 -08001263 }
1264
1265 public void unhold() {
1266 LogUtil.i("DialerCall.unhold", "");
linyuh183cb712017-12-27 17:02:37 -08001267 telecomCall.unhold();
Eric Erfanianccca3152017-02-22 16:32:36 -08001268 }
1269
1270 public void splitFromConference() {
1271 LogUtil.i("DialerCall.splitFromConference", "");
linyuh183cb712017-12-27 17:02:37 -08001272 telecomCall.splitFromConference();
Eric Erfanianccca3152017-02-22 16:32:36 -08001273 }
1274
1275 public void answer(int videoState) {
1276 LogUtil.i("DialerCall.answer", "videoState: " + videoState);
linyuh183cb712017-12-27 17:02:37 -08001277 telecomCall.answer(videoState);
Eric Erfanianccca3152017-02-22 16:32:36 -08001278 }
1279
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001280 public void answer() {
linyuh183cb712017-12-27 17:02:37 -08001281 answer(telecomCall.getDetails().getVideoState());
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001282 }
1283
Eric Erfanianccca3152017-02-22 16:32:36 -08001284 public void reject(boolean rejectWithMessage, String message) {
1285 LogUtil.i("DialerCall.reject", "");
linyuh183cb712017-12-27 17:02:37 -08001286 telecomCall.reject(rejectWithMessage, message);
Eric Erfanianccca3152017-02-22 16:32:36 -08001287 }
1288
1289 /** Return the string label to represent the call provider */
1290 public String getCallProviderLabel() {
1291 if (callProviderLabel == null) {
1292 PhoneAccount account = getPhoneAccount();
1293 if (account != null && !TextUtils.isEmpty(account.getLabel())) {
wangqi9982f0d2017-10-11 17:46:07 -07001294 if (callCapableAccounts != null && callCapableAccounts.size() > 1) {
Eric Erfanianccca3152017-02-22 16:32:36 -08001295 callProviderLabel = account.getLabel().toString();
1296 }
1297 }
1298 if (callProviderLabel == null) {
1299 callProviderLabel = "";
1300 }
1301 }
1302 return callProviderLabel;
1303 }
1304
1305 private PhoneAccount getPhoneAccount() {
1306 PhoneAccountHandle accountHandle = getAccountHandle();
1307 if (accountHandle == null) {
1308 return null;
1309 }
linyuh183cb712017-12-27 17:02:37 -08001310 return context.getSystemService(TelecomManager.class).getPhoneAccount(accountHandle);
Eric Erfanianccca3152017-02-22 16:32:36 -08001311 }
1312
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001313 public VideoTech getVideoTech() {
roldenburg7bb96232017-10-09 10:32:05 -07001314 if (videoTech == null) {
roldenburg6bd612f2018-01-18 12:57:19 -08001315 videoTech = videoTechManager.getVideoTech(getAccountHandle());
roldenburg7bb96232017-10-09 10:32:05 -07001316
1317 // Only store the first video tech type found to be available during the life of the call.
1318 if (selectedAvailableVideoTechType == com.android.dialer.logging.VideoTech.Type.NONE) {
1319 // Update the video tech.
1320 selectedAvailableVideoTechType = videoTech.getVideoTechType();
1321 }
1322 }
Eric Erfanian2ca43182017-08-31 06:57:16 -07001323 return videoTech;
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001324 }
1325
Eric Erfanianccca3152017-02-22 16:32:36 -08001326 public String getCallbackNumber() {
1327 if (callbackNumber == null) {
1328 // Show the emergency callback number if either:
1329 // 1. This is an emergency call.
1330 // 2. The phone is in Emergency Callback Mode, which means we should show the callback
1331 // number.
1332 boolean showCallbackNumber = hasProperty(Details.PROPERTY_EMERGENCY_CALLBACK_MODE);
1333
1334 if (isEmergencyCall() || showCallbackNumber) {
wangqi339b4f32017-09-18 14:32:09 -07001335 callbackNumber =
linyuh183cb712017-12-27 17:02:37 -08001336 context.getSystemService(TelecomManager.class).getLine1Number(getAccountHandle());
Eric Erfanianccca3152017-02-22 16:32:36 -08001337 }
1338
Eric Erfanianccca3152017-02-22 16:32:36 -08001339 if (callbackNumber == null) {
1340 callbackNumber = "";
1341 }
1342 }
1343 return callbackNumber;
1344 }
1345
wangqi97539352017-09-25 11:15:16 -07001346 public String getSimCountryIso() {
1347 String simCountryIso =
linyuh183cb712017-12-27 17:02:37 -08001348 TelephonyManagerCompat.getTelephonyManagerForPhoneAccountHandle(context, getAccountHandle())
wangqi97539352017-09-25 11:15:16 -07001349 .getSimCountryIso();
1350 if (!TextUtils.isEmpty(simCountryIso)) {
1351 simCountryIso = simCountryIso.toUpperCase(Locale.US);
1352 }
1353 return simCountryIso;
1354 }
1355
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001356 @Override
1357 public void onVideoTechStateChanged() {
1358 update();
1359 }
1360
1361 @Override
1362 public void onSessionModificationStateChanged() {
wangqi9982f0d2017-10-11 17:46:07 -07001363 Trace.beginSection("DialerCall.onSessionModificationStateChanged");
linyuh183cb712017-12-27 17:02:37 -08001364 for (DialerCallListener listener : listeners) {
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001365 listener.onDialerCallSessionModificationStateChange();
1366 }
wangqi9982f0d2017-10-11 17:46:07 -07001367 Trace.endSection();
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001368 }
1369
1370 @Override
1371 public void onCameraDimensionsChanged(int width, int height) {
1372 InCallVideoCallCallbackNotifier.getInstance().cameraDimensionsChanged(this, width, height);
1373 }
1374
1375 @Override
1376 public void onPeerDimensionsChanged(int width, int height) {
1377 InCallVideoCallCallbackNotifier.getInstance().peerDimensionsChanged(this, width, height);
1378 }
1379
1380 @Override
1381 public void onVideoUpgradeRequestReceived() {
1382 LogUtil.enterBlock("DialerCall.onVideoUpgradeRequestReceived");
1383
linyuh183cb712017-12-27 17:02:37 -08001384 for (DialerCallListener listener : listeners) {
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001385 listener.onDialerCallUpgradeToVideo();
1386 }
1387
1388 update();
Eric Erfanian8369df02017-05-03 10:27:13 -07001389
linyuh183cb712017-12-27 17:02:37 -08001390 Logger.get(context)
Eric Erfanian8369df02017-05-03 10:27:13 -07001391 .logCallImpression(
1392 DialerImpression.Type.VIDEO_CALL_REQUEST_RECEIVED, getUniqueCallId(), getTimeAddedMs());
1393 }
1394
1395 @Override
1396 public void onUpgradedToVideo(boolean switchToSpeaker) {
1397 LogUtil.enterBlock("DialerCall.onUpgradedToVideo");
1398
1399 if (!switchToSpeaker) {
1400 return;
1401 }
1402
1403 CallAudioState audioState = AudioModeProvider.getInstance().getAudioState();
1404
1405 if (0 != (CallAudioState.ROUTE_BLUETOOTH & audioState.getSupportedRouteMask())) {
1406 LogUtil.e(
1407 "DialerCall.onUpgradedToVideo",
1408 "toggling speakerphone not allowed when bluetooth supported.");
1409 return;
1410 }
1411
1412 if (audioState.getRoute() == CallAudioState.ROUTE_SPEAKER) {
1413 return;
1414 }
1415
1416 TelecomAdapter.getInstance().setAudioRoute(CallAudioState.ROUTE_SPEAKER);
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001417 }
1418
Eric Erfanian2ca43182017-08-31 06:57:16 -07001419 @Override
1420 public void onCapabilitiesUpdated() {
1421 if (getNumber() == null) {
1422 return;
1423 }
1424 EnrichedCallCapabilities capabilities =
linyuh183cb712017-12-27 17:02:37 -08001425 EnrichedCallComponent.get(context).getEnrichedCallManager().getCapabilities(getNumber());
Eric Erfanian2ca43182017-08-31 06:57:16 -07001426 if (capabilities != null) {
1427 setEnrichedCallCapabilities(capabilities);
1428 update();
1429 }
1430 }
1431
1432 @Override
1433 public void onEnrichedCallStateChanged() {
1434 updateEnrichedCallSession();
1435 }
1436
1437 @Override
1438 public void onImpressionLoggingNeeded(DialerImpression.Type impressionType) {
linyuh183cb712017-12-27 17:02:37 -08001439 Logger.get(context).logCallImpression(impressionType, getUniqueCallId(), getTimeAddedMs());
twyendde01c52017-09-22 10:07:31 -07001440 if (impressionType == DialerImpression.Type.LIGHTBRINGER_UPGRADE_REQUESTED) {
1441 if (getLogState().contactLookupResult == Type.NOT_FOUND) {
linyuh183cb712017-12-27 17:02:37 -08001442 Logger.get(context)
twyendde01c52017-09-22 10:07:31 -07001443 .logCallImpression(
1444 DialerImpression.Type.LIGHTBRINGER_NON_CONTACT_UPGRADE_REQUESTED,
1445 getUniqueCallId(),
1446 getTimeAddedMs());
1447 }
1448 }
Eric Erfanian2ca43182017-08-31 06:57:16 -07001449 }
1450
1451 private void updateEnrichedCallSession() {
1452 if (getNumber() == null) {
1453 return;
1454 }
1455 if (getEnrichedCallSession() != null) {
1456 // State changes to existing sessions are currently handled by the UI components (which have
1457 // their own listeners). Someday instead we could remove those and just call update() here and
1458 // have the usual onDialerCallUpdate update the UI.
1459 dispatchOnEnrichedCallSessionUpdate();
1460 return;
1461 }
1462
linyuh183cb712017-12-27 17:02:37 -08001463 EnrichedCallManager manager = EnrichedCallComponent.get(context).getEnrichedCallManager();
Eric Erfanian2ca43182017-08-31 06:57:16 -07001464
1465 Filter filter =
1466 isIncoming()
1467 ? manager.createIncomingCallComposerFilter()
1468 : manager.createOutgoingCallComposerFilter();
1469
1470 Session session = manager.getSession(getUniqueCallId(), getNumber(), filter);
1471 if (session == null) {
1472 return;
1473 }
1474
1475 session.setUniqueDialerCallId(getUniqueCallId());
1476 setEnrichedCallSession(session);
1477
1478 LogUtil.i(
1479 "DialerCall.updateEnrichedCallSession",
1480 "setting session %d's dialer id to %s",
1481 session.getSessionId(),
1482 getUniqueCallId());
1483
1484 dispatchOnEnrichedCallSessionUpdate();
1485 }
1486
1487 private void dispatchOnEnrichedCallSessionUpdate() {
linyuh183cb712017-12-27 17:02:37 -08001488 for (DialerCallListener listener : listeners) {
Eric Erfanian2ca43182017-08-31 06:57:16 -07001489 listener.onEnrichedCallSessionUpdate();
1490 }
1491 }
1492
1493 void onRemovedFromCallList() {
1494 // Ensure we clean up when this call is removed.
linyuh183cb712017-12-27 17:02:37 -08001495 videoTechManager.dispatchRemovedFromCallList();
Eric Erfanian2ca43182017-08-31 06:57:16 -07001496 }
1497
wangqi4d705e52017-09-28 12:23:35 -07001498 public com.android.dialer.logging.VideoTech.Type getSelectedAvailableVideoTechType() {
1499 return selectedAvailableVideoTechType;
yueg457b3972017-09-18 15:11:47 -07001500 }
1501
Android Dialer974fc292018-02-01 16:12:25 -08001502 public void markFeedbackRequested() {
1503 feedbackRequested = true;
1504 }
1505
1506 public boolean isFeedbackRequested() {
1507 return feedbackRequested;
1508 }
1509
Eric Erfanianccca3152017-02-22 16:32:36 -08001510 /**
1511 * Specifies whether a number is in the call history or not. {@link #CALL_HISTORY_STATUS_UNKNOWN}
1512 * means there is no result.
1513 */
1514 @IntDef({
1515 CALL_HISTORY_STATUS_UNKNOWN,
1516 CALL_HISTORY_STATUS_PRESENT,
1517 CALL_HISTORY_STATUS_NOT_PRESENT
1518 })
1519 @Retention(RetentionPolicy.SOURCE)
1520 public @interface CallHistoryStatus {}
1521
1522 /* Defines different states of this call */
1523 public static class State {
1524
1525 public static final int INVALID = 0;
1526 public static final int NEW = 1; /* The call is new. */
1527 public static final int IDLE = 2; /* The call is idle. Nothing active */
1528 public static final int ACTIVE = 3; /* There is an active call */
1529 public static final int INCOMING = 4; /* A normal incoming phone call */
1530 public static final int CALL_WAITING = 5; /* Incoming call while another is active */
1531 public static final int DIALING = 6; /* An outgoing call during dial phase */
1532 public static final int REDIALING = 7; /* Subsequent dialing attempt after a failure */
1533 public static final int ONHOLD = 8; /* An active phone call placed on hold */
1534 public static final int DISCONNECTING = 9; /* A call is being ended. */
1535 public static final int DISCONNECTED = 10; /* State after a call disconnects */
1536 public static final int CONFERENCED = 11; /* DialerCall part of a conference call */
1537 public static final int SELECT_PHONE_ACCOUNT = 12; /* Waiting for account selection */
1538 public static final int CONNECTING = 13; /* Waiting for Telecom broadcast to finish */
1539 public static final int BLOCKED = 14; /* The number was found on the block list */
1540 public static final int PULLING = 15; /* An external call being pulled to the device */
Eric Erfanian2ca43182017-08-31 06:57:16 -07001541 public static final int CALL_PENDING = 16; /* A call is pending on a long process to finish */
Eric Erfanianccca3152017-02-22 16:32:36 -08001542
1543 public static boolean isConnectingOrConnected(int state) {
1544 switch (state) {
1545 case ACTIVE:
1546 case INCOMING:
1547 case CALL_WAITING:
1548 case CONNECTING:
1549 case DIALING:
1550 case PULLING:
1551 case REDIALING:
1552 case ONHOLD:
1553 case CONFERENCED:
1554 return true;
1555 default:
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001556 return false;
Eric Erfanianccca3152017-02-22 16:32:36 -08001557 }
Eric Erfanianccca3152017-02-22 16:32:36 -08001558 }
1559
1560 public static boolean isDialing(int state) {
1561 return state == DIALING || state == PULLING || state == REDIALING;
1562 }
1563
1564 public static String toString(int state) {
1565 switch (state) {
1566 case INVALID:
1567 return "INVALID";
1568 case NEW:
1569 return "NEW";
1570 case IDLE:
1571 return "IDLE";
1572 case ACTIVE:
1573 return "ACTIVE";
1574 case INCOMING:
1575 return "INCOMING";
1576 case CALL_WAITING:
1577 return "CALL_WAITING";
1578 case DIALING:
1579 return "DIALING";
1580 case PULLING:
1581 return "PULLING";
1582 case REDIALING:
1583 return "REDIALING";
1584 case ONHOLD:
1585 return "ONHOLD";
1586 case DISCONNECTING:
1587 return "DISCONNECTING";
1588 case DISCONNECTED:
1589 return "DISCONNECTED";
1590 case CONFERENCED:
1591 return "CONFERENCED";
1592 case SELECT_PHONE_ACCOUNT:
1593 return "SELECT_PHONE_ACCOUNT";
1594 case CONNECTING:
1595 return "CONNECTING";
1596 case BLOCKED:
1597 return "BLOCKED";
1598 default:
1599 return "UNKNOWN";
1600 }
1601 }
1602 }
1603
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001604 /** Camera direction constants */
1605 public static class CameraDirection {
Eric Erfanianccca3152017-02-22 16:32:36 -08001606 public static final int CAMERA_DIRECTION_UNKNOWN = -1;
1607 public static final int CAMERA_DIRECTION_FRONT_FACING = CameraCharacteristics.LENS_FACING_FRONT;
1608 public static final int CAMERA_DIRECTION_BACK_FACING = CameraCharacteristics.LENS_FACING_BACK;
Eric Erfanianccca3152017-02-22 16:32:36 -08001609 }
1610
1611 /**
1612 * Tracks any state variables that is useful for logging. There is some amount of overlap with
1613 * existing call member variables, but this duplication helps to ensure that none of these logging
1614 * variables will interface with/and affect call logic.
1615 */
1616 public static class LogState {
1617
1618 public DisconnectCause disconnectCause;
1619 public boolean isIncoming = false;
Eric Erfanian8369df02017-05-03 10:27:13 -07001620 public ContactLookupResult.Type contactLookupResult =
1621 ContactLookupResult.Type.UNKNOWN_LOOKUP_RESULT_TYPE;
Eric Erfanianccca3152017-02-22 16:32:36 -08001622 public CallSpecificAppData callSpecificAppData;
1623 // If this was a conference call, the total number of calls involved in the conference.
1624 public int conferencedCalls = 0;
1625 public long duration = 0;
1626 public boolean isLogged = false;
1627
Eric Erfanian8369df02017-05-03 10:27:13 -07001628 private static String lookupToString(ContactLookupResult.Type lookupType) {
Eric Erfanianccca3152017-02-22 16:32:36 -08001629 switch (lookupType) {
Eric Erfanian8369df02017-05-03 10:27:13 -07001630 case LOCAL_CONTACT:
Eric Erfanianccca3152017-02-22 16:32:36 -08001631 return "Local";
Eric Erfanian8369df02017-05-03 10:27:13 -07001632 case LOCAL_CACHE:
Eric Erfanianccca3152017-02-22 16:32:36 -08001633 return "Cache";
Eric Erfanian8369df02017-05-03 10:27:13 -07001634 case REMOTE:
Eric Erfanianccca3152017-02-22 16:32:36 -08001635 return "Remote";
Eric Erfanian8369df02017-05-03 10:27:13 -07001636 case EMERGENCY:
Eric Erfanianccca3152017-02-22 16:32:36 -08001637 return "Emergency";
Eric Erfanian8369df02017-05-03 10:27:13 -07001638 case VOICEMAIL:
Eric Erfanianccca3152017-02-22 16:32:36 -08001639 return "Voicemail";
1640 default:
1641 return "Not found";
1642 }
1643 }
1644
1645 private static String initiationToString(CallSpecificAppData callSpecificAppData) {
1646 if (callSpecificAppData == null) {
1647 return "null";
1648 }
Eric Erfanian8369df02017-05-03 10:27:13 -07001649 switch (callSpecificAppData.getCallInitiationType()) {
1650 case INCOMING_INITIATION:
Eric Erfanianccca3152017-02-22 16:32:36 -08001651 return "Incoming";
Eric Erfanian8369df02017-05-03 10:27:13 -07001652 case DIALPAD:
Eric Erfanianccca3152017-02-22 16:32:36 -08001653 return "Dialpad";
Eric Erfanian8369df02017-05-03 10:27:13 -07001654 case SPEED_DIAL:
Eric Erfanianccca3152017-02-22 16:32:36 -08001655 return "Speed Dial";
Eric Erfanian8369df02017-05-03 10:27:13 -07001656 case REMOTE_DIRECTORY:
Eric Erfanianccca3152017-02-22 16:32:36 -08001657 return "Remote Directory";
Eric Erfanian8369df02017-05-03 10:27:13 -07001658 case SMART_DIAL:
Eric Erfanianccca3152017-02-22 16:32:36 -08001659 return "Smart Dial";
Eric Erfanian8369df02017-05-03 10:27:13 -07001660 case REGULAR_SEARCH:
Eric Erfanianccca3152017-02-22 16:32:36 -08001661 return "Regular Search";
Eric Erfanian8369df02017-05-03 10:27:13 -07001662 case CALL_LOG:
Eric Erfanianccca3152017-02-22 16:32:36 -08001663 return "DialerCall Log";
Eric Erfanian8369df02017-05-03 10:27:13 -07001664 case CALL_LOG_FILTER:
Eric Erfanianccca3152017-02-22 16:32:36 -08001665 return "DialerCall Log Filter";
Eric Erfanian8369df02017-05-03 10:27:13 -07001666 case VOICEMAIL_LOG:
Eric Erfanianccca3152017-02-22 16:32:36 -08001667 return "Voicemail Log";
Eric Erfanian8369df02017-05-03 10:27:13 -07001668 case CALL_DETAILS:
Eric Erfanianccca3152017-02-22 16:32:36 -08001669 return "DialerCall Details";
Eric Erfanian8369df02017-05-03 10:27:13 -07001670 case QUICK_CONTACTS:
Eric Erfanianccca3152017-02-22 16:32:36 -08001671 return "Quick Contacts";
Eric Erfanian8369df02017-05-03 10:27:13 -07001672 case EXTERNAL_INITIATION:
Eric Erfanianccca3152017-02-22 16:32:36 -08001673 return "External";
Eric Erfanian8369df02017-05-03 10:27:13 -07001674 case LAUNCHER_SHORTCUT:
Eric Erfanianccca3152017-02-22 16:32:36 -08001675 return "Launcher Shortcut";
1676 default:
Eric Erfanian8369df02017-05-03 10:27:13 -07001677 return "Unknown: " + callSpecificAppData.getCallInitiationType();
Eric Erfanianccca3152017-02-22 16:32:36 -08001678 }
1679 }
1680
1681 @Override
1682 public String toString() {
1683 return String.format(
1684 Locale.US,
1685 "["
1686 + "%s, " // DisconnectCause toString already describes the object type
1687 + "isIncoming: %s, "
1688 + "contactLookup: %s, "
1689 + "callInitiation: %s, "
1690 + "duration: %s"
1691 + "]",
1692 disconnectCause,
1693 isIncoming,
1694 lookupToString(contactLookupResult),
1695 initiationToString(callSpecificAppData),
1696 duration);
1697 }
1698 }
1699
roldenburgd7490db2018-01-09 13:51:29 -08001700 /** Coordinates the available VideoTech implementations for a call. */
1701 @VisibleForTesting
1702 public static class VideoTechManager {
Eric Erfaniand8046e52017-04-06 09:41:50 -07001703 private final Context context;
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001704 private final EmptyVideoTech emptyVideoTech = new EmptyVideoTech();
roldenburgd7490db2018-01-09 13:51:29 -08001705 private final VideoTech rcsVideoShare;
Eric Erfanian90508232017-03-24 09:31:16 -07001706 private final List<VideoTech> videoTechs;
roldenburg7bb96232017-10-09 10:32:05 -07001707 private VideoTech savedTech;
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001708
roldenburgd7490db2018-01-09 13:51:29 -08001709 @VisibleForTesting
1710 public VideoTechManager(DialerCall call) {
linyuh183cb712017-12-27 17:02:37 -08001711 this.context = call.context;
Eric Erfaniand8046e52017-04-06 09:41:50 -07001712
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001713 String phoneNumber = call.getNumber();
Eric Erfaniand8046e52017-04-06 09:41:50 -07001714 phoneNumber = phoneNumber != null ? phoneNumber : "";
Eric Erfanian2ca43182017-08-31 06:57:16 -07001715 phoneNumber = phoneNumber.replaceAll("[^+0-9]", "");
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001716
1717 // Insert order here determines the priority of that video tech option
Eric Erfanian8369df02017-05-03 10:27:13 -07001718 videoTechs = new ArrayList<>();
yueg457b3972017-09-18 15:11:47 -07001719
linyuh183cb712017-12-27 17:02:37 -08001720 videoTechs.add(new ImsVideoTech(Logger.get(call.context), call, call.telecomCall));
Eric Erfanian90508232017-03-24 09:31:16 -07001721
roldenburgd7490db2018-01-09 13:51:29 -08001722 rcsVideoShare =
linyuh183cb712017-12-27 17:02:37 -08001723 EnrichedCallComponent.get(call.context)
Eric Erfanian90508232017-03-24 09:31:16 -07001724 .getRcsVideoShareFactory()
1725 .newRcsVideoShare(
linyuh183cb712017-12-27 17:02:37 -08001726 EnrichedCallComponent.get(call.context).getEnrichedCallManager(),
Eric Erfanian90508232017-03-24 09:31:16 -07001727 call,
Eric Erfaniand8046e52017-04-06 09:41:50 -07001728 phoneNumber);
roldenburg3eca69f2018-01-16 12:07:04 -08001729 videoTechs.add(rcsVideoShare);
Eric Erfaniand8046e52017-04-06 09:41:50 -07001730
1731 videoTechs.add(
roldenburg4f026392017-10-13 18:42:20 -07001732 new DuoVideoTech(
linyuh183cb712017-12-27 17:02:37 -08001733 DuoComponent.get(call.context).getDuo(), call, call.telecomCall, phoneNumber));
roldenburgd7490db2018-01-09 13:51:29 -08001734
1735 savedTech = emptyVideoTech;
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001736 }
1737
roldenburgd7490db2018-01-09 13:51:29 -08001738 @VisibleForTesting
roldenburg6bd612f2018-01-18 12:57:19 -08001739 public VideoTech getVideoTech(PhoneAccountHandle phoneAccountHandle) {
roldenburgd7490db2018-01-09 13:51:29 -08001740 if (savedTech == emptyVideoTech) {
1741 for (VideoTech tech : videoTechs) {
roldenburg6bd612f2018-01-18 12:57:19 -08001742 if (tech.isAvailable(context, phoneAccountHandle)) {
roldenburgd7490db2018-01-09 13:51:29 -08001743 savedTech = tech;
1744 savedTech.becomePrimary();
1745 break;
1746 }
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001747 }
roldenburg6bd612f2018-01-18 12:57:19 -08001748 } else if (savedTech instanceof DuoVideoTech
1749 && rcsVideoShare.isAvailable(context, phoneAccountHandle)) {
roldenburgd7490db2018-01-09 13:51:29 -08001750 // RCS Video Share will become available after the capability exchange which is slower than
1751 // Duo reading local contacts for reachability. If Video Share becomes available and we are
1752 // not in the middle of any session changes, let it take over.
1753 savedTech = rcsVideoShare;
1754 rcsVideoShare.becomePrimary();
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001755 }
1756
roldenburgd7490db2018-01-09 13:51:29 -08001757 return savedTech;
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001758 }
1759
roldenburgd7490db2018-01-09 13:51:29 -08001760 @VisibleForTesting
roldenburg6bd612f2018-01-18 12:57:19 -08001761 public void dispatchCallStateChanged(int newState, PhoneAccountHandle phoneAccountHandle) {
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001762 for (VideoTech videoTech : videoTechs) {
roldenburg6bd612f2018-01-18 12:57:19 -08001763 videoTech.onCallStateChanged(context, newState, phoneAccountHandle);
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001764 }
1765 }
Eric Erfanian2ca43182017-08-31 06:57:16 -07001766
1767 void dispatchRemovedFromCallList() {
1768 for (VideoTech videoTech : videoTechs) {
1769 videoTech.onRemovedFromCallList();
1770 }
1771 }
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001772 }
1773
Eric Erfanianccca3152017-02-22 16:32:36 -08001774 /** Called when canned text responses have been loaded. */
1775 public interface CannedTextResponsesLoadedListener {
1776 void onCannedTextResponsesLoaded(DialerCall call);
1777 }
1778}