blob: 4815a6e41b7a0ec086efa3ec9b58a7119322aee4 [file] [log] [blame]
Eric Erfanianccca3152017-02-22 16:32:36 -08001/*
2 * Copyright (C) 2013 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.incallui.call;
18
wangqi9982f0d2017-10-11 17:46:07 -070019import android.Manifest.permission;
wangqida410d32018-03-06 16:51:38 -080020import android.annotation.SuppressLint;
wangqi8d407a02018-02-15 15:32:52 -080021import android.annotation.TargetApi;
Eric Erfanianccca3152017-02-22 16:32:36 -080022import android.content.Context;
23import android.hardware.camera2.CameraCharacteristics;
24import android.net.Uri;
erfanian2cf2c342017-12-21 12:01:33 -080025import android.os.Build;
Eric Erfanianccca3152017-02-22 16:32:36 -080026import android.os.Build.VERSION;
27import android.os.Build.VERSION_CODES;
28import android.os.Bundle;
wangqida410d32018-03-06 16:51:38 -080029import android.os.PersistableBundle;
Eric Erfanianccca3152017-02-22 16:32:36 -080030import android.os.Trace;
31import android.support.annotation.IntDef;
Eric Erfaniand5e47f62017-03-15 14:41:07 -070032import android.support.annotation.NonNull;
Eric Erfanianccca3152017-02-22 16:32:36 -080033import android.support.annotation.Nullable;
twyendde01c52017-09-22 10:07:31 -070034import android.support.annotation.VisibleForTesting;
wangqif4ba3452018-01-09 11:26:29 -080035import android.support.v4.os.BuildCompat;
Eric Erfanianccca3152017-02-22 16:32:36 -080036import android.telecom.Call;
37import android.telecom.Call.Details;
wangqi219b8702018-02-13 09:34:41 -080038import android.telecom.Call.RttCall;
Eric Erfanian8369df02017-05-03 10:27:13 -070039import android.telecom.CallAudioState;
Eric Erfanianccca3152017-02-22 16:32:36 -080040import android.telecom.Connection;
41import android.telecom.DisconnectCause;
42import android.telecom.GatewayInfo;
43import android.telecom.InCallService.VideoCall;
44import android.telecom.PhoneAccount;
45import android.telecom.PhoneAccountHandle;
46import android.telecom.StatusHints;
47import android.telecom.TelecomManager;
48import android.telecom.VideoProfile;
Eric Erfanianccca3152017-02-22 16:32:36 -080049import android.text.TextUtils;
roldenburg08424ee2018-03-28 17:02:46 -070050import android.widget.Toast;
Eric Erfanianccca3152017-02-22 16:32:36 -080051import com.android.contacts.common.compat.CallCompat;
Eric Erfanianccca3152017-02-22 16:32:36 -080052import com.android.contacts.common.compat.telecom.TelecomManagerCompat;
erfanian2cf2c342017-12-21 12:01:33 -080053import com.android.dialer.assisteddialing.ConcreteCreator;
erfaniand0f207f2017-10-11 12:23:29 -070054import com.android.dialer.assisteddialing.TransformationInfo;
Eric Erfanian8369df02017-05-03 10:27:13 -070055import com.android.dialer.callintent.CallInitiationType;
Eric Erfanianccca3152017-02-22 16:32:36 -080056import com.android.dialer.callintent.CallIntentParser;
Eric Erfanian8369df02017-05-03 10:27:13 -070057import com.android.dialer.callintent.CallSpecificAppData;
Eric Erfanianccca3152017-02-22 16:32:36 -080058import com.android.dialer.common.Assert;
Eric Erfanianccca3152017-02-22 16:32:36 -080059import com.android.dialer.common.LogUtil;
Eric Erfanian2ca43182017-08-31 06:57:16 -070060import com.android.dialer.compat.telephony.TelephonyManagerCompat;
61import com.android.dialer.configprovider.ConfigProviderBindings;
roldenburg4f026392017-10-13 18:42:20 -070062import com.android.dialer.duo.DuoComponent;
Eric Erfanian8369df02017-05-03 10:27:13 -070063import com.android.dialer.enrichedcall.EnrichedCallCapabilities;
Eric Erfaniand5e47f62017-03-15 14:41:07 -070064import com.android.dialer.enrichedcall.EnrichedCallComponent;
Eric Erfanian2ca43182017-08-31 06:57:16 -070065import com.android.dialer.enrichedcall.EnrichedCallManager;
66import com.android.dialer.enrichedcall.EnrichedCallManager.CapabilitiesListener;
67import com.android.dialer.enrichedcall.EnrichedCallManager.Filter;
68import com.android.dialer.enrichedcall.EnrichedCallManager.StateChangedListener;
Eric Erfanian8369df02017-05-03 10:27:13 -070069import com.android.dialer.enrichedcall.Session;
wangqi9982f0d2017-10-11 17:46:07 -070070import com.android.dialer.location.GeoUtil;
Eric Erfanian8369df02017-05-03 10:27:13 -070071import com.android.dialer.logging.ContactLookupResult;
twyendde01c52017-09-22 10:07:31 -070072import com.android.dialer.logging.ContactLookupResult.Type;
Eric Erfanian8369df02017-05-03 10:27:13 -070073import com.android.dialer.logging.DialerImpression;
74import com.android.dialer.logging.Logger;
twyen73a74c32018-03-07 12:12:24 -080075import com.android.dialer.preferredsim.PreferredAccountRecorder;
twyena4745bd2017-12-12 18:40:11 -080076import com.android.dialer.telecom.TelecomCallUtil;
wangqi9982f0d2017-10-11 17:46:07 -070077import com.android.dialer.telecom.TelecomUtil;
Eric Erfanianc857f902017-05-15 14:05:33 -070078import com.android.dialer.theme.R;
wangqi9982f0d2017-10-11 17:46:07 -070079import com.android.dialer.util.PermissionsUtil;
Eric Erfanian8369df02017-05-03 10:27:13 -070080import com.android.incallui.audiomode.AudioModeProvider;
Eric Erfanianccca3152017-02-22 16:32:36 -080081import com.android.incallui.latencyreport.LatencyReport;
Eric Erfaniand5e47f62017-03-15 14:41:07 -070082import com.android.incallui.videotech.VideoTech;
83import com.android.incallui.videotech.VideoTech.VideoTechListener;
roldenburg4f026392017-10-13 18:42:20 -070084import com.android.incallui.videotech.duo.DuoVideoTech;
Eric Erfaniand5e47f62017-03-15 14:41:07 -070085import com.android.incallui.videotech.empty.EmptyVideoTech;
86import com.android.incallui.videotech.ims.ImsVideoTech;
Eric Erfanian90508232017-03-24 09:31:16 -070087import com.android.incallui.videotech.utils.VideoUtils;
Eric Erfanianccca3152017-02-22 16:32:36 -080088import java.lang.annotation.Retention;
89import java.lang.annotation.RetentionPolicy;
90import java.util.ArrayList;
91import java.util.List;
92import java.util.Locale;
93import java.util.Objects;
94import java.util.UUID;
95import java.util.concurrent.CopyOnWriteArrayList;
96import java.util.concurrent.TimeUnit;
97
98/** Describes a single call and its state. */
Eric Erfanian2ca43182017-08-31 06:57:16 -070099public class DialerCall implements VideoTechListener, StateChangedListener, CapabilitiesListener {
Eric Erfanianccca3152017-02-22 16:32:36 -0800100
101 public static final int CALL_HISTORY_STATUS_UNKNOWN = 0;
102 public static final int CALL_HISTORY_STATUS_PRESENT = 1;
103 public static final int CALL_HISTORY_STATUS_NOT_PRESENT = 2;
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700104
105 // Hard coded property for {@code Call}. Upstreamed change from Motorola.
Eric Erfanian938468d2017-10-24 14:05:52 -0700106 // TODO(a bug): Move it to Telecom in framework.
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700107 public static final int PROPERTY_CODEC_KNOWN = 0x04000000;
108
Eric Erfanianccca3152017-02-22 16:32:36 -0800109 private static final String ID_PREFIX = "DialerCall_";
110 private static final String CONFIG_EMERGENCY_CALLBACK_WINDOW_MILLIS =
111 "emergency_callback_window_millis";
linyuh183cb712017-12-27 17:02:37 -0800112 private static int idCounter = 0;
Eric Erfanianccca3152017-02-22 16:32:36 -0800113
114 /**
Eric Erfanianc857f902017-05-15 14:05:33 -0700115 * A counter used to append to restricted/private/hidden calls so that users can identify them in
116 * a conversation. This value is reset in {@link CallList#onCallRemoved(Context, Call)} when there
117 * are no live calls.
118 */
linyuh183cb712017-12-27 17:02:37 -0800119 private static int hiddenCounter;
Eric Erfanianc857f902017-05-15 14:05:33 -0700120
121 /**
Eric Erfanianccca3152017-02-22 16:32:36 -0800122 * The unique call ID for every call. This will help us to identify each call and allow us the
123 * ability to stitch impressions to calls if needed.
124 */
125 private final String uniqueCallId = UUID.randomUUID().toString();
126
linyuh183cb712017-12-27 17:02:37 -0800127 private final Call telecomCall;
128 private final LatencyReport latencyReport;
129 private final String id;
130 private final int hiddenId;
131 private final List<String> childCallIds = new ArrayList<>();
132 private final LogState logState = new LogState();
133 private final Context context;
134 private final DialerCallDelegate dialerCallDelegate;
135 private final List<DialerCallListener> listeners = new CopyOnWriteArrayList<>();
136 private final List<CannedTextResponsesLoadedListener> cannedTextResponsesLoadedListeners =
Eric Erfanianccca3152017-02-22 16:32:36 -0800137 new CopyOnWriteArrayList<>();
linyuh183cb712017-12-27 17:02:37 -0800138 private final VideoTechManager videoTechManager;
Eric Erfanianccca3152017-02-22 16:32:36 -0800139
erfaniand05d8992018-03-20 19:42:26 -0700140 private boolean isSpeakEasyCall;
linyuh183cb712017-12-27 17:02:37 -0800141 private boolean isEmergencyCall;
142 private Uri handle;
143 private int state = State.INVALID;
144 private DisconnectCause disconnectCause;
Eric Erfanianccca3152017-02-22 16:32:36 -0800145
roldenburg08424ee2018-03-28 17:02:46 -0700146 private boolean hasShownLteToWiFiHandoverToast;
Eric Erfanianccca3152017-02-22 16:32:36 -0800147 private boolean hasShownWiFiToLteHandoverToast;
148 private boolean doNotShowDialogForHandoffToWifiFailure;
149
linyuh183cb712017-12-27 17:02:37 -0800150 private String childNumber;
151 private String lastForwardedNumber;
wangqif4ba3452018-01-09 11:26:29 -0800152 private boolean isCallForwarded;
linyuh183cb712017-12-27 17:02:37 -0800153 private String callSubject;
154 private PhoneAccountHandle phoneAccountHandle;
155 @CallHistoryStatus private int callHistoryStatus = CALL_HISTORY_STATUS_UNKNOWN;
156 private boolean isSpam;
157 private boolean isBlocked;
Eric Erfanian938468d2017-10-24 14:05:52 -0700158
159 @Nullable private Boolean isInUserSpamList;
160
161 @Nullable private Boolean isInUserWhiteList;
162
163 @Nullable private Boolean isInGlobalSpamList;
Eric Erfanianccca3152017-02-22 16:32:36 -0800164 private boolean didShowCameraPermission;
wangqida410d32018-03-06 16:51:38 -0800165 private boolean didDismissVideoChargesAlertDialog;
166 private PersistableBundle carrierConfig;
Eric Erfanianccca3152017-02-22 16:32:36 -0800167 private String callProviderLabel;
168 private String callbackNumber;
linyuh183cb712017-12-27 17:02:37 -0800169 private int cameraDirection = CameraDirection.CAMERA_DIRECTION_UNKNOWN;
170 private EnrichedCallCapabilities enrichedCallCapabilities;
171 private Session enrichedCallSession;
Eric Erfanianccca3152017-02-22 16:32:36 -0800172
Eric Erfanian2ca43182017-08-31 06:57:16 -0700173 private int answerAndReleaseButtonDisplayedTimes = 0;
174 private boolean releasedByAnsweringSecondCall = false;
175 // Times when a second call is received but AnswerAndRelease button is not shown
176 // since it's not supported.
177 private int secondCallWithoutAnswerAndReleasedButtonTimes = 0;
roldenburg7bb96232017-10-09 10:32:05 -0700178 private VideoTech videoTech;
Eric Erfanian2ca43182017-08-31 06:57:16 -0700179
wangqi4d705e52017-09-28 12:23:35 -0700180 private com.android.dialer.logging.VideoTech.Type selectedAvailableVideoTechType =
181 com.android.dialer.logging.VideoTech.Type.NONE;
wangqi9982f0d2017-10-11 17:46:07 -0700182 private boolean isVoicemailNumber;
183 private List<PhoneAccountHandle> callCapableAccounts;
184 private String countryIso;
yueg457b3972017-09-18 15:11:47 -0700185
Android Dialer974fc292018-02-01 16:12:25 -0800186 private volatile boolean feedbackRequested = false;
187
twyen73a74c32018-03-07 12:12:24 -0800188 @Nullable private PreferredAccountRecorder preferredAccountRecorder;
189
Eric Erfanianccca3152017-02-22 16:32:36 -0800190 public static String getNumberFromHandle(Uri handle) {
191 return handle == null ? "" : handle.getSchemeSpecificPart();
192 }
193
194 /**
195 * Whether the call is put on hold by remote party. This is different than the {@link
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700196 * State#ONHOLD} state which indicates that the call is being held locally on the device.
Eric Erfanianccca3152017-02-22 16:32:36 -0800197 */
198 private boolean isRemotelyHeld;
199
Eric Erfanian2ca43182017-08-31 06:57:16 -0700200 /** Indicates whether this call is currently in the process of being merged into a conference. */
201 private boolean isMergeInProcess;
202
Eric Erfanianccca3152017-02-22 16:32:36 -0800203 /**
204 * Indicates whether the phone account associated with this call supports specifying a call
205 * subject.
206 */
linyuh183cb712017-12-27 17:02:37 -0800207 private boolean isCallSubjectSupported;
Eric Erfanianccca3152017-02-22 16:32:36 -0800208
linyuh183cb712017-12-27 17:02:37 -0800209 private final Call.Callback telecomCallCallback =
Eric Erfanianccca3152017-02-22 16:32:36 -0800210 new Call.Callback() {
211 @Override
212 public void onStateChanged(Call call, int newState) {
213 LogUtil.v("TelecomCallCallback.onStateChanged", "call=" + call + " newState=" + newState);
214 update();
215 }
216
217 @Override
218 public void onParentChanged(Call call, Call newParent) {
219 LogUtil.v(
220 "TelecomCallCallback.onParentChanged", "call=" + call + " newParent=" + newParent);
221 update();
222 }
223
224 @Override
225 public void onChildrenChanged(Call call, List<Call> children) {
226 update();
227 }
228
229 @Override
230 public void onDetailsChanged(Call call, Call.Details details) {
Eric Erfanian2ca43182017-08-31 06:57:16 -0700231 LogUtil.v(
232 "TelecomCallCallback.onDetailsChanged", " call=" + call + " details=" + details);
Eric Erfanianccca3152017-02-22 16:32:36 -0800233 update();
234 }
235
236 @Override
237 public void onCannedTextResponsesLoaded(Call call, List<String> cannedTextResponses) {
238 LogUtil.v(
Eric Erfanian2ca43182017-08-31 06:57:16 -0700239 "TelecomCallCallback.onCannedTextResponsesLoaded",
Eric Erfanianccca3152017-02-22 16:32:36 -0800240 "call=" + call + " cannedTextResponses=" + cannedTextResponses);
linyuh183cb712017-12-27 17:02:37 -0800241 for (CannedTextResponsesLoadedListener listener : cannedTextResponsesLoadedListeners) {
Eric Erfanianccca3152017-02-22 16:32:36 -0800242 listener.onCannedTextResponsesLoaded(DialerCall.this);
243 }
244 }
245
246 @Override
247 public void onPostDialWait(Call call, String remainingPostDialSequence) {
248 LogUtil.v(
Eric Erfanian2ca43182017-08-31 06:57:16 -0700249 "TelecomCallCallback.onPostDialWait",
Eric Erfanianccca3152017-02-22 16:32:36 -0800250 "call=" + call + " remainingPostDialSequence=" + remainingPostDialSequence);
251 update();
252 }
253
254 @Override
255 public void onVideoCallChanged(Call call, VideoCall videoCall) {
256 LogUtil.v(
Eric Erfanian2ca43182017-08-31 06:57:16 -0700257 "TelecomCallCallback.onVideoCallChanged", "call=" + call + " videoCall=" + videoCall);
Eric Erfanianccca3152017-02-22 16:32:36 -0800258 update();
259 }
260
261 @Override
262 public void onCallDestroyed(Call call) {
Eric Erfanian2ca43182017-08-31 06:57:16 -0700263 LogUtil.v("TelecomCallCallback.onCallDestroyed", "call=" + call);
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700264 unregisterCallback();
Eric Erfanianccca3152017-02-22 16:32:36 -0800265 }
266
267 @Override
268 public void onConferenceableCallsChanged(Call call, List<Call> conferenceableCalls) {
269 LogUtil.v(
Eric Erfanian2ca43182017-08-31 06:57:16 -0700270 "TelecomCallCallback.onConferenceableCallsChanged",
Eric Erfanianccca3152017-02-22 16:32:36 -0800271 "call %s, conferenceable calls: %d",
272 call,
273 conferenceableCalls.size());
274 update();
275 }
276
277 @Override
wangqi219b8702018-02-13 09:34:41 -0800278 public void onRttModeChanged(Call call, int mode) {
279 LogUtil.v("TelecomCallCallback.onRttModeChanged", "mode=%d", mode);
280 }
281
282 @Override
283 public void onRttRequest(Call call, int id) {
284 LogUtil.v("TelecomCallCallback.onRttRequest", "id=%d", id);
285 }
286
287 @Override
288 public void onRttInitiationFailure(Call call, int reason) {
289 LogUtil.v("TelecomCallCallback.onRttInitiationFailure", "reason=%d", reason);
290 update();
291 }
292
293 @Override
294 public void onRttStatusChanged(Call call, boolean enabled, RttCall rttCall) {
295 LogUtil.v("TelecomCallCallback.onRttStatusChanged", "enabled=%b", enabled);
296 update();
297 }
298
299 @Override
Eric Erfanianccca3152017-02-22 16:32:36 -0800300 public void onConnectionEvent(android.telecom.Call call, String event, Bundle extras) {
301 LogUtil.v(
Eric Erfanian2ca43182017-08-31 06:57:16 -0700302 "TelecomCallCallback.onConnectionEvent",
Eric Erfanianccca3152017-02-22 16:32:36 -0800303 "Call: " + call + ", Event: " + event + ", Extras: " + extras);
304 switch (event) {
305 // The Previous attempt to Merge two calls together has failed in Telecom. We must
306 // now update the UI to possibly re-enable the Merge button based on the number of
307 // currently conferenceable calls available or Connection Capabilities.
308 case android.telecom.Connection.EVENT_CALL_MERGE_FAILED:
309 update();
310 break;
311 case TelephonyManagerCompat.EVENT_HANDOVER_VIDEO_FROM_WIFI_TO_LTE:
312 notifyWiFiToLteHandover();
313 break;
roldenburg08424ee2018-03-28 17:02:46 -0700314 case TelephonyManagerCompat.EVENT_HANDOVER_VIDEO_FROM_LTE_TO_WIFI:
315 onLteToWifiHandover();
316 break;
Eric Erfanianccca3152017-02-22 16:32:36 -0800317 case TelephonyManagerCompat.EVENT_HANDOVER_TO_WIFI_FAILED:
318 notifyHandoverToWifiFailed();
319 break;
320 case TelephonyManagerCompat.EVENT_CALL_REMOTELY_HELD:
321 isRemotelyHeld = true;
322 update();
323 break;
324 case TelephonyManagerCompat.EVENT_CALL_REMOTELY_UNHELD:
325 isRemotelyHeld = false;
326 update();
327 break;
Eric Erfanianc857f902017-05-15 14:05:33 -0700328 case TelephonyManagerCompat.EVENT_NOTIFY_INTERNATIONAL_CALL_ON_WFC:
329 notifyInternationalCallOnWifi();
330 break;
Eric Erfanian2ca43182017-08-31 06:57:16 -0700331 case TelephonyManagerCompat.EVENT_MERGE_START:
332 LogUtil.i("DialerCall.onConnectionEvent", "merge start");
333 isMergeInProcess = true;
334 break;
335 case TelephonyManagerCompat.EVENT_MERGE_COMPLETE:
336 LogUtil.i("DialerCall.onConnectionEvent", "merge complete");
337 isMergeInProcess = false;
338 break;
wangqif4ba3452018-01-09 11:26:29 -0800339 case TelephonyManagerCompat.EVENT_CALL_FORWARDED:
340 // Only handle this event for P+ since it's unreliable pre-P.
341 if (BuildCompat.isAtLeastP()) {
342 isCallForwarded = true;
343 update();
344 }
345 break;
Eric Erfanianccca3152017-02-22 16:32:36 -0800346 default:
347 break;
348 }
349 }
350 };
Eric Erfanianc857f902017-05-15 14:05:33 -0700351
linyuh183cb712017-12-27 17:02:37 -0800352 private long timeAddedMs;
Eric Erfanianccca3152017-02-22 16:32:36 -0800353
354 public DialerCall(
355 Context context,
356 DialerCallDelegate dialerCallDelegate,
357 Call telecomCall,
358 LatencyReport latencyReport,
359 boolean registerCallback) {
360 Assert.isNotNull(context);
linyuh183cb712017-12-27 17:02:37 -0800361 this.context = context;
362 this.dialerCallDelegate = dialerCallDelegate;
363 this.telecomCall = telecomCall;
364 this.latencyReport = latencyReport;
365 id = ID_PREFIX + Integer.toString(idCounter++);
Eric Erfanianccca3152017-02-22 16:32:36 -0800366
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700367 // Must be after assigning mTelecomCall
linyuh183cb712017-12-27 17:02:37 -0800368 videoTechManager = new VideoTechManager(this);
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700369
370 updateFromTelecomCall();
Eric Erfanianc857f902017-05-15 14:05:33 -0700371 if (isHiddenNumber() && TextUtils.isEmpty(getNumber())) {
linyuh183cb712017-12-27 17:02:37 -0800372 hiddenId = ++hiddenCounter;
Eric Erfanianc857f902017-05-15 14:05:33 -0700373 } else {
linyuh183cb712017-12-27 17:02:37 -0800374 hiddenId = 0;
Eric Erfanianc857f902017-05-15 14:05:33 -0700375 }
Eric Erfanianccca3152017-02-22 16:32:36 -0800376
377 if (registerCallback) {
linyuh183cb712017-12-27 17:02:37 -0800378 this.telecomCall.registerCallback(telecomCallCallback);
Eric Erfanianccca3152017-02-22 16:32:36 -0800379 }
380
linyuh183cb712017-12-27 17:02:37 -0800381 timeAddedMs = System.currentTimeMillis();
Eric Erfanianccca3152017-02-22 16:32:36 -0800382 parseCallSpecificAppData();
Eric Erfanian2ca43182017-08-31 06:57:16 -0700383
384 updateEnrichedCallSession();
Eric Erfanianccca3152017-02-22 16:32:36 -0800385 }
386
twyendde01c52017-09-22 10:07:31 -0700387 /** Test only constructor to avoid initializing dependencies. */
388 @VisibleForTesting
389 DialerCall(Context context) {
linyuh183cb712017-12-27 17:02:37 -0800390 this.context = context;
391 telecomCall = null;
392 latencyReport = null;
393 id = null;
394 hiddenId = 0;
395 dialerCallDelegate = null;
396 videoTechManager = null;
twyendde01c52017-09-22 10:07:31 -0700397 }
398
Eric Erfanianccca3152017-02-22 16:32:36 -0800399 private static int translateState(int state) {
400 switch (state) {
401 case Call.STATE_NEW:
402 case Call.STATE_CONNECTING:
403 return DialerCall.State.CONNECTING;
404 case Call.STATE_SELECT_PHONE_ACCOUNT:
405 return DialerCall.State.SELECT_PHONE_ACCOUNT;
406 case Call.STATE_DIALING:
407 return DialerCall.State.DIALING;
408 case Call.STATE_PULLING_CALL:
409 return DialerCall.State.PULLING;
410 case Call.STATE_RINGING:
411 return DialerCall.State.INCOMING;
412 case Call.STATE_ACTIVE:
413 return DialerCall.State.ACTIVE;
414 case Call.STATE_HOLDING:
415 return DialerCall.State.ONHOLD;
416 case Call.STATE_DISCONNECTED:
417 return DialerCall.State.DISCONNECTED;
418 case Call.STATE_DISCONNECTING:
419 return DialerCall.State.DISCONNECTING;
420 default:
421 return DialerCall.State.INVALID;
422 }
423 }
424
425 public static boolean areSame(DialerCall call1, DialerCall call2) {
426 if (call1 == null && call2 == null) {
427 return true;
428 } else if (call1 == null || call2 == null) {
429 return false;
430 }
431
432 // otherwise compare call Ids
433 return call1.getId().equals(call2.getId());
434 }
435
Eric Erfanianccca3152017-02-22 16:32:36 -0800436 public void addListener(DialerCallListener listener) {
437 Assert.isMainThread();
linyuh183cb712017-12-27 17:02:37 -0800438 listeners.add(listener);
Eric Erfanianccca3152017-02-22 16:32:36 -0800439 }
440
441 public void removeListener(DialerCallListener listener) {
442 Assert.isMainThread();
linyuh183cb712017-12-27 17:02:37 -0800443 listeners.remove(listener);
Eric Erfanianccca3152017-02-22 16:32:36 -0800444 }
445
446 public void addCannedTextResponsesLoadedListener(CannedTextResponsesLoadedListener listener) {
447 Assert.isMainThread();
linyuh183cb712017-12-27 17:02:37 -0800448 cannedTextResponsesLoadedListeners.add(listener);
Eric Erfanianccca3152017-02-22 16:32:36 -0800449 }
450
451 public void removeCannedTextResponsesLoadedListener(CannedTextResponsesLoadedListener listener) {
452 Assert.isMainThread();
linyuh183cb712017-12-27 17:02:37 -0800453 cannedTextResponsesLoadedListeners.remove(listener);
Eric Erfanianccca3152017-02-22 16:32:36 -0800454 }
455
roldenburg08424ee2018-03-28 17:02:46 -0700456 private void onLteToWifiHandover() {
457 LogUtil.enterBlock("DialerCall.onLteToWifiHandover");
458 if (hasShownLteToWiFiHandoverToast) {
459 return;
460 }
461
462 Toast.makeText(context, R.string.video_call_lte_to_wifi_handover_toast, Toast.LENGTH_LONG)
463 .show();
464 hasShownLteToWiFiHandoverToast = true;
465 }
466
Eric Erfanianccca3152017-02-22 16:32:36 -0800467 public void notifyWiFiToLteHandover() {
468 LogUtil.i("DialerCall.notifyWiFiToLteHandover", "");
linyuh183cb712017-12-27 17:02:37 -0800469 for (DialerCallListener listener : listeners) {
Eric Erfanianccca3152017-02-22 16:32:36 -0800470 listener.onWiFiToLteHandover();
471 }
472 }
473
474 public void notifyHandoverToWifiFailed() {
475 LogUtil.i("DialerCall.notifyHandoverToWifiFailed", "");
linyuh183cb712017-12-27 17:02:37 -0800476 for (DialerCallListener listener : listeners) {
Eric Erfanianccca3152017-02-22 16:32:36 -0800477 listener.onHandoverToWifiFailure();
478 }
479 }
480
Eric Erfanianc857f902017-05-15 14:05:33 -0700481 public void notifyInternationalCallOnWifi() {
482 LogUtil.enterBlock("DialerCall.notifyInternationalCallOnWifi");
linyuh183cb712017-12-27 17:02:37 -0800483 for (DialerCallListener dialerCallListener : listeners) {
Eric Erfanianc857f902017-05-15 14:05:33 -0700484 dialerCallListener.onInternationalCallOnWifi();
485 }
486 }
487
Eric Erfanianccca3152017-02-22 16:32:36 -0800488 /* package-private */ Call getTelecomCall() {
linyuh183cb712017-12-27 17:02:37 -0800489 return telecomCall;
Eric Erfanianccca3152017-02-22 16:32:36 -0800490 }
wangqida410d32018-03-06 16:51:38 -0800491
Eric Erfanianccca3152017-02-22 16:32:36 -0800492 public StatusHints getStatusHints() {
linyuh183cb712017-12-27 17:02:37 -0800493 return telecomCall.getDetails().getStatusHints();
Eric Erfanianccca3152017-02-22 16:32:36 -0800494 }
495
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700496 public int getCameraDir() {
linyuh183cb712017-12-27 17:02:37 -0800497 return cameraDirection;
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700498 }
499
500 public void setCameraDir(int cameraDir) {
501 if (cameraDir == CameraDirection.CAMERA_DIRECTION_FRONT_FACING
502 || cameraDir == CameraDirection.CAMERA_DIRECTION_BACK_FACING) {
linyuh183cb712017-12-27 17:02:37 -0800503 cameraDirection = cameraDir;
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700504 } else {
linyuh183cb712017-12-27 17:02:37 -0800505 cameraDirection = CameraDirection.CAMERA_DIRECTION_UNKNOWN;
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700506 }
Eric Erfanianccca3152017-02-22 16:32:36 -0800507 }
508
Eric Erfanian2ca43182017-08-31 06:57:16 -0700509 public boolean wasParentCall() {
linyuh183cb712017-12-27 17:02:37 -0800510 return logState.conferencedCalls != 0;
Eric Erfanian2ca43182017-08-31 06:57:16 -0700511 }
512
wangqi9982f0d2017-10-11 17:46:07 -0700513 public boolean isVoiceMailNumber() {
514 return isVoicemailNumber;
515 }
516
517 public List<PhoneAccountHandle> getCallCapableAccounts() {
518 return callCapableAccounts;
519 }
520
521 public String getCountryIso() {
522 return countryIso;
523 }
524
525 private void updateIsVoiceMailNumber() {
526 if (getHandle() != null && PhoneAccount.SCHEME_VOICEMAIL.equals(getHandle().getScheme())) {
527 isVoicemailNumber = true;
roldenburg37a969d2018-02-22 14:46:44 -0800528 return;
wangqi9982f0d2017-10-11 17:46:07 -0700529 }
530
linyuh183cb712017-12-27 17:02:37 -0800531 if (!PermissionsUtil.hasPermission(context, permission.READ_PHONE_STATE)) {
wangqi9982f0d2017-10-11 17:46:07 -0700532 isVoicemailNumber = false;
roldenburg37a969d2018-02-22 14:46:44 -0800533 return;
wangqi9982f0d2017-10-11 17:46:07 -0700534 }
535
linyuh183cb712017-12-27 17:02:37 -0800536 isVoicemailNumber = TelecomUtil.isVoicemailNumber(context, getAccountHandle(), getNumber());
wangqi9982f0d2017-10-11 17:46:07 -0700537 }
538
Eric Erfanianccca3152017-02-22 16:32:36 -0800539 private void update() {
Eric Erfanian2ca43182017-08-31 06:57:16 -0700540 Trace.beginSection("DialerCall.update");
Eric Erfanianccca3152017-02-22 16:32:36 -0800541 int oldState = getState();
roldenburg7bb96232017-10-09 10:32:05 -0700542 // Clear any cache here that could potentially change on update.
543 videoTech = null;
Eric Erfanianccca3152017-02-22 16:32:36 -0800544 // We want to potentially register a video call callback here.
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700545 updateFromTelecomCall();
Eric Erfanianccca3152017-02-22 16:32:36 -0800546 if (oldState != getState() && getState() == DialerCall.State.DISCONNECTED) {
linyuh183cb712017-12-27 17:02:37 -0800547 for (DialerCallListener listener : listeners) {
Eric Erfanianccca3152017-02-22 16:32:36 -0800548 listener.onDialerCallDisconnect();
549 }
linyuh183cb712017-12-27 17:02:37 -0800550 EnrichedCallComponent.get(context)
Eric Erfanian2ca43182017-08-31 06:57:16 -0700551 .getEnrichedCallManager()
552 .unregisterCapabilitiesListener(this);
linyuh183cb712017-12-27 17:02:37 -0800553 EnrichedCallComponent.get(context)
Eric Erfanian2ca43182017-08-31 06:57:16 -0700554 .getEnrichedCallManager()
555 .unregisterStateChangedListener(this);
Eric Erfanianccca3152017-02-22 16:32:36 -0800556 } else {
linyuh183cb712017-12-27 17:02:37 -0800557 for (DialerCallListener listener : listeners) {
Eric Erfanianccca3152017-02-22 16:32:36 -0800558 listener.onDialerCallUpdate();
559 }
560 }
561 Trace.endSection();
562 }
563
wangqi9982f0d2017-10-11 17:46:07 -0700564 @SuppressWarnings("MissingPermission")
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700565 private void updateFromTelecomCall() {
Eric Erfanian2ca43182017-08-31 06:57:16 -0700566 Trace.beginSection("DialerCall.updateFromTelecomCall");
linyuh183cb712017-12-27 17:02:37 -0800567 LogUtil.v("DialerCall.updateFromTelecomCall", telecomCall.toString());
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700568
roldenburg6bd612f2018-01-18 12:57:19 -0800569 videoTechManager.dispatchCallStateChanged(telecomCall.getState(), getAccountHandle());
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700570
linyuh183cb712017-12-27 17:02:37 -0800571 final int translatedState = translateState(telecomCall.getState());
572 if (state != State.BLOCKED) {
Eric Erfanianccca3152017-02-22 16:32:36 -0800573 setState(translatedState);
linyuh183cb712017-12-27 17:02:37 -0800574 setDisconnectCause(telecomCall.getDetails().getDisconnectCause());
Eric Erfanianccca3152017-02-22 16:32:36 -0800575 }
576
linyuh183cb712017-12-27 17:02:37 -0800577 childCallIds.clear();
578 final int numChildCalls = telecomCall.getChildren().size();
Eric Erfanianccca3152017-02-22 16:32:36 -0800579 for (int i = 0; i < numChildCalls; i++) {
linyuh183cb712017-12-27 17:02:37 -0800580 childCallIds.add(
581 dialerCallDelegate
582 .getDialerCallFromTelecomCall(telecomCall.getChildren().get(i))
Eric Erfanianccca3152017-02-22 16:32:36 -0800583 .getId());
584 }
585
586 // The number of conferenced calls can change over the course of the call, so use the
587 // maximum number of conferenced child calls as the metric for conference call usage.
linyuh183cb712017-12-27 17:02:37 -0800588 logState.conferencedCalls = Math.max(numChildCalls, logState.conferencedCalls);
Eric Erfanianccca3152017-02-22 16:32:36 -0800589
linyuh183cb712017-12-27 17:02:37 -0800590 updateFromCallExtras(telecomCall.getDetails().getExtras());
Eric Erfanianccca3152017-02-22 16:32:36 -0800591
592 // If the handle of the call has changed, update state for the call determining if it is an
593 // emergency call.
linyuh183cb712017-12-27 17:02:37 -0800594 Uri newHandle = telecomCall.getDetails().getHandle();
595 if (!Objects.equals(handle, newHandle)) {
596 handle = newHandle;
Eric Erfanianccca3152017-02-22 16:32:36 -0800597 updateEmergencyCallState();
598 }
599
linyuh183cb712017-12-27 17:02:37 -0800600 TelecomManager telecomManager = context.getSystemService(TelecomManager.class);
Eric Erfanianccca3152017-02-22 16:32:36 -0800601 // If the phone account handle of the call is set, cache capability bit indicating whether
602 // the phone account supports call subjects.
linyuh183cb712017-12-27 17:02:37 -0800603 PhoneAccountHandle newPhoneAccountHandle = telecomCall.getDetails().getAccountHandle();
604 if (!Objects.equals(phoneAccountHandle, newPhoneAccountHandle)) {
605 phoneAccountHandle = newPhoneAccountHandle;
Eric Erfanianccca3152017-02-22 16:32:36 -0800606
linyuh183cb712017-12-27 17:02:37 -0800607 if (phoneAccountHandle != null) {
608 PhoneAccount phoneAccount = telecomManager.getPhoneAccount(phoneAccountHandle);
Eric Erfanianccca3152017-02-22 16:32:36 -0800609 if (phoneAccount != null) {
linyuh183cb712017-12-27 17:02:37 -0800610 isCallSubjectSupported =
Eric Erfanianccca3152017-02-22 16:32:36 -0800611 phoneAccount.hasCapabilities(PhoneAccount.CAPABILITY_CALL_SUBJECT);
wangqida410d32018-03-06 16:51:38 -0800612 if (phoneAccount.hasCapabilities(PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION)) {
613 cacheCarrierConfiguration(phoneAccountHandle);
614 }
Eric Erfanianccca3152017-02-22 16:32:36 -0800615 }
616 }
617 }
linyuh183cb712017-12-27 17:02:37 -0800618 if (PermissionsUtil.hasPermission(context, permission.READ_PHONE_STATE)) {
wangqi9982f0d2017-10-11 17:46:07 -0700619 updateIsVoiceMailNumber();
620 callCapableAccounts = telecomManager.getCallCapablePhoneAccounts();
linyuh183cb712017-12-27 17:02:37 -0800621 countryIso = GeoUtil.getCurrentCountryIso(context);
wangqi9982f0d2017-10-11 17:46:07 -0700622 }
Eric Erfanian2ca43182017-08-31 06:57:16 -0700623 Trace.endSection();
Eric Erfanianccca3152017-02-22 16:32:36 -0800624 }
625
626 /**
wangqida410d32018-03-06 16:51:38 -0800627 * Caches frequently used carrier configuration locally.
628 *
629 * @param accountHandle The PhoneAccount handle.
630 */
631 @SuppressLint("MissingPermission")
632 private void cacheCarrierConfiguration(PhoneAccountHandle accountHandle) {
633 if (!PermissionsUtil.hasPermission(context, permission.READ_PHONE_STATE)) {
634 return;
635 }
636 if (VERSION.SDK_INT < VERSION_CODES.O) {
637 return;
638 }
639 // TODO(a bug): This may take several seconds to complete, revisit it to move it to worker
640 // thread.
641 carrierConfig =
642 TelephonyManagerCompat.getTelephonyManagerForPhoneAccountHandle(context, accountHandle)
643 .getCarrierConfig();
644 }
645
646 /**
Eric Erfanianccca3152017-02-22 16:32:36 -0800647 * Tests corruption of the {@code callExtras} bundle by calling {@link
648 * Bundle#containsKey(String)}. If the bundle is corrupted a {@link IllegalArgumentException} will
649 * be thrown and caught by this function.
650 *
651 * @param callExtras the bundle to verify
652 * @return {@code true} if the bundle is corrupted, {@code false} otherwise.
653 */
654 protected boolean areCallExtrasCorrupted(Bundle callExtras) {
655 /**
Eric Erfanian938468d2017-10-24 14:05:52 -0700656 * There's currently a bug in Telephony service (a bug) that could corrupt the extras
Eric Erfanianccca3152017-02-22 16:32:36 -0800657 * bundle, resulting in a IllegalArgumentException while validating data under {@link
658 * Bundle#containsKey(String)}.
659 */
660 try {
661 callExtras.containsKey(Connection.EXTRA_CHILD_ADDRESS);
662 return false;
663 } catch (IllegalArgumentException e) {
664 LogUtil.e(
665 "DialerCall.areCallExtrasCorrupted", "callExtras is corrupted, ignoring exception", e);
666 return true;
667 }
668 }
669
670 protected void updateFromCallExtras(Bundle callExtras) {
671 if (callExtras == null || areCallExtrasCorrupted(callExtras)) {
672 /**
673 * If the bundle is corrupted, abandon information update as a work around. These are not
674 * critical for the dialer to function.
675 */
676 return;
677 }
678 // Check for a change in the child address and notify any listeners.
679 if (callExtras.containsKey(Connection.EXTRA_CHILD_ADDRESS)) {
680 String childNumber = callExtras.getString(Connection.EXTRA_CHILD_ADDRESS);
linyuh183cb712017-12-27 17:02:37 -0800681 if (!Objects.equals(childNumber, this.childNumber)) {
682 this.childNumber = childNumber;
683 for (DialerCallListener listener : listeners) {
Eric Erfanianccca3152017-02-22 16:32:36 -0800684 listener.onDialerCallChildNumberChange();
685 }
686 }
687 }
688
689 // Last forwarded number comes in as an array of strings. We want to choose the
690 // last item in the array. The forwarding numbers arrive independently of when the
691 // call is originally set up, so we need to notify the the UI of the change.
692 if (callExtras.containsKey(Connection.EXTRA_LAST_FORWARDED_NUMBER)) {
693 ArrayList<String> lastForwardedNumbers =
694 callExtras.getStringArrayList(Connection.EXTRA_LAST_FORWARDED_NUMBER);
695
696 if (lastForwardedNumbers != null) {
697 String lastForwardedNumber = null;
698 if (!lastForwardedNumbers.isEmpty()) {
699 lastForwardedNumber = lastForwardedNumbers.get(lastForwardedNumbers.size() - 1);
700 }
701
linyuh183cb712017-12-27 17:02:37 -0800702 if (!Objects.equals(lastForwardedNumber, this.lastForwardedNumber)) {
703 this.lastForwardedNumber = lastForwardedNumber;
704 for (DialerCallListener listener : listeners) {
Eric Erfanianccca3152017-02-22 16:32:36 -0800705 listener.onDialerCallLastForwardedNumberChange();
706 }
707 }
708 }
709 }
710
711 // DialerCall subject is present in the extras at the start of call, so we do not need to
712 // notify any other listeners of this.
713 if (callExtras.containsKey(Connection.EXTRA_CALL_SUBJECT)) {
714 String callSubject = callExtras.getString(Connection.EXTRA_CALL_SUBJECT);
linyuh183cb712017-12-27 17:02:37 -0800715 if (!Objects.equals(this.callSubject, callSubject)) {
716 this.callSubject = callSubject;
Eric Erfanianccca3152017-02-22 16:32:36 -0800717 }
718 }
719 }
720
Eric Erfanianccca3152017-02-22 16:32:36 -0800721 public String getId() {
linyuh183cb712017-12-27 17:02:37 -0800722 return id;
Eric Erfanianccca3152017-02-22 16:32:36 -0800723 }
724
Eric Erfanianc857f902017-05-15 14:05:33 -0700725 /**
726 * @return name appended with a number if the number is restricted/unknown and the user has
727 * received more than one restricted/unknown call.
728 */
729 @Nullable
730 public String updateNameIfRestricted(@Nullable String name) {
linyuh183cb712017-12-27 17:02:37 -0800731 if (name != null && isHiddenNumber() && hiddenId != 0 && hiddenCounter > 1) {
732 return context.getString(R.string.unknown_counter, name, hiddenId);
Eric Erfanianc857f902017-05-15 14:05:33 -0700733 }
734 return name;
735 }
736
737 public static void clearRestrictedCount() {
linyuh183cb712017-12-27 17:02:37 -0800738 hiddenCounter = 0;
Eric Erfanianc857f902017-05-15 14:05:33 -0700739 }
740
741 private boolean isHiddenNumber() {
742 return getNumberPresentation() == TelecomManager.PRESENTATION_RESTRICTED
743 || getNumberPresentation() == TelecomManager.PRESENTATION_UNKNOWN;
744 }
745
Eric Erfanianccca3152017-02-22 16:32:36 -0800746 public boolean hasShownWiFiToLteHandoverToast() {
747 return hasShownWiFiToLteHandoverToast;
748 }
749
750 public void setHasShownWiFiToLteHandoverToast() {
751 hasShownWiFiToLteHandoverToast = true;
752 }
753
754 public boolean showWifiHandoverAlertAsToast() {
755 return doNotShowDialogForHandoffToWifiFailure;
756 }
757
758 public void setDoNotShowDialogForHandoffToWifiFailure(boolean bool) {
759 doNotShowDialogForHandoffToWifiFailure = bool;
760 }
761
wangqida410d32018-03-06 16:51:38 -0800762 public boolean showVideoChargesAlertDialog() {
763 if (carrierConfig == null) {
764 return false;
765 }
766 return carrierConfig.getBoolean(
767 TelephonyManagerCompat.CARRIER_CONFIG_KEY_SHOW_VIDEO_CALL_CHARGES_ALERT_DIALOG_BOOL);
768 }
769
Eric Erfanianccca3152017-02-22 16:32:36 -0800770 public long getTimeAddedMs() {
linyuh183cb712017-12-27 17:02:37 -0800771 return timeAddedMs;
Eric Erfanianccca3152017-02-22 16:32:36 -0800772 }
773
774 @Nullable
775 public String getNumber() {
linyuh183cb712017-12-27 17:02:37 -0800776 return TelecomCallUtil.getNumber(telecomCall);
Eric Erfanianccca3152017-02-22 16:32:36 -0800777 }
778
779 public void blockCall() {
linyuh183cb712017-12-27 17:02:37 -0800780 telecomCall.reject(false, null);
Eric Erfanianccca3152017-02-22 16:32:36 -0800781 setState(State.BLOCKED);
782 }
783
784 @Nullable
785 public Uri getHandle() {
linyuh183cb712017-12-27 17:02:37 -0800786 return telecomCall == null ? null : telecomCall.getDetails().getHandle();
Eric Erfanianccca3152017-02-22 16:32:36 -0800787 }
788
789 public boolean isEmergencyCall() {
linyuh183cb712017-12-27 17:02:37 -0800790 return isEmergencyCall;
Eric Erfanianccca3152017-02-22 16:32:36 -0800791 }
792
793 public boolean isPotentialEmergencyCallback() {
794 // The property PROPERTY_EMERGENCY_CALLBACK_MODE is only set for CDMA calls when the system
795 // is actually in emergency callback mode (ie data is disabled).
796 if (hasProperty(Details.PROPERTY_EMERGENCY_CALLBACK_MODE)) {
797 return true;
798 }
799 // We want to treat any incoming call that arrives a short time after an outgoing emergency call
800 // as a potential emergency callback.
801 if (getExtras() != null
802 && getExtras().getLong(TelecomManagerCompat.EXTRA_LAST_EMERGENCY_CALLBACK_TIME_MILLIS, 0)
803 > 0) {
804 long lastEmergencyCallMillis =
805 getExtras().getLong(TelecomManagerCompat.EXTRA_LAST_EMERGENCY_CALLBACK_TIME_MILLIS, 0);
806 if (isInEmergencyCallbackWindow(lastEmergencyCallMillis)) {
807 return true;
808 }
809 }
810 return false;
811 }
812
813 boolean isInEmergencyCallbackWindow(long timestampMillis) {
814 long emergencyCallbackWindowMillis =
linyuh183cb712017-12-27 17:02:37 -0800815 ConfigProviderBindings.get(context)
Eric Erfanianccca3152017-02-22 16:32:36 -0800816 .getLong(CONFIG_EMERGENCY_CALLBACK_WINDOW_MILLIS, TimeUnit.MINUTES.toMillis(5));
817 return System.currentTimeMillis() - timestampMillis < emergencyCallbackWindowMillis;
818 }
819
820 public int getState() {
linyuh183cb712017-12-27 17:02:37 -0800821 if (telecomCall != null && telecomCall.getParent() != null) {
Eric Erfanianccca3152017-02-22 16:32:36 -0800822 return State.CONFERENCED;
823 } else {
linyuh183cb712017-12-27 17:02:37 -0800824 return state;
Eric Erfanianccca3152017-02-22 16:32:36 -0800825 }
826 }
827
yueg265089a2017-10-06 14:35:15 -0700828 public int getNonConferenceState() {
linyuh183cb712017-12-27 17:02:37 -0800829 return state;
yueg265089a2017-10-06 14:35:15 -0700830 }
831
Eric Erfanianccca3152017-02-22 16:32:36 -0800832 public void setState(int state) {
Eric Erfanian2ca43182017-08-31 06:57:16 -0700833 if (state == State.INCOMING) {
linyuh183cb712017-12-27 17:02:37 -0800834 logState.isIncoming = true;
Eric Erfanian2ca43182017-08-31 06:57:16 -0700835 } else if (state == State.DISCONNECTED) {
836 long newDuration =
Eric Erfanianccca3152017-02-22 16:32:36 -0800837 getConnectTimeMillis() == 0 ? 0 : System.currentTimeMillis() - getConnectTimeMillis();
linyuh183cb712017-12-27 17:02:37 -0800838 if (this.state != state) {
839 logState.duration = newDuration;
Eric Erfanian2ca43182017-08-31 06:57:16 -0700840 } else {
841 LogUtil.i(
842 "DialerCall.setState",
843 "ignoring state transition from DISCONNECTED to DISCONNECTED."
844 + " Duration would have changed from %s to %s",
linyuh183cb712017-12-27 17:02:37 -0800845 logState.duration,
Eric Erfanian2ca43182017-08-31 06:57:16 -0700846 newDuration);
847 }
Eric Erfanianccca3152017-02-22 16:32:36 -0800848 }
linyuh183cb712017-12-27 17:02:37 -0800849 this.state = state;
Eric Erfanianccca3152017-02-22 16:32:36 -0800850 }
851
852 public int getNumberPresentation() {
linyuh183cb712017-12-27 17:02:37 -0800853 return telecomCall == null ? -1 : telecomCall.getDetails().getHandlePresentation();
Eric Erfanianccca3152017-02-22 16:32:36 -0800854 }
855
856 public int getCnapNamePresentation() {
linyuh183cb712017-12-27 17:02:37 -0800857 return telecomCall == null ? -1 : telecomCall.getDetails().getCallerDisplayNamePresentation();
Eric Erfanianccca3152017-02-22 16:32:36 -0800858 }
859
860 @Nullable
861 public String getCnapName() {
linyuh183cb712017-12-27 17:02:37 -0800862 return telecomCall == null ? null : getTelecomCall().getDetails().getCallerDisplayName();
Eric Erfanianccca3152017-02-22 16:32:36 -0800863 }
864
865 public Bundle getIntentExtras() {
linyuh183cb712017-12-27 17:02:37 -0800866 return telecomCall.getDetails().getIntentExtras();
Eric Erfanianccca3152017-02-22 16:32:36 -0800867 }
868
869 @Nullable
870 public Bundle getExtras() {
linyuh183cb712017-12-27 17:02:37 -0800871 return telecomCall == null ? null : telecomCall.getDetails().getExtras();
Eric Erfanianccca3152017-02-22 16:32:36 -0800872 }
873
874 /** @return The child number for the call, or {@code null} if none specified. */
875 public String getChildNumber() {
linyuh183cb712017-12-27 17:02:37 -0800876 return childNumber;
Eric Erfanianccca3152017-02-22 16:32:36 -0800877 }
878
879 /** @return The last forwarded number for the call, or {@code null} if none specified. */
880 public String getLastForwardedNumber() {
linyuh183cb712017-12-27 17:02:37 -0800881 return lastForwardedNumber;
Eric Erfanianccca3152017-02-22 16:32:36 -0800882 }
883
wangqif4ba3452018-01-09 11:26:29 -0800884 public boolean isCallForwarded() {
885 return isCallForwarded;
886 }
887
Eric Erfanianccca3152017-02-22 16:32:36 -0800888 /** @return The call subject, or {@code null} if none specified. */
889 public String getCallSubject() {
linyuh183cb712017-12-27 17:02:37 -0800890 return callSubject;
Eric Erfanianccca3152017-02-22 16:32:36 -0800891 }
892
893 /**
894 * @return {@code true} if the call's phone account supports call subjects, {@code false}
895 * otherwise.
896 */
897 public boolean isCallSubjectSupported() {
linyuh183cb712017-12-27 17:02:37 -0800898 return isCallSubjectSupported;
Eric Erfanianccca3152017-02-22 16:32:36 -0800899 }
900
901 /** Returns call disconnect cause, defined by {@link DisconnectCause}. */
902 public DisconnectCause getDisconnectCause() {
linyuh183cb712017-12-27 17:02:37 -0800903 if (state == State.DISCONNECTED || state == State.IDLE) {
904 return disconnectCause;
Eric Erfanianccca3152017-02-22 16:32:36 -0800905 }
906
907 return new DisconnectCause(DisconnectCause.UNKNOWN);
908 }
909
910 public void setDisconnectCause(DisconnectCause disconnectCause) {
linyuh183cb712017-12-27 17:02:37 -0800911 this.disconnectCause = disconnectCause;
912 logState.disconnectCause = this.disconnectCause;
Eric Erfanianccca3152017-02-22 16:32:36 -0800913 }
914
915 /** Returns the possible text message responses. */
916 public List<String> getCannedSmsResponses() {
linyuh183cb712017-12-27 17:02:37 -0800917 return telecomCall.getCannedTextResponses();
Eric Erfanianccca3152017-02-22 16:32:36 -0800918 }
919
920 /** Checks if the call supports the given set of capabilities supplied as a bit mask. */
921 public boolean can(int capabilities) {
linyuh183cb712017-12-27 17:02:37 -0800922 int supportedCapabilities = telecomCall.getDetails().getCallCapabilities();
Eric Erfanianccca3152017-02-22 16:32:36 -0800923
924 if ((capabilities & Call.Details.CAPABILITY_MERGE_CONFERENCE) != 0) {
925 // We allow you to merge if the capabilities allow it or if it is a call with
926 // conferenceable calls.
linyuh183cb712017-12-27 17:02:37 -0800927 if (telecomCall.getConferenceableCalls().isEmpty()
Eric Erfanianccca3152017-02-22 16:32:36 -0800928 && ((Call.Details.CAPABILITY_MERGE_CONFERENCE & supportedCapabilities) == 0)) {
929 // Cannot merge calls if there are no calls to merge with.
930 return false;
931 }
932 capabilities &= ~Call.Details.CAPABILITY_MERGE_CONFERENCE;
933 }
934 return (capabilities == (capabilities & supportedCapabilities));
935 }
936
937 public boolean hasProperty(int property) {
linyuh183cb712017-12-27 17:02:37 -0800938 return telecomCall.getDetails().hasProperty(property);
Eric Erfanianccca3152017-02-22 16:32:36 -0800939 }
940
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700941 @NonNull
Eric Erfanianccca3152017-02-22 16:32:36 -0800942 public String getUniqueCallId() {
943 return uniqueCallId;
944 }
945
946 /** Gets the time when the call first became active. */
947 public long getConnectTimeMillis() {
linyuh183cb712017-12-27 17:02:37 -0800948 return telecomCall.getDetails().getConnectTimeMillis();
Eric Erfanianccca3152017-02-22 16:32:36 -0800949 }
950
951 public boolean isConferenceCall() {
952 return hasProperty(Call.Details.PROPERTY_CONFERENCE);
953 }
954
955 @Nullable
956 public GatewayInfo getGatewayInfo() {
linyuh183cb712017-12-27 17:02:37 -0800957 return telecomCall == null ? null : telecomCall.getDetails().getGatewayInfo();
Eric Erfanianccca3152017-02-22 16:32:36 -0800958 }
959
960 @Nullable
961 public PhoneAccountHandle getAccountHandle() {
linyuh183cb712017-12-27 17:02:37 -0800962 return telecomCall == null ? null : telecomCall.getDetails().getAccountHandle();
Eric Erfanianccca3152017-02-22 16:32:36 -0800963 }
964
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700965 /** @return The {@link VideoCall} instance associated with the {@link Call}. */
Eric Erfanianccca3152017-02-22 16:32:36 -0800966 public VideoCall getVideoCall() {
linyuh183cb712017-12-27 17:02:37 -0800967 return telecomCall == null ? null : telecomCall.getVideoCall();
Eric Erfanianccca3152017-02-22 16:32:36 -0800968 }
969
970 public List<String> getChildCallIds() {
linyuh183cb712017-12-27 17:02:37 -0800971 return childCallIds;
Eric Erfanianccca3152017-02-22 16:32:36 -0800972 }
973
974 public String getParentId() {
linyuh183cb712017-12-27 17:02:37 -0800975 Call parentCall = telecomCall.getParent();
Eric Erfanianccca3152017-02-22 16:32:36 -0800976 if (parentCall != null) {
linyuh183cb712017-12-27 17:02:37 -0800977 return dialerCallDelegate.getDialerCallFromTelecomCall(parentCall).getId();
Eric Erfanianccca3152017-02-22 16:32:36 -0800978 }
979 return null;
980 }
981
982 public int getVideoState() {
linyuh183cb712017-12-27 17:02:37 -0800983 return telecomCall.getDetails().getVideoState();
Eric Erfanianccca3152017-02-22 16:32:36 -0800984 }
985
986 public boolean isVideoCall() {
roldenburg2cec3802017-10-11 16:26:51 -0700987 return getVideoTech().isTransmittingOrReceiving() || VideoProfile.isVideo(getVideoState());
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700988 }
989
wangqi8d407a02018-02-15 15:32:52 -0800990 @TargetApi(28)
wangqi219b8702018-02-13 09:34:41 -0800991 public boolean isRttCall() {
992 if (BuildCompat.isAtLeastP()) {
993 return getTelecomCall().isRttActive();
994 } else {
995 return false;
996 }
997 }
998
wangqi153af2f2018-02-15 16:21:49 -0800999 @TargetApi(28)
1000 public RttCall getRttCall() {
1001 if (!isRttCall()) {
1002 return null;
1003 }
1004 return getTelecomCall().getRttCall();
1005 }
1006
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001007 public boolean hasReceivedVideoUpgradeRequest() {
1008 return VideoUtils.hasReceivedVideoUpgradeRequest(getVideoTech().getSessionModificationState());
1009 }
1010
1011 public boolean hasSentVideoUpgradeRequest() {
1012 return VideoUtils.hasSentVideoUpgradeRequest(getVideoTech().getSessionModificationState());
Eric Erfanianccca3152017-02-22 16:32:36 -08001013 }
1014
wangqi219b8702018-02-13 09:34:41 -08001015 public boolean hasSentRttUpgradeRequest() {
wangqi219b8702018-02-13 09:34:41 -08001016 return false;
1017 }
1018
Eric Erfanianccca3152017-02-22 16:32:36 -08001019 /**
1020 * Determines if the call handle is an emergency number or not and caches the result to avoid
1021 * repeated calls to isEmergencyNumber.
1022 */
1023 private void updateEmergencyCallState() {
linyuh183cb712017-12-27 17:02:37 -08001024 isEmergencyCall = TelecomCallUtil.isEmergencyCall(telecomCall);
Eric Erfanianccca3152017-02-22 16:32:36 -08001025 }
1026
Eric Erfanianccca3152017-02-22 16:32:36 -08001027 public LogState getLogState() {
linyuh183cb712017-12-27 17:02:37 -08001028 return logState;
Eric Erfanianccca3152017-02-22 16:32:36 -08001029 }
1030
1031 /**
1032 * Determines if the call is an external call.
1033 *
1034 * <p>An external call is one which does not exist locally for the {@link
1035 * android.telecom.ConnectionService} it is associated with.
1036 *
Eric Erfanianccca3152017-02-22 16:32:36 -08001037 * @return {@code true} if the call is an external call, {@code false} otherwise.
1038 */
linyuh437ae952018-03-26 12:46:18 -07001039 boolean isExternalCall() {
1040 return hasProperty(CallCompat.Details.PROPERTY_IS_EXTERNAL_CALL);
Eric Erfanianccca3152017-02-22 16:32:36 -08001041 }
1042
1043 /**
Eric Erfanianccca3152017-02-22 16:32:36 -08001044 * Determines if answering this call will cause an ongoing video call to be dropped.
1045 *
1046 * @return {@code true} if answering this call will drop an ongoing video call, {@code false}
1047 * otherwise.
1048 */
1049 public boolean answeringDisconnectsForegroundVideoCall() {
1050 Bundle extras = getExtras();
1051 if (extras == null
1052 || !extras.containsKey(CallCompat.Details.EXTRA_ANSWERING_DROPS_FOREGROUND_CALL)) {
1053 return false;
1054 }
1055 return extras.getBoolean(CallCompat.Details.EXTRA_ANSWERING_DROPS_FOREGROUND_CALL);
1056 }
1057
1058 private void parseCallSpecificAppData() {
1059 if (isExternalCall()) {
1060 return;
1061 }
1062
linyuh183cb712017-12-27 17:02:37 -08001063 logState.callSpecificAppData = CallIntentParser.getCallSpecificAppData(getIntentExtras());
1064 if (logState.callSpecificAppData == null) {
Eric Erfanian8369df02017-05-03 10:27:13 -07001065
linyuh183cb712017-12-27 17:02:37 -08001066 logState.callSpecificAppData =
Eric Erfanian8369df02017-05-03 10:27:13 -07001067 CallSpecificAppData.newBuilder()
1068 .setCallInitiationType(CallInitiationType.Type.EXTERNAL_INITIATION)
1069 .build();
Eric Erfanianccca3152017-02-22 16:32:36 -08001070 }
1071 if (getState() == State.INCOMING) {
linyuh183cb712017-12-27 17:02:37 -08001072 logState.callSpecificAppData =
1073 logState
Eric Erfanian8369df02017-05-03 10:27:13 -07001074 .callSpecificAppData
1075 .toBuilder()
1076 .setCallInitiationType(CallInitiationType.Type.INCOMING_INITIATION)
1077 .build();
Eric Erfanianccca3152017-02-22 16:32:36 -08001078 }
1079 }
1080
1081 @Override
1082 public String toString() {
linyuh183cb712017-12-27 17:02:37 -08001083 if (telecomCall == null) {
Eric Erfanianccca3152017-02-22 16:32:36 -08001084 // This should happen only in testing since otherwise we would never have a null
1085 // Telecom call.
linyuh183cb712017-12-27 17:02:37 -08001086 return String.valueOf(id);
Eric Erfanianccca3152017-02-22 16:32:36 -08001087 }
1088
1089 return String.format(
1090 Locale.US,
1091 "[%s, %s, %s, %s, children:%s, parent:%s, "
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001092 + "conferenceable:%s, videoState:%s, mSessionModificationState:%d, CameraDir:%s]",
linyuh183cb712017-12-27 17:02:37 -08001093 id,
Eric Erfanianccca3152017-02-22 16:32:36 -08001094 State.toString(getState()),
linyuh183cb712017-12-27 17:02:37 -08001095 Details.capabilitiesToString(telecomCall.getDetails().getCallCapabilities()),
1096 Details.propertiesToString(telecomCall.getDetails().getCallProperties()),
1097 childCallIds,
Eric Erfanianccca3152017-02-22 16:32:36 -08001098 getParentId(),
linyuh183cb712017-12-27 17:02:37 -08001099 this.telecomCall.getConferenceableCalls(),
1100 VideoProfile.videoStateToString(telecomCall.getDetails().getVideoState()),
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001101 getVideoTech().getSessionModificationState(),
1102 getCameraDir());
Eric Erfanianccca3152017-02-22 16:32:36 -08001103 }
1104
1105 public String toSimpleString() {
1106 return super.toString();
1107 }
1108
1109 @CallHistoryStatus
1110 public int getCallHistoryStatus() {
linyuh183cb712017-12-27 17:02:37 -08001111 return callHistoryStatus;
Eric Erfanianccca3152017-02-22 16:32:36 -08001112 }
1113
1114 public void setCallHistoryStatus(@CallHistoryStatus int callHistoryStatus) {
linyuh183cb712017-12-27 17:02:37 -08001115 this.callHistoryStatus = callHistoryStatus;
Eric Erfanianccca3152017-02-22 16:32:36 -08001116 }
1117
1118 public boolean didShowCameraPermission() {
1119 return didShowCameraPermission;
1120 }
1121
1122 public void setDidShowCameraPermission(boolean didShow) {
1123 didShowCameraPermission = didShow;
1124 }
1125
wangqida410d32018-03-06 16:51:38 -08001126 public boolean didDismissVideoChargesAlertDialog() {
1127 return didDismissVideoChargesAlertDialog;
1128 }
1129
1130 public void setDidDismissVideoChargesAlertDialog(boolean didDismiss) {
1131 didDismissVideoChargesAlertDialog = didDismiss;
1132 }
1133
Eric Erfanian938468d2017-10-24 14:05:52 -07001134 @Nullable
1135 public Boolean isInGlobalSpamList() {
Eric Erfanianccca3152017-02-22 16:32:36 -08001136 return isInGlobalSpamList;
1137 }
1138
1139 public void setIsInGlobalSpamList(boolean inSpamList) {
1140 isInGlobalSpamList = inSpamList;
1141 }
1142
Eric Erfanian938468d2017-10-24 14:05:52 -07001143 @Nullable
1144 public Boolean isInUserSpamList() {
Eric Erfanianccca3152017-02-22 16:32:36 -08001145 return isInUserSpamList;
1146 }
1147
1148 public void setIsInUserSpamList(boolean inSpamList) {
1149 isInUserSpamList = inSpamList;
1150 }
1151
Eric Erfanian938468d2017-10-24 14:05:52 -07001152 @Nullable
1153 public Boolean isInUserWhiteList() {
Eric Erfanianccca3152017-02-22 16:32:36 -08001154 return isInUserWhiteList;
1155 }
1156
1157 public void setIsInUserWhiteList(boolean inWhiteList) {
1158 isInUserWhiteList = inWhiteList;
1159 }
1160
1161 public boolean isSpam() {
linyuh183cb712017-12-27 17:02:37 -08001162 return isSpam;
Eric Erfanianccca3152017-02-22 16:32:36 -08001163 }
1164
1165 public void setSpam(boolean isSpam) {
linyuh183cb712017-12-27 17:02:37 -08001166 this.isSpam = isSpam;
Eric Erfanianccca3152017-02-22 16:32:36 -08001167 }
1168
1169 public boolean isBlocked() {
linyuh183cb712017-12-27 17:02:37 -08001170 return isBlocked;
Eric Erfanianccca3152017-02-22 16:32:36 -08001171 }
1172
1173 public void setBlockedStatus(boolean isBlocked) {
linyuh183cb712017-12-27 17:02:37 -08001174 this.isBlocked = isBlocked;
Eric Erfanianccca3152017-02-22 16:32:36 -08001175 }
1176
1177 public boolean isRemotelyHeld() {
1178 return isRemotelyHeld;
1179 }
1180
Eric Erfanian2ca43182017-08-31 06:57:16 -07001181 public boolean isMergeInProcess() {
1182 return isMergeInProcess;
1183 }
1184
Eric Erfanianccca3152017-02-22 16:32:36 -08001185 public boolean isIncoming() {
linyuh183cb712017-12-27 17:02:37 -08001186 return logState.isIncoming;
Eric Erfanianccca3152017-02-22 16:32:36 -08001187 }
1188
erfanian2cf2c342017-12-21 12:01:33 -08001189 /**
1190 * Try and determine if the call used assisted dialing.
1191 *
1192 * <p>We will not be able to verify a call underwent assisted dialing until the Platform
1193 * implmentation is complete in P+.
1194 *
1195 * @return a boolean indicating assisted dialing may have been performed
1196 */
Eric Erfanian2ca43182017-08-31 06:57:16 -07001197 public boolean isAssistedDialed() {
1198 if (getIntentExtras() != null) {
erfaniand2e5d0b2018-03-02 14:54:35 -08001199 // P and below uses the existence of USE_ASSISTED_DIALING to indicate assisted dialing
erfanian2cf2c342017-12-21 12:01:33 -08001200 // was used. The Dialer client is responsible for performing assisted dialing before
1201 // placing the outgoing call.
1202 //
1203 // The existence of the assisted dialing extras indicates that assisted dialing took place.
1204 if (getIntentExtras().getBoolean(TelephonyManagerCompat.USE_ASSISTED_DIALING, false)
1205 && getAssistedDialingExtras() != null
1206 && Build.VERSION.SDK_INT <= ConcreteCreator.BUILD_CODE_CEILING) {
1207 return true;
1208 }
1209 }
1210
Eric Erfanian2ca43182017-08-31 06:57:16 -07001211 return false;
1212 }
1213
erfanian2cf2c342017-12-21 12:01:33 -08001214 @Nullable
erfaniand0f207f2017-10-11 12:23:29 -07001215 public TransformationInfo getAssistedDialingExtras() {
erfanian2cf2c342017-12-21 12:01:33 -08001216 if (getIntentExtras() == null) {
1217 return null;
erfaniand0f207f2017-10-11 12:23:29 -07001218 }
erfanian2cf2c342017-12-21 12:01:33 -08001219
1220 if (getIntentExtras().getBundle(TelephonyManagerCompat.ASSISTED_DIALING_EXTRAS) == null) {
1221 return null;
1222 }
1223
erfanianf2556612018-01-23 09:55:59 -08001224 // Used in N-OMR1
erfanian2cf2c342017-12-21 12:01:33 -08001225 return TransformationInfo.newInstanceFromBundle(
1226 getIntentExtras().getBundle(TelephonyManagerCompat.ASSISTED_DIALING_EXTRAS));
erfaniand0f207f2017-10-11 12:23:29 -07001227 }
1228
Eric Erfanianccca3152017-02-22 16:32:36 -08001229 public LatencyReport getLatencyReport() {
linyuh183cb712017-12-27 17:02:37 -08001230 return latencyReport;
Eric Erfanianccca3152017-02-22 16:32:36 -08001231 }
1232
Eric Erfanian2ca43182017-08-31 06:57:16 -07001233 public int getAnswerAndReleaseButtonDisplayedTimes() {
1234 return answerAndReleaseButtonDisplayedTimes;
1235 }
1236
1237 public void increaseAnswerAndReleaseButtonDisplayedTimes() {
1238 answerAndReleaseButtonDisplayedTimes++;
1239 }
1240
1241 public boolean getReleasedByAnsweringSecondCall() {
1242 return releasedByAnsweringSecondCall;
1243 }
1244
1245 public void setReleasedByAnsweringSecondCall(boolean releasedByAnsweringSecondCall) {
1246 this.releasedByAnsweringSecondCall = releasedByAnsweringSecondCall;
1247 }
1248
1249 public int getSecondCallWithoutAnswerAndReleasedButtonTimes() {
1250 return secondCallWithoutAnswerAndReleasedButtonTimes;
1251 }
1252
1253 public void increaseSecondCallWithoutAnswerAndReleasedButtonTimes() {
1254 secondCallWithoutAnswerAndReleasedButtonTimes++;
1255 }
1256
Eric Erfanian8369df02017-05-03 10:27:13 -07001257 @Nullable
1258 public EnrichedCallCapabilities getEnrichedCallCapabilities() {
linyuh183cb712017-12-27 17:02:37 -08001259 return enrichedCallCapabilities;
Eric Erfanian8369df02017-05-03 10:27:13 -07001260 }
1261
1262 public void setEnrichedCallCapabilities(
1263 @Nullable EnrichedCallCapabilities mEnrichedCallCapabilities) {
linyuh183cb712017-12-27 17:02:37 -08001264 this.enrichedCallCapabilities = mEnrichedCallCapabilities;
Eric Erfanian8369df02017-05-03 10:27:13 -07001265 }
1266
1267 @Nullable
1268 public Session getEnrichedCallSession() {
linyuh183cb712017-12-27 17:02:37 -08001269 return enrichedCallSession;
Eric Erfanian8369df02017-05-03 10:27:13 -07001270 }
1271
1272 public void setEnrichedCallSession(@Nullable Session mEnrichedCallSession) {
linyuh183cb712017-12-27 17:02:37 -08001273 this.enrichedCallSession = mEnrichedCallSession;
Eric Erfanian8369df02017-05-03 10:27:13 -07001274 }
1275
Eric Erfanianccca3152017-02-22 16:32:36 -08001276 public void unregisterCallback() {
linyuh183cb712017-12-27 17:02:37 -08001277 telecomCall.unregisterCallback(telecomCallCallback);
Eric Erfanianccca3152017-02-22 16:32:36 -08001278 }
1279
Eric Erfanianccca3152017-02-22 16:32:36 -08001280 public void phoneAccountSelected(PhoneAccountHandle accountHandle, boolean setDefault) {
1281 LogUtil.i(
1282 "DialerCall.phoneAccountSelected",
1283 "accountHandle: %s, setDefault: %b",
1284 accountHandle,
1285 setDefault);
linyuh183cb712017-12-27 17:02:37 -08001286 telecomCall.phoneAccountSelected(accountHandle, setDefault);
Eric Erfanianccca3152017-02-22 16:32:36 -08001287 }
1288
1289 public void disconnect() {
1290 LogUtil.i("DialerCall.disconnect", "");
1291 setState(DialerCall.State.DISCONNECTING);
linyuh183cb712017-12-27 17:02:37 -08001292 for (DialerCallListener listener : listeners) {
Eric Erfanianccca3152017-02-22 16:32:36 -08001293 listener.onDialerCallUpdate();
1294 }
linyuh183cb712017-12-27 17:02:37 -08001295 telecomCall.disconnect();
Eric Erfanianccca3152017-02-22 16:32:36 -08001296 }
1297
1298 public void hold() {
1299 LogUtil.i("DialerCall.hold", "");
linyuh183cb712017-12-27 17:02:37 -08001300 telecomCall.hold();
Eric Erfanianccca3152017-02-22 16:32:36 -08001301 }
1302
1303 public void unhold() {
1304 LogUtil.i("DialerCall.unhold", "");
linyuh183cb712017-12-27 17:02:37 -08001305 telecomCall.unhold();
Eric Erfanianccca3152017-02-22 16:32:36 -08001306 }
1307
1308 public void splitFromConference() {
1309 LogUtil.i("DialerCall.splitFromConference", "");
linyuh183cb712017-12-27 17:02:37 -08001310 telecomCall.splitFromConference();
Eric Erfanianccca3152017-02-22 16:32:36 -08001311 }
1312
1313 public void answer(int videoState) {
1314 LogUtil.i("DialerCall.answer", "videoState: " + videoState);
linyuh183cb712017-12-27 17:02:37 -08001315 telecomCall.answer(videoState);
Eric Erfanianccca3152017-02-22 16:32:36 -08001316 }
1317
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001318 public void answer() {
linyuh183cb712017-12-27 17:02:37 -08001319 answer(telecomCall.getDetails().getVideoState());
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001320 }
1321
Eric Erfanianccca3152017-02-22 16:32:36 -08001322 public void reject(boolean rejectWithMessage, String message) {
1323 LogUtil.i("DialerCall.reject", "");
linyuh183cb712017-12-27 17:02:37 -08001324 telecomCall.reject(rejectWithMessage, message);
Eric Erfanianccca3152017-02-22 16:32:36 -08001325 }
1326
1327 /** Return the string label to represent the call provider */
1328 public String getCallProviderLabel() {
1329 if (callProviderLabel == null) {
1330 PhoneAccount account = getPhoneAccount();
1331 if (account != null && !TextUtils.isEmpty(account.getLabel())) {
wangqi9982f0d2017-10-11 17:46:07 -07001332 if (callCapableAccounts != null && callCapableAccounts.size() > 1) {
Eric Erfanianccca3152017-02-22 16:32:36 -08001333 callProviderLabel = account.getLabel().toString();
1334 }
1335 }
1336 if (callProviderLabel == null) {
1337 callProviderLabel = "";
1338 }
1339 }
1340 return callProviderLabel;
1341 }
1342
1343 private PhoneAccount getPhoneAccount() {
1344 PhoneAccountHandle accountHandle = getAccountHandle();
1345 if (accountHandle == null) {
1346 return null;
1347 }
linyuh183cb712017-12-27 17:02:37 -08001348 return context.getSystemService(TelecomManager.class).getPhoneAccount(accountHandle);
Eric Erfanianccca3152017-02-22 16:32:36 -08001349 }
1350
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001351 public VideoTech getVideoTech() {
roldenburg7bb96232017-10-09 10:32:05 -07001352 if (videoTech == null) {
roldenburg6bd612f2018-01-18 12:57:19 -08001353 videoTech = videoTechManager.getVideoTech(getAccountHandle());
roldenburg7bb96232017-10-09 10:32:05 -07001354
1355 // Only store the first video tech type found to be available during the life of the call.
1356 if (selectedAvailableVideoTechType == com.android.dialer.logging.VideoTech.Type.NONE) {
1357 // Update the video tech.
1358 selectedAvailableVideoTechType = videoTech.getVideoTechType();
1359 }
1360 }
Eric Erfanian2ca43182017-08-31 06:57:16 -07001361 return videoTech;
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001362 }
1363
Eric Erfanianccca3152017-02-22 16:32:36 -08001364 public String getCallbackNumber() {
1365 if (callbackNumber == null) {
1366 // Show the emergency callback number if either:
1367 // 1. This is an emergency call.
1368 // 2. The phone is in Emergency Callback Mode, which means we should show the callback
1369 // number.
1370 boolean showCallbackNumber = hasProperty(Details.PROPERTY_EMERGENCY_CALLBACK_MODE);
1371
1372 if (isEmergencyCall() || showCallbackNumber) {
wangqi339b4f32017-09-18 14:32:09 -07001373 callbackNumber =
linyuh183cb712017-12-27 17:02:37 -08001374 context.getSystemService(TelecomManager.class).getLine1Number(getAccountHandle());
Eric Erfanianccca3152017-02-22 16:32:36 -08001375 }
1376
Eric Erfanianccca3152017-02-22 16:32:36 -08001377 if (callbackNumber == null) {
1378 callbackNumber = "";
1379 }
1380 }
1381 return callbackNumber;
1382 }
1383
wangqi97539352017-09-25 11:15:16 -07001384 public String getSimCountryIso() {
1385 String simCountryIso =
linyuh183cb712017-12-27 17:02:37 -08001386 TelephonyManagerCompat.getTelephonyManagerForPhoneAccountHandle(context, getAccountHandle())
wangqi97539352017-09-25 11:15:16 -07001387 .getSimCountryIso();
1388 if (!TextUtils.isEmpty(simCountryIso)) {
1389 simCountryIso = simCountryIso.toUpperCase(Locale.US);
1390 }
1391 return simCountryIso;
1392 }
1393
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001394 @Override
1395 public void onVideoTechStateChanged() {
1396 update();
1397 }
1398
1399 @Override
1400 public void onSessionModificationStateChanged() {
wangqi9982f0d2017-10-11 17:46:07 -07001401 Trace.beginSection("DialerCall.onSessionModificationStateChanged");
linyuh183cb712017-12-27 17:02:37 -08001402 for (DialerCallListener listener : listeners) {
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001403 listener.onDialerCallSessionModificationStateChange();
1404 }
wangqi9982f0d2017-10-11 17:46:07 -07001405 Trace.endSection();
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001406 }
1407
1408 @Override
1409 public void onCameraDimensionsChanged(int width, int height) {
1410 InCallVideoCallCallbackNotifier.getInstance().cameraDimensionsChanged(this, width, height);
1411 }
1412
1413 @Override
1414 public void onPeerDimensionsChanged(int width, int height) {
1415 InCallVideoCallCallbackNotifier.getInstance().peerDimensionsChanged(this, width, height);
1416 }
1417
1418 @Override
1419 public void onVideoUpgradeRequestReceived() {
1420 LogUtil.enterBlock("DialerCall.onVideoUpgradeRequestReceived");
1421
linyuh183cb712017-12-27 17:02:37 -08001422 for (DialerCallListener listener : listeners) {
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001423 listener.onDialerCallUpgradeToVideo();
1424 }
1425
1426 update();
Eric Erfanian8369df02017-05-03 10:27:13 -07001427
linyuh183cb712017-12-27 17:02:37 -08001428 Logger.get(context)
Eric Erfanian8369df02017-05-03 10:27:13 -07001429 .logCallImpression(
1430 DialerImpression.Type.VIDEO_CALL_REQUEST_RECEIVED, getUniqueCallId(), getTimeAddedMs());
1431 }
1432
1433 @Override
1434 public void onUpgradedToVideo(boolean switchToSpeaker) {
1435 LogUtil.enterBlock("DialerCall.onUpgradedToVideo");
1436
1437 if (!switchToSpeaker) {
1438 return;
1439 }
1440
1441 CallAudioState audioState = AudioModeProvider.getInstance().getAudioState();
1442
1443 if (0 != (CallAudioState.ROUTE_BLUETOOTH & audioState.getSupportedRouteMask())) {
1444 LogUtil.e(
1445 "DialerCall.onUpgradedToVideo",
1446 "toggling speakerphone not allowed when bluetooth supported.");
1447 return;
1448 }
1449
1450 if (audioState.getRoute() == CallAudioState.ROUTE_SPEAKER) {
1451 return;
1452 }
1453
1454 TelecomAdapter.getInstance().setAudioRoute(CallAudioState.ROUTE_SPEAKER);
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001455 }
1456
Eric Erfanian2ca43182017-08-31 06:57:16 -07001457 @Override
1458 public void onCapabilitiesUpdated() {
1459 if (getNumber() == null) {
1460 return;
1461 }
1462 EnrichedCallCapabilities capabilities =
linyuh183cb712017-12-27 17:02:37 -08001463 EnrichedCallComponent.get(context).getEnrichedCallManager().getCapabilities(getNumber());
Eric Erfanian2ca43182017-08-31 06:57:16 -07001464 if (capabilities != null) {
1465 setEnrichedCallCapabilities(capabilities);
1466 update();
1467 }
1468 }
1469
1470 @Override
1471 public void onEnrichedCallStateChanged() {
1472 updateEnrichedCallSession();
1473 }
1474
1475 @Override
1476 public void onImpressionLoggingNeeded(DialerImpression.Type impressionType) {
linyuh183cb712017-12-27 17:02:37 -08001477 Logger.get(context).logCallImpression(impressionType, getUniqueCallId(), getTimeAddedMs());
twyendde01c52017-09-22 10:07:31 -07001478 if (impressionType == DialerImpression.Type.LIGHTBRINGER_UPGRADE_REQUESTED) {
1479 if (getLogState().contactLookupResult == Type.NOT_FOUND) {
linyuh183cb712017-12-27 17:02:37 -08001480 Logger.get(context)
twyendde01c52017-09-22 10:07:31 -07001481 .logCallImpression(
1482 DialerImpression.Type.LIGHTBRINGER_NON_CONTACT_UPGRADE_REQUESTED,
1483 getUniqueCallId(),
1484 getTimeAddedMs());
1485 }
1486 }
Eric Erfanian2ca43182017-08-31 06:57:16 -07001487 }
1488
1489 private void updateEnrichedCallSession() {
1490 if (getNumber() == null) {
1491 return;
1492 }
1493 if (getEnrichedCallSession() != null) {
1494 // State changes to existing sessions are currently handled by the UI components (which have
1495 // their own listeners). Someday instead we could remove those and just call update() here and
1496 // have the usual onDialerCallUpdate update the UI.
1497 dispatchOnEnrichedCallSessionUpdate();
1498 return;
1499 }
1500
linyuh183cb712017-12-27 17:02:37 -08001501 EnrichedCallManager manager = EnrichedCallComponent.get(context).getEnrichedCallManager();
Eric Erfanian2ca43182017-08-31 06:57:16 -07001502
1503 Filter filter =
1504 isIncoming()
1505 ? manager.createIncomingCallComposerFilter()
1506 : manager.createOutgoingCallComposerFilter();
1507
1508 Session session = manager.getSession(getUniqueCallId(), getNumber(), filter);
1509 if (session == null) {
1510 return;
1511 }
1512
1513 session.setUniqueDialerCallId(getUniqueCallId());
1514 setEnrichedCallSession(session);
1515
1516 LogUtil.i(
1517 "DialerCall.updateEnrichedCallSession",
1518 "setting session %d's dialer id to %s",
1519 session.getSessionId(),
1520 getUniqueCallId());
1521
1522 dispatchOnEnrichedCallSessionUpdate();
1523 }
1524
1525 private void dispatchOnEnrichedCallSessionUpdate() {
linyuh183cb712017-12-27 17:02:37 -08001526 for (DialerCallListener listener : listeners) {
Eric Erfanian2ca43182017-08-31 06:57:16 -07001527 listener.onEnrichedCallSessionUpdate();
1528 }
1529 }
1530
1531 void onRemovedFromCallList() {
1532 // Ensure we clean up when this call is removed.
linyuh183cb712017-12-27 17:02:37 -08001533 videoTechManager.dispatchRemovedFromCallList();
Eric Erfanian2ca43182017-08-31 06:57:16 -07001534 }
1535
wangqi4d705e52017-09-28 12:23:35 -07001536 public com.android.dialer.logging.VideoTech.Type getSelectedAvailableVideoTechType() {
1537 return selectedAvailableVideoTechType;
yueg457b3972017-09-18 15:11:47 -07001538 }
1539
Android Dialer974fc292018-02-01 16:12:25 -08001540 public void markFeedbackRequested() {
1541 feedbackRequested = true;
1542 }
1543
1544 public boolean isFeedbackRequested() {
1545 return feedbackRequested;
1546 }
1547
Eric Erfanianccca3152017-02-22 16:32:36 -08001548 /**
twyen73a74c32018-03-07 12:12:24 -08001549 * If the in call UI has shown the phone account selection dialog for the call, the {@link
1550 * PreferredAccountRecorder} to record the result from the dialog.
1551 */
1552 @Nullable
1553 public PreferredAccountRecorder getPreferredAccountRecorder() {
1554 return preferredAccountRecorder;
1555 }
1556
1557 public void setPreferredAccountRecorder(PreferredAccountRecorder preferredAccountRecorder) {
1558 this.preferredAccountRecorder = preferredAccountRecorder;
1559 }
1560
erfaniand05d8992018-03-20 19:42:26 -07001561 /** Indicates the call is eligible for SpeakEasy */
1562 public boolean isSpeakEasyEligible() {
1563 // TODO(erfanian): refactor key location
1564 return ConfigProviderBindings.get(context).getBoolean("speak_easy_enabled", false);
1565 }
1566
1567 /** Indicates the user has selected SpeakEasy */
1568 public boolean isSpeakEasyCall() {
1569 if (!isSpeakEasyEligible()) {
1570 return false;
1571 }
1572 return isSpeakEasyCall;
1573 }
1574
1575 /** Sets the user preference for SpeakEasy */
1576 public void setIsSpeakEasyCall(boolean isSpeakEasyCall) {
1577 this.isSpeakEasyCall = isSpeakEasyCall;
1578 }
1579
twyen73a74c32018-03-07 12:12:24 -08001580 /**
Eric Erfanianccca3152017-02-22 16:32:36 -08001581 * Specifies whether a number is in the call history or not. {@link #CALL_HISTORY_STATUS_UNKNOWN}
1582 * means there is no result.
1583 */
1584 @IntDef({
1585 CALL_HISTORY_STATUS_UNKNOWN,
1586 CALL_HISTORY_STATUS_PRESENT,
1587 CALL_HISTORY_STATUS_NOT_PRESENT
1588 })
1589 @Retention(RetentionPolicy.SOURCE)
1590 public @interface CallHistoryStatus {}
1591
1592 /* Defines different states of this call */
1593 public static class State {
1594
1595 public static final int INVALID = 0;
1596 public static final int NEW = 1; /* The call is new. */
1597 public static final int IDLE = 2; /* The call is idle. Nothing active */
1598 public static final int ACTIVE = 3; /* There is an active call */
1599 public static final int INCOMING = 4; /* A normal incoming phone call */
1600 public static final int CALL_WAITING = 5; /* Incoming call while another is active */
1601 public static final int DIALING = 6; /* An outgoing call during dial phase */
1602 public static final int REDIALING = 7; /* Subsequent dialing attempt after a failure */
1603 public static final int ONHOLD = 8; /* An active phone call placed on hold */
1604 public static final int DISCONNECTING = 9; /* A call is being ended. */
1605 public static final int DISCONNECTED = 10; /* State after a call disconnects */
1606 public static final int CONFERENCED = 11; /* DialerCall part of a conference call */
1607 public static final int SELECT_PHONE_ACCOUNT = 12; /* Waiting for account selection */
1608 public static final int CONNECTING = 13; /* Waiting for Telecom broadcast to finish */
1609 public static final int BLOCKED = 14; /* The number was found on the block list */
1610 public static final int PULLING = 15; /* An external call being pulled to the device */
Eric Erfanian2ca43182017-08-31 06:57:16 -07001611 public static final int CALL_PENDING = 16; /* A call is pending on a long process to finish */
Eric Erfanianccca3152017-02-22 16:32:36 -08001612
1613 public static boolean isConnectingOrConnected(int state) {
1614 switch (state) {
1615 case ACTIVE:
1616 case INCOMING:
1617 case CALL_WAITING:
1618 case CONNECTING:
1619 case DIALING:
1620 case PULLING:
1621 case REDIALING:
1622 case ONHOLD:
1623 case CONFERENCED:
1624 return true;
1625 default:
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001626 return false;
Eric Erfanianccca3152017-02-22 16:32:36 -08001627 }
Eric Erfanianccca3152017-02-22 16:32:36 -08001628 }
1629
1630 public static boolean isDialing(int state) {
1631 return state == DIALING || state == PULLING || state == REDIALING;
1632 }
1633
1634 public static String toString(int state) {
1635 switch (state) {
1636 case INVALID:
1637 return "INVALID";
1638 case NEW:
1639 return "NEW";
1640 case IDLE:
1641 return "IDLE";
1642 case ACTIVE:
1643 return "ACTIVE";
1644 case INCOMING:
1645 return "INCOMING";
1646 case CALL_WAITING:
1647 return "CALL_WAITING";
1648 case DIALING:
1649 return "DIALING";
1650 case PULLING:
1651 return "PULLING";
1652 case REDIALING:
1653 return "REDIALING";
1654 case ONHOLD:
1655 return "ONHOLD";
1656 case DISCONNECTING:
1657 return "DISCONNECTING";
1658 case DISCONNECTED:
1659 return "DISCONNECTED";
1660 case CONFERENCED:
1661 return "CONFERENCED";
1662 case SELECT_PHONE_ACCOUNT:
1663 return "SELECT_PHONE_ACCOUNT";
1664 case CONNECTING:
1665 return "CONNECTING";
1666 case BLOCKED:
1667 return "BLOCKED";
1668 default:
1669 return "UNKNOWN";
1670 }
1671 }
1672 }
1673
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001674 /** Camera direction constants */
1675 public static class CameraDirection {
Eric Erfanianccca3152017-02-22 16:32:36 -08001676 public static final int CAMERA_DIRECTION_UNKNOWN = -1;
1677 public static final int CAMERA_DIRECTION_FRONT_FACING = CameraCharacteristics.LENS_FACING_FRONT;
1678 public static final int CAMERA_DIRECTION_BACK_FACING = CameraCharacteristics.LENS_FACING_BACK;
Eric Erfanianccca3152017-02-22 16:32:36 -08001679 }
1680
1681 /**
1682 * Tracks any state variables that is useful for logging. There is some amount of overlap with
1683 * existing call member variables, but this duplication helps to ensure that none of these logging
1684 * variables will interface with/and affect call logic.
1685 */
1686 public static class LogState {
1687
1688 public DisconnectCause disconnectCause;
1689 public boolean isIncoming = false;
Eric Erfanian8369df02017-05-03 10:27:13 -07001690 public ContactLookupResult.Type contactLookupResult =
1691 ContactLookupResult.Type.UNKNOWN_LOOKUP_RESULT_TYPE;
Eric Erfanianccca3152017-02-22 16:32:36 -08001692 public CallSpecificAppData callSpecificAppData;
1693 // If this was a conference call, the total number of calls involved in the conference.
1694 public int conferencedCalls = 0;
1695 public long duration = 0;
1696 public boolean isLogged = false;
1697
Eric Erfanian8369df02017-05-03 10:27:13 -07001698 private static String lookupToString(ContactLookupResult.Type lookupType) {
Eric Erfanianccca3152017-02-22 16:32:36 -08001699 switch (lookupType) {
Eric Erfanian8369df02017-05-03 10:27:13 -07001700 case LOCAL_CONTACT:
Eric Erfanianccca3152017-02-22 16:32:36 -08001701 return "Local";
Eric Erfanian8369df02017-05-03 10:27:13 -07001702 case LOCAL_CACHE:
Eric Erfanianccca3152017-02-22 16:32:36 -08001703 return "Cache";
Eric Erfanian8369df02017-05-03 10:27:13 -07001704 case REMOTE:
Eric Erfanianccca3152017-02-22 16:32:36 -08001705 return "Remote";
Eric Erfanian8369df02017-05-03 10:27:13 -07001706 case EMERGENCY:
Eric Erfanianccca3152017-02-22 16:32:36 -08001707 return "Emergency";
Eric Erfanian8369df02017-05-03 10:27:13 -07001708 case VOICEMAIL:
Eric Erfanianccca3152017-02-22 16:32:36 -08001709 return "Voicemail";
1710 default:
1711 return "Not found";
1712 }
1713 }
1714
1715 private static String initiationToString(CallSpecificAppData callSpecificAppData) {
1716 if (callSpecificAppData == null) {
1717 return "null";
1718 }
Eric Erfanian8369df02017-05-03 10:27:13 -07001719 switch (callSpecificAppData.getCallInitiationType()) {
1720 case INCOMING_INITIATION:
Eric Erfanianccca3152017-02-22 16:32:36 -08001721 return "Incoming";
Eric Erfanian8369df02017-05-03 10:27:13 -07001722 case DIALPAD:
Eric Erfanianccca3152017-02-22 16:32:36 -08001723 return "Dialpad";
Eric Erfanian8369df02017-05-03 10:27:13 -07001724 case SPEED_DIAL:
Eric Erfanianccca3152017-02-22 16:32:36 -08001725 return "Speed Dial";
Eric Erfanian8369df02017-05-03 10:27:13 -07001726 case REMOTE_DIRECTORY:
Eric Erfanianccca3152017-02-22 16:32:36 -08001727 return "Remote Directory";
Eric Erfanian8369df02017-05-03 10:27:13 -07001728 case SMART_DIAL:
Eric Erfanianccca3152017-02-22 16:32:36 -08001729 return "Smart Dial";
Eric Erfanian8369df02017-05-03 10:27:13 -07001730 case REGULAR_SEARCH:
Eric Erfanianccca3152017-02-22 16:32:36 -08001731 return "Regular Search";
Eric Erfanian8369df02017-05-03 10:27:13 -07001732 case CALL_LOG:
Eric Erfanianccca3152017-02-22 16:32:36 -08001733 return "DialerCall Log";
Eric Erfanian8369df02017-05-03 10:27:13 -07001734 case CALL_LOG_FILTER:
Eric Erfanianccca3152017-02-22 16:32:36 -08001735 return "DialerCall Log Filter";
Eric Erfanian8369df02017-05-03 10:27:13 -07001736 case VOICEMAIL_LOG:
Eric Erfanianccca3152017-02-22 16:32:36 -08001737 return "Voicemail Log";
Eric Erfanian8369df02017-05-03 10:27:13 -07001738 case CALL_DETAILS:
Eric Erfanianccca3152017-02-22 16:32:36 -08001739 return "DialerCall Details";
Eric Erfanian8369df02017-05-03 10:27:13 -07001740 case QUICK_CONTACTS:
Eric Erfanianccca3152017-02-22 16:32:36 -08001741 return "Quick Contacts";
Eric Erfanian8369df02017-05-03 10:27:13 -07001742 case EXTERNAL_INITIATION:
Eric Erfanianccca3152017-02-22 16:32:36 -08001743 return "External";
Eric Erfanian8369df02017-05-03 10:27:13 -07001744 case LAUNCHER_SHORTCUT:
Eric Erfanianccca3152017-02-22 16:32:36 -08001745 return "Launcher Shortcut";
1746 default:
Eric Erfanian8369df02017-05-03 10:27:13 -07001747 return "Unknown: " + callSpecificAppData.getCallInitiationType();
Eric Erfanianccca3152017-02-22 16:32:36 -08001748 }
1749 }
1750
1751 @Override
1752 public String toString() {
1753 return String.format(
1754 Locale.US,
1755 "["
1756 + "%s, " // DisconnectCause toString already describes the object type
1757 + "isIncoming: %s, "
1758 + "contactLookup: %s, "
1759 + "callInitiation: %s, "
1760 + "duration: %s"
1761 + "]",
1762 disconnectCause,
1763 isIncoming,
1764 lookupToString(contactLookupResult),
1765 initiationToString(callSpecificAppData),
1766 duration);
1767 }
1768 }
1769
roldenburgd7490db2018-01-09 13:51:29 -08001770 /** Coordinates the available VideoTech implementations for a call. */
1771 @VisibleForTesting
1772 public static class VideoTechManager {
Eric Erfaniand8046e52017-04-06 09:41:50 -07001773 private final Context context;
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001774 private final EmptyVideoTech emptyVideoTech = new EmptyVideoTech();
roldenburgd7490db2018-01-09 13:51:29 -08001775 private final VideoTech rcsVideoShare;
Eric Erfanian90508232017-03-24 09:31:16 -07001776 private final List<VideoTech> videoTechs;
roldenburg7bb96232017-10-09 10:32:05 -07001777 private VideoTech savedTech;
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001778
roldenburgd7490db2018-01-09 13:51:29 -08001779 @VisibleForTesting
1780 public VideoTechManager(DialerCall call) {
linyuh183cb712017-12-27 17:02:37 -08001781 this.context = call.context;
Eric Erfaniand8046e52017-04-06 09:41:50 -07001782
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001783 String phoneNumber = call.getNumber();
Eric Erfaniand8046e52017-04-06 09:41:50 -07001784 phoneNumber = phoneNumber != null ? phoneNumber : "";
Eric Erfanian2ca43182017-08-31 06:57:16 -07001785 phoneNumber = phoneNumber.replaceAll("[^+0-9]", "");
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001786
1787 // Insert order here determines the priority of that video tech option
Eric Erfanian8369df02017-05-03 10:27:13 -07001788 videoTechs = new ArrayList<>();
yueg457b3972017-09-18 15:11:47 -07001789
linyuh183cb712017-12-27 17:02:37 -08001790 videoTechs.add(new ImsVideoTech(Logger.get(call.context), call, call.telecomCall));
Eric Erfanian90508232017-03-24 09:31:16 -07001791
roldenburgd7490db2018-01-09 13:51:29 -08001792 rcsVideoShare =
linyuh183cb712017-12-27 17:02:37 -08001793 EnrichedCallComponent.get(call.context)
Eric Erfanian90508232017-03-24 09:31:16 -07001794 .getRcsVideoShareFactory()
1795 .newRcsVideoShare(
linyuh183cb712017-12-27 17:02:37 -08001796 EnrichedCallComponent.get(call.context).getEnrichedCallManager(),
Eric Erfanian90508232017-03-24 09:31:16 -07001797 call,
Eric Erfaniand8046e52017-04-06 09:41:50 -07001798 phoneNumber);
roldenburg3eca69f2018-01-16 12:07:04 -08001799 videoTechs.add(rcsVideoShare);
Eric Erfaniand8046e52017-04-06 09:41:50 -07001800
1801 videoTechs.add(
roldenburg4f026392017-10-13 18:42:20 -07001802 new DuoVideoTech(
linyuh183cb712017-12-27 17:02:37 -08001803 DuoComponent.get(call.context).getDuo(), call, call.telecomCall, phoneNumber));
roldenburgd7490db2018-01-09 13:51:29 -08001804
1805 savedTech = emptyVideoTech;
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001806 }
1807
roldenburgd7490db2018-01-09 13:51:29 -08001808 @VisibleForTesting
roldenburg6bd612f2018-01-18 12:57:19 -08001809 public VideoTech getVideoTech(PhoneAccountHandle phoneAccountHandle) {
roldenburgd7490db2018-01-09 13:51:29 -08001810 if (savedTech == emptyVideoTech) {
1811 for (VideoTech tech : videoTechs) {
roldenburg6bd612f2018-01-18 12:57:19 -08001812 if (tech.isAvailable(context, phoneAccountHandle)) {
roldenburgd7490db2018-01-09 13:51:29 -08001813 savedTech = tech;
1814 savedTech.becomePrimary();
1815 break;
1816 }
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001817 }
roldenburg6bd612f2018-01-18 12:57:19 -08001818 } else if (savedTech instanceof DuoVideoTech
1819 && rcsVideoShare.isAvailable(context, phoneAccountHandle)) {
roldenburgd7490db2018-01-09 13:51:29 -08001820 // RCS Video Share will become available after the capability exchange which is slower than
1821 // Duo reading local contacts for reachability. If Video Share becomes available and we are
1822 // not in the middle of any session changes, let it take over.
1823 savedTech = rcsVideoShare;
1824 rcsVideoShare.becomePrimary();
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001825 }
1826
roldenburgd7490db2018-01-09 13:51:29 -08001827 return savedTech;
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001828 }
1829
roldenburgd7490db2018-01-09 13:51:29 -08001830 @VisibleForTesting
roldenburg6bd612f2018-01-18 12:57:19 -08001831 public void dispatchCallStateChanged(int newState, PhoneAccountHandle phoneAccountHandle) {
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001832 for (VideoTech videoTech : videoTechs) {
roldenburg6bd612f2018-01-18 12:57:19 -08001833 videoTech.onCallStateChanged(context, newState, phoneAccountHandle);
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001834 }
1835 }
Eric Erfanian2ca43182017-08-31 06:57:16 -07001836
1837 void dispatchRemovedFromCallList() {
1838 for (VideoTech videoTech : videoTechs) {
1839 videoTech.onRemovedFromCallList();
1840 }
1841 }
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001842 }
1843
Eric Erfanianccca3152017-02-22 16:32:36 -08001844 /** Called when canned text responses have been loaded. */
1845 public interface CannedTextResponsesLoadedListener {
1846 void onCannedTextResponsesLoaded(DialerCall call);
1847 }
1848}