blob: 9db42d75fbfcf74b5af31849991e77af8655a70a [file] [log] [blame]
Eric Erfanianccca3152017-02-22 16:32:36 -08001/*
2 * Copyright (C) 2016 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;
18
linyuhc3968e62017-11-20 17:40:50 -080019import android.app.ActivityManager;
20import android.app.ActivityManager.AppTask;
linyuh57b093b2017-11-17 14:32:32 -080021import android.app.ActivityManager.TaskDescription;
linyuh7b86f562017-11-16 11:24:09 -080022import android.app.AlertDialog;
linyuhf99f6302017-11-15 11:23:51 -080023import android.app.Dialog;
linyuh57b093b2017-11-17 14:32:32 -080024import android.app.KeyguardManager;
Eric Erfanianccca3152017-02-22 16:32:36 -080025import android.content.Context;
26import android.content.Intent;
linyuhc3968e62017-11-20 17:40:50 -080027import android.content.res.Configuration;
Eric Erfanianccca3152017-02-22 16:32:36 -080028import android.os.Bundle;
Eric Erfanian2ca43182017-08-31 06:57:16 -070029import android.os.Trace;
linyuhc3968e62017-11-20 17:40:50 -080030import android.support.annotation.IntDef;
Eric Erfanianc857f902017-05-15 14:05:33 -070031import android.support.annotation.NonNull;
Eric Erfanianccca3152017-02-22 16:32:36 -080032import android.support.annotation.Nullable;
linyuhc3968e62017-11-20 17:40:50 -080033import android.support.annotation.VisibleForTesting;
wangqibc28ea72018-04-02 16:23:00 -070034import android.support.v4.app.DialogFragment;
erfaniand05d8992018-03-20 19:42:26 -070035import android.support.v4.app.Fragment;
Eric Erfanianccca3152017-02-22 16:32:36 -080036import android.support.v4.app.FragmentManager;
37import android.support.v4.app.FragmentTransaction;
linyuh57b093b2017-11-17 14:32:32 -080038import android.support.v4.content.res.ResourcesCompat;
twyen73a74c32018-03-07 12:12:24 -080039import android.telecom.Call;
linyuhc3968e62017-11-20 17:40:50 -080040import android.telecom.CallAudioState;
41import android.telecom.PhoneAccountHandle;
Eric Erfanian90508232017-03-24 09:31:16 -070042import android.telephony.TelephonyManager;
Eric Erfanianccca3152017-02-22 16:32:36 -080043import android.view.KeyEvent;
44import android.view.MenuItem;
45import android.view.MotionEvent;
46import android.view.View;
linyuh9c327da2017-11-14 12:33:48 -080047import android.view.WindowManager;
linyuhc3968e62017-11-20 17:40:50 -080048import android.view.animation.Animation;
49import android.view.animation.AnimationUtils;
linyuh7b86f562017-11-16 11:24:09 -080050import android.widget.CheckBox;
51import android.widget.Toast;
linyuhf99f6302017-11-15 11:23:51 -080052import com.android.contacts.common.widget.SelectPhoneAccountDialogFragment;
linyuhc3968e62017-11-20 17:40:50 -080053import com.android.dialer.animation.AnimUtils;
54import com.android.dialer.animation.AnimationListenerAdapter;
Eric Erfaniand5e47f62017-03-15 14:41:07 -070055import com.android.dialer.common.Assert;
Eric Erfanianccca3152017-02-22 16:32:36 -080056import com.android.dialer.common.LogUtil;
twyen73a74c32018-03-07 12:12:24 -080057import com.android.dialer.common.concurrent.DialerExecutorComponent;
weijiaxu650e7cc2017-10-31 12:38:54 -070058import com.android.dialer.common.concurrent.ThreadUtil;
twyena1723252018-04-24 17:02:57 -070059import com.android.dialer.common.concurrent.UiListener;
zachh190343a2018-05-31 17:30:46 -070060import com.android.dialer.configprovider.ConfigProviderComponent;
Eric Erfanianccca3152017-02-22 16:32:36 -080061import com.android.dialer.logging.Logger;
Eric Erfanian8369df02017-05-03 10:27:13 -070062import com.android.dialer.logging.ScreenEvent;
zachh7a96dc72018-02-20 22:16:03 -080063import com.android.dialer.metrics.Metrics;
64import com.android.dialer.metrics.MetricsComponent;
twyen73a74c32018-03-07 12:12:24 -080065import com.android.dialer.preferredsim.PreferredAccountRecorder;
66import com.android.dialer.preferredsim.PreferredAccountWorker;
twyena1723252018-04-24 17:02:57 -070067import com.android.dialer.preferredsim.PreferredAccountWorker.Result;
twyen56f79ba2018-04-30 14:25:46 -070068import com.android.dialer.preferredsim.PreferredSimComponent;
linyuhc3968e62017-11-20 17:40:50 -080069import com.android.dialer.util.ViewUtil;
Eric Erfanianccca3152017-02-22 16:32:36 -080070import com.android.incallui.answer.bindings.AnswerBindings;
71import com.android.incallui.answer.protocol.AnswerScreen;
72import com.android.incallui.answer.protocol.AnswerScreenDelegate;
73import com.android.incallui.answer.protocol.AnswerScreenDelegateFactory;
74import com.android.incallui.answerproximitysensor.PseudoScreenState;
linyuh57b093b2017-11-17 14:32:32 -080075import com.android.incallui.audiomode.AudioModeProvider;
Eric Erfanianccca3152017-02-22 16:32:36 -080076import com.android.incallui.call.CallList;
77import com.android.incallui.call.DialerCall;
linyuh57b093b2017-11-17 14:32:32 -080078import com.android.incallui.call.TelecomAdapter;
wangqibb94ca62018-04-27 14:34:04 -070079import com.android.incallui.call.state.DialerCallState;
Eric Erfanian2ca43182017-08-31 06:57:16 -070080import com.android.incallui.callpending.CallPendingActivity;
81import com.android.incallui.disconnectdialog.DisconnectMessage;
Eric Erfanianccca3152017-02-22 16:32:36 -080082import com.android.incallui.incall.bindings.InCallBindings;
83import com.android.incallui.incall.protocol.InCallButtonUiDelegate;
84import com.android.incallui.incall.protocol.InCallButtonUiDelegateFactory;
85import com.android.incallui.incall.protocol.InCallScreen;
86import com.android.incallui.incall.protocol.InCallScreenDelegate;
87import com.android.incallui.incall.protocol.InCallScreenDelegateFactory;
linyuh7b86f562017-11-16 11:24:09 -080088import com.android.incallui.incalluilock.InCallUiLock;
wangqi219b8702018-02-13 09:34:41 -080089import com.android.incallui.rtt.bindings.RttBindings;
90import com.android.incallui.rtt.protocol.RttCallScreen;
91import com.android.incallui.rtt.protocol.RttCallScreenDelegate;
92import com.android.incallui.rtt.protocol.RttCallScreenDelegateFactory;
erfaniand05d8992018-03-20 19:42:26 -070093import com.android.incallui.speakeasy.SpeakEasyCallManager;
linyuhf99f6302017-11-15 11:23:51 -080094import com.android.incallui.telecomeventui.InternationalCallOnWifiDialogFragment;
Eric Erfanianccca3152017-02-22 16:32:36 -080095import com.android.incallui.video.bindings.VideoBindings;
96import com.android.incallui.video.protocol.VideoCallScreen;
97import com.android.incallui.video.protocol.VideoCallScreenDelegate;
98import com.android.incallui.video.protocol.VideoCallScreenDelegateFactory;
linyuhc3968e62017-11-20 17:40:50 -080099import com.google.common.base.Optional;
twyena1723252018-04-24 17:02:57 -0700100import com.google.common.util.concurrent.ListenableFuture;
linyuhc3968e62017-11-20 17:40:50 -0800101import java.lang.annotation.Retention;
102import java.lang.annotation.RetentionPolicy;
103import java.util.ArrayList;
104import java.util.List;
Eric Erfanianccca3152017-02-22 16:32:36 -0800105
106/** Version of {@link InCallActivity} that shows the new UI */
107public class InCallActivity extends TransactionSafeFragmentActivity
108 implements AnswerScreenDelegateFactory,
109 InCallScreenDelegateFactory,
110 InCallButtonUiDelegateFactory,
111 VideoCallScreenDelegateFactory,
wangqi219b8702018-02-13 09:34:41 -0800112 RttCallScreenDelegateFactory,
Eric Erfanianccca3152017-02-22 16:32:36 -0800113 PseudoScreenState.StateChangedListener {
114
linyuhc3968e62017-11-20 17:40:50 -0800115 @Retention(RetentionPolicy.SOURCE)
116 @IntDef({
117 DIALPAD_REQUEST_NONE,
118 DIALPAD_REQUEST_SHOW,
119 DIALPAD_REQUEST_HIDE,
120 })
121 @interface DialpadRequestType {}
Eric Erfanian2ca43182017-08-31 06:57:16 -0700122
linyuhc3968e62017-11-20 17:40:50 -0800123 private static final int DIALPAD_REQUEST_NONE = 1;
124 private static final int DIALPAD_REQUEST_SHOW = 2;
125 private static final int DIALPAD_REQUEST_HIDE = 3;
linyuh57b093b2017-11-17 14:32:32 -0800126
linyuhc3968e62017-11-20 17:40:50 -0800127 private static Optional<Integer> audioRouteForTesting = Optional.absent();
linyuh57b093b2017-11-17 14:32:32 -0800128
twyen73a74c32018-03-07 12:12:24 -0800129 private SelectPhoneAccountListener selectPhoneAccountListener;
twyena1723252018-04-24 17:02:57 -0700130 private UiListener<Result> preferredAccountWorkerResultListener;
Eric Erfanianccca3152017-02-22 16:32:36 -0800131
linyuhc3968e62017-11-20 17:40:50 -0800132 private Animation dialpadSlideInAnimation;
133 private Animation dialpadSlideOutAnimation;
134 private Dialog errorDialog;
linyuh69a25062017-11-15 16:18:51 -0800135 private InCallOrientationEventListener inCallOrientationEventListener;
linyuhc3968e62017-11-20 17:40:50 -0800136 private View pseudoBlackScreenOverlay;
137 private SelectPhoneAccountDialogFragment selectPhoneAccountDialogFragment;
138 private String dtmfTextToPrepopulate;
linyuhc3968e62017-11-20 17:40:50 -0800139 private boolean allowOrientationChange;
140 private boolean animateDialpadOnShow;
Eric Erfanianccca3152017-02-22 16:32:36 -0800141 private boolean didShowAnswerScreen;
142 private boolean didShowInCallScreen;
143 private boolean didShowVideoCallScreen;
wangqi219b8702018-02-13 09:34:41 -0800144 private boolean didShowRttCallScreen;
erfaniand05d8992018-03-20 19:42:26 -0700145 private boolean didShowSpeakEasyScreen;
erfanian612d13a2018-04-04 15:27:57 -0700146 private String lastShownSpeakEasyScreenUniqueCallid = "";
linyuh9c327da2017-11-14 12:33:48 -0800147 private boolean dismissKeyguard;
Eric Erfanianccca3152017-02-22 16:32:36 -0800148 private boolean isInShowMainInCallFragment;
linyuhc3968e62017-11-20 17:40:50 -0800149 private boolean isRecreating; // whether the activity is going to be recreated
150 private boolean isVisible;
Eric Erfanianccca3152017-02-22 16:32:36 -0800151 private boolean needDismissPendingDialogs;
linyuhc3968e62017-11-20 17:40:50 -0800152 private boolean touchDownWhenPseudoScreenOff;
linyuhc3968e62017-11-20 17:40:50 -0800153 @DialpadRequestType private int showDialpadRequest = DIALPAD_REQUEST_NONE;
erfaniand05d8992018-03-20 19:42:26 -0700154 private SpeakEasyCallManager speakEasyCallManager;
wangqifb0cfff2018-06-05 11:51:01 -0700155 private DialogFragment rttRequestDialogFragment;
Eric Erfanianccca3152017-02-22 16:32:36 -0800156
157 public static Intent getIntent(
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700158 Context context, boolean showDialpad, boolean newOutgoingCall, boolean isForFullScreen) {
Eric Erfanianccca3152017-02-22 16:32:36 -0800159 Intent intent = new Intent(Intent.ACTION_MAIN, null);
160 intent.setFlags(Intent.FLAG_ACTIVITY_NO_USER_ACTION | Intent.FLAG_ACTIVITY_NEW_TASK);
161 intent.setClass(context, InCallActivity.class);
linyuhc3968e62017-11-20 17:40:50 -0800162 if (showDialpad) {
163 intent.putExtra(IntentExtraNames.SHOW_DIALPAD, true);
164 }
165 intent.putExtra(IntentExtraNames.NEW_OUTGOING_CALL, newOutgoingCall);
166 intent.putExtra(IntentExtraNames.FOR_FULL_SCREEN, isForFullScreen);
Eric Erfanianccca3152017-02-22 16:32:36 -0800167 return intent;
168 }
169
170 @Override
171 protected void onResumeFragments() {
172 super.onResumeFragments();
173 if (needDismissPendingDialogs) {
174 dismissPendingDialogs();
175 }
176 }
177
178 @Override
linyuhc3968e62017-11-20 17:40:50 -0800179 protected void onCreate(Bundle bundle) {
Eric Erfanian2ca43182017-08-31 06:57:16 -0700180 Trace.beginSection("InCallActivity.onCreate");
linyuhc3968e62017-11-20 17:40:50 -0800181 super.onCreate(bundle);
Eric Erfanianccca3152017-02-22 16:32:36 -0800182
twyena1723252018-04-24 17:02:57 -0700183 preferredAccountWorkerResultListener =
184 DialerExecutorComponent.get(this)
185 .createUiListener(getFragmentManager(), "preferredAccountWorkerResultListener");
186
twyen73a74c32018-03-07 12:12:24 -0800187 selectPhoneAccountListener = new SelectPhoneAccountListener(getApplicationContext());
188
linyuhc3968e62017-11-20 17:40:50 -0800189 if (bundle != null) {
190 didShowAnswerScreen = bundle.getBoolean(KeysForSavedInstance.DID_SHOW_ANSWER_SCREEN);
191 didShowInCallScreen = bundle.getBoolean(KeysForSavedInstance.DID_SHOW_IN_CALL_SCREEN);
192 didShowVideoCallScreen = bundle.getBoolean(KeysForSavedInstance.DID_SHOW_VIDEO_CALL_SCREEN);
wangqi153af2f2018-02-15 16:21:49 -0800193 didShowRttCallScreen = bundle.getBoolean(KeysForSavedInstance.DID_SHOW_RTT_CALL_SCREEN);
wangqic46cfd22018-05-22 15:10:05 -0700194 didShowSpeakEasyScreen = bundle.getBoolean(KeysForSavedInstance.DID_SHOW_SPEAK_EASY_SCREEN);
Eric Erfanianccca3152017-02-22 16:32:36 -0800195 }
196
linyuhc3968e62017-11-20 17:40:50 -0800197 setWindowFlags();
198 setContentView(R.layout.incall_screen);
199 internalResolveIntent(getIntent());
200
201 boolean isLandscape =
202 getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE;
203 boolean isRtl = ViewUtil.isRtl();
204 if (isLandscape) {
205 dialpadSlideInAnimation =
206 AnimationUtils.loadAnimation(
207 this, isRtl ? R.anim.dialpad_slide_in_left : R.anim.dialpad_slide_in_right);
208 dialpadSlideOutAnimation =
209 AnimationUtils.loadAnimation(
210 this, isRtl ? R.anim.dialpad_slide_out_left : R.anim.dialpad_slide_out_right);
211 } else {
212 dialpadSlideInAnimation = AnimationUtils.loadAnimation(this, R.anim.dialpad_slide_in_bottom);
213 dialpadSlideOutAnimation =
214 AnimationUtils.loadAnimation(this, R.anim.dialpad_slide_out_bottom);
215 }
216 dialpadSlideInAnimation.setInterpolator(AnimUtils.EASE_IN);
217 dialpadSlideOutAnimation.setInterpolator(AnimUtils.EASE_OUT);
218 dialpadSlideOutAnimation.setAnimationListener(
219 new AnimationListenerAdapter() {
220 @Override
221 public void onAnimationEnd(Animation animation) {
222 hideDialpadFragment();
223 }
224 });
225
226 if (bundle != null && showDialpadRequest == DIALPAD_REQUEST_NONE) {
227 // If the dialpad was shown before, set related variables so that it can be shown and
228 // populated with the previous DTMF text during onResume().
229 if (bundle.containsKey(IntentExtraNames.SHOW_DIALPAD)) {
230 boolean showDialpad = bundle.getBoolean(IntentExtraNames.SHOW_DIALPAD);
231 showDialpadRequest = showDialpad ? DIALPAD_REQUEST_SHOW : DIALPAD_REQUEST_HIDE;
232 animateDialpadOnShow = false;
233 }
234 dtmfTextToPrepopulate = bundle.getString(KeysForSavedInstance.DIALPAD_TEXT);
235
236 SelectPhoneAccountDialogFragment selectPhoneAccountDialogFragment =
237 (SelectPhoneAccountDialogFragment)
238 getFragmentManager().findFragmentByTag(Tags.SELECT_ACCOUNT_FRAGMENT);
239 if (selectPhoneAccountDialogFragment != null) {
240 selectPhoneAccountDialogFragment.setListener(selectPhoneAccountListener);
241 }
242 }
243
linyuh69a25062017-11-15 16:18:51 -0800244 inCallOrientationEventListener = new InCallOrientationEventListener(this);
Eric Erfanianccca3152017-02-22 16:32:36 -0800245
246 getWindow()
247 .getDecorView()
248 .setSystemUiVisibility(
249 View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
250
251 pseudoBlackScreenOverlay = findViewById(R.id.psuedo_black_screen_overlay);
Eric Erfanian2ca43182017-08-31 06:57:16 -0700252 sendBroadcast(CallPendingActivity.getFinishBroadcast());
253 Trace.endSection();
zachh7a96dc72018-02-20 22:16:03 -0800254 MetricsComponent.get(this)
255 .metrics()
256 .stopTimer(Metrics.ON_CALL_ADDED_TO_ON_INCALL_UI_SHOWN_INCOMING);
257 MetricsComponent.get(this)
258 .metrics()
259 .stopTimer(Metrics.ON_CALL_ADDED_TO_ON_INCALL_UI_SHOWN_OUTGOING);
Eric Erfanianccca3152017-02-22 16:32:36 -0800260 }
261
linyuhc3968e62017-11-20 17:40:50 -0800262 private void setWindowFlags() {
263 // Allow the activity to be shown when the screen is locked and filter out touch events that are
264 // "too fat".
265 int flags =
266 WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
267 | WindowManager.LayoutParams.FLAG_IGNORE_CHEEK_PRESSES;
268
linyuhf79d1cb2017-12-15 17:49:56 -0800269 // When the audio stream is not via Bluetooth, turn on the screen once the activity is shown.
270 // When the audio stream is via Bluetooth, turn on the screen only for an incoming call.
linyuhc3968e62017-11-20 17:40:50 -0800271 final int audioRoute = getAudioRoute();
linyuhf79d1cb2017-12-15 17:49:56 -0800272 if (audioRoute != CallAudioState.ROUTE_BLUETOOTH
273 || CallList.getInstance().getIncomingCall() != null) {
linyuhc3968e62017-11-20 17:40:50 -0800274 flags |= WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON;
275 }
276
277 getWindow().addFlags(flags);
278 }
279
280 private static int getAudioRoute() {
281 if (audioRouteForTesting.isPresent()) {
282 return audioRouteForTesting.get();
283 }
284
285 return AudioModeProvider.getInstance().getAudioState().getRoute();
286 }
287
288 @VisibleForTesting(otherwise = VisibleForTesting.NONE)
289 public static void setAudioRouteForTesting(int audioRoute) {
290 audioRouteForTesting = Optional.of(audioRoute);
291 }
292
293 private void internalResolveIntent(Intent intent) {
294 if (!intent.getAction().equals(Intent.ACTION_MAIN)) {
295 return;
296 }
297
298 if (intent.hasExtra(IntentExtraNames.SHOW_DIALPAD)) {
299 // IntentExtraNames.SHOW_DIALPAD can be used to specify whether the DTMF dialpad should be
300 // initially visible. If the extra is absent, leave the dialpad in its previous state.
301 boolean showDialpad = intent.getBooleanExtra(IntentExtraNames.SHOW_DIALPAD, false);
302 relaunchedFromDialer(showDialpad);
303 }
304
305 DialerCall outgoingCall = CallList.getInstance().getOutgoingCall();
306 if (outgoingCall == null) {
307 outgoingCall = CallList.getInstance().getPendingOutgoingCall();
308 }
309 if (intent.getBooleanExtra(IntentExtraNames.NEW_OUTGOING_CALL, false)) {
310 intent.removeExtra(IntentExtraNames.NEW_OUTGOING_CALL);
311
312 // InCallActivity is responsible for disconnecting a new outgoing call if there is no way of
313 // making it (i.e. no valid call capable accounts).
linyuh122fb0b2018-03-26 13:35:32 -0700314 if (InCallPresenter.isCallWithNoValidAccounts(outgoingCall)) {
linyuhc3968e62017-11-20 17:40:50 -0800315 LogUtil.i(
316 "InCallActivity.internalResolveIntent", "Call with no valid accounts, disconnecting");
317 outgoingCall.disconnect();
318 }
319
320 dismissKeyguard(true);
321 }
322
323 if (showPhoneAccountSelectionDialog()) {
324 hideMainInCallFragment();
325 }
326 }
327
328 /**
329 * When relaunching from the dialer app, {@code showDialpad} indicates whether the dialpad should
330 * be shown on launch.
331 *
332 * @param showDialpad {@code true} to indicate the dialpad should be shown on launch, and {@code
333 * false} to indicate no change should be made to the dialpad visibility.
334 */
335 private void relaunchedFromDialer(boolean showDialpad) {
336 showDialpadRequest = showDialpad ? DIALPAD_REQUEST_SHOW : DIALPAD_REQUEST_NONE;
337 animateDialpadOnShow = true;
338
339 if (showDialpadRequest == DIALPAD_REQUEST_SHOW) {
340 // If there's only one line in use, AND it's on hold, then we're sure the user
341 // wants to use the dialpad toward the exact line, so un-hold the holding line.
342 DialerCall call = CallList.getInstance().getActiveOrBackgroundCall();
wangqibb94ca62018-04-27 14:34:04 -0700343 if (call != null && call.getState() == DialerCallState.ONHOLD) {
linyuhc3968e62017-11-20 17:40:50 -0800344 call.unhold();
345 }
346 }
347 }
348
349 /**
350 * Show a phone account selection dialog if there is a call waiting for phone account selection.
351 *
352 * @return true if the dialog was shown.
353 */
354 private boolean showPhoneAccountSelectionDialog() {
355 DialerCall waitingForAccountCall = CallList.getInstance().getWaitingForAccountCall();
356 if (waitingForAccountCall == null) {
357 return false;
358 }
359
twyen56f79ba2018-04-30 14:25:46 -0700360 PreferredAccountWorker preferredAccountWorker =
361 PreferredSimComponent.get(this).preferredAccountWorker();
linyuhc3968e62017-11-20 17:40:50 -0800362
twyen56f79ba2018-04-30 14:25:46 -0700363 Bundle extras = waitingForAccountCall.getIntentExtras();
364 List<PhoneAccountHandle> phoneAccountHandles =
365 extras == null
366 ? new ArrayList<>()
367 : extras.getParcelableArrayList(Call.AVAILABLE_PHONE_ACCOUNTS);
368
369 ListenableFuture<PreferredAccountWorker.Result> preferredAccountFuture =
370 preferredAccountWorker.selectAccount(
371 waitingForAccountCall.getNumber(), phoneAccountHandles);
twyena1723252018-04-24 17:02:57 -0700372 preferredAccountWorkerResultListener.listen(
373 this,
374 preferredAccountFuture,
375 result -> {
twyen56f79ba2018-04-30 14:25:46 -0700376 String callId = waitingForAccountCall.getId();
377 if (result.getSelectedPhoneAccountHandle().isPresent()) {
twyena1723252018-04-24 17:02:57 -0700378 selectPhoneAccountListener.onPhoneAccountSelected(
twyen56f79ba2018-04-30 14:25:46 -0700379 result.getSelectedPhoneAccountHandle().get(), false, callId);
twyena1723252018-04-24 17:02:57 -0700380 return;
381 }
twyen66adad02018-04-24 13:51:08 -0700382
linyuhf62092d2018-06-07 11:03:48 -0700383 if (!isVisible()) {
384 LogUtil.i(
385 "InCallActivity.showPhoneAccountSelectionDialog",
386 "activity ended before result returned");
387 return;
388 }
389
twyena1723252018-04-24 17:02:57 -0700390 waitingForAccountCall.setPreferredAccountRecorder(
391 new PreferredAccountRecorder(
392 waitingForAccountCall.getNumber(),
393 result.getSuggestion().orNull(),
394 result.getDataId().orNull()));
twyena1723252018-04-24 17:02:57 -0700395 selectPhoneAccountDialogFragment =
396 SelectPhoneAccountDialogFragment.newInstance(
twyen56f79ba2018-04-30 14:25:46 -0700397 result.getDialogOptionsBuilder().get().setCallId(callId).build(),
398 selectPhoneAccountListener);
twyena1723252018-04-24 17:02:57 -0700399 selectPhoneAccountDialogFragment.show(getFragmentManager(), Tags.SELECT_ACCOUNT_FRAGMENT);
400 },
401 throwable -> {
402 throw new RuntimeException(throwable);
403 });
twyen73a74c32018-03-07 12:12:24 -0800404
linyuhc3968e62017-11-20 17:40:50 -0800405 return true;
406 }
407
Eric Erfanianccca3152017-02-22 16:32:36 -0800408 @Override
409 protected void onSaveInstanceState(Bundle out) {
linyuh57b093b2017-11-17 14:32:32 -0800410 LogUtil.enterBlock("InCallActivity.onSaveInstanceState");
411
412 // TODO: DialpadFragment should handle this as part of its own state
linyuhc3968e62017-11-20 17:40:50 -0800413 out.putBoolean(IntentExtraNames.SHOW_DIALPAD, isDialpadVisible());
linyuh57b093b2017-11-17 14:32:32 -0800414 DialpadFragment dialpadFragment = getDialpadFragment();
415 if (dialpadFragment != null) {
linyuhc3968e62017-11-20 17:40:50 -0800416 out.putString(KeysForSavedInstance.DIALPAD_TEXT, dialpadFragment.getDtmfText());
linyuh57b093b2017-11-17 14:32:32 -0800417 }
418
linyuhc3968e62017-11-20 17:40:50 -0800419 out.putBoolean(KeysForSavedInstance.DID_SHOW_ANSWER_SCREEN, didShowAnswerScreen);
420 out.putBoolean(KeysForSavedInstance.DID_SHOW_IN_CALL_SCREEN, didShowInCallScreen);
421 out.putBoolean(KeysForSavedInstance.DID_SHOW_VIDEO_CALL_SCREEN, didShowVideoCallScreen);
wangqi153af2f2018-02-15 16:21:49 -0800422 out.putBoolean(KeysForSavedInstance.DID_SHOW_RTT_CALL_SCREEN, didShowRttCallScreen);
erfaniand05d8992018-03-20 19:42:26 -0700423 out.putBoolean(KeysForSavedInstance.DID_SHOW_SPEAK_EASY_SCREEN, didShowSpeakEasyScreen);
linyuh57b093b2017-11-17 14:32:32 -0800424
Eric Erfanianccca3152017-02-22 16:32:36 -0800425 super.onSaveInstanceState(out);
426 isVisible = false;
427 }
428
429 @Override
430 protected void onStart() {
Eric Erfanian2ca43182017-08-31 06:57:16 -0700431 Trace.beginSection("InCallActivity.onStart");
Eric Erfanianccca3152017-02-22 16:32:36 -0800432 super.onStart();
linyuh57b093b2017-11-17 14:32:32 -0800433
Eric Erfanianccca3152017-02-22 16:32:36 -0800434 isVisible = true;
435 showMainInCallFragment();
linyuh57b093b2017-11-17 14:32:32 -0800436
437 InCallPresenter.getInstance().setActivity(this);
438 enableInCallOrientationEventListener(
439 getRequestedOrientation()
440 == InCallOrientationEventListener.ACTIVITY_PREFERENCE_ALLOW_ROTATION);
441 InCallPresenter.getInstance().onActivityStarted();
442
yueg10f6e822018-01-17 15:32:18 -0800443 if (!isRecreating) {
444 InCallPresenter.getInstance().onUiShowing(true);
445 }
446
linyuh437ae952018-03-26 12:46:18 -0700447 if (isInMultiWindowMode() && !getResources().getBoolean(R.bool.incall_dialpad_allowed)) {
Eric Erfanianccca3152017-02-22 16:32:36 -0800448 // Hide the dialpad because there may not be enough room
449 showDialpadFragment(false, false);
450 }
linyuh57b093b2017-11-17 14:32:32 -0800451
Eric Erfanian2ca43182017-08-31 06:57:16 -0700452 Trace.endSection();
Eric Erfanianccca3152017-02-22 16:32:36 -0800453 }
454
455 @Override
456 protected void onResume() {
Eric Erfanian2ca43182017-08-31 06:57:16 -0700457 Trace.beginSection("InCallActivity.onResume");
Eric Erfanianccca3152017-02-22 16:32:36 -0800458 super.onResume();
linyuhc3968e62017-11-20 17:40:50 -0800459
460 if (!InCallPresenter.getInstance().isReadyForTearDown()) {
461 updateTaskDescription();
linyuhc3968e62017-11-20 17:40:50 -0800462 }
463
464 // If there is a pending request to show or hide the dialpad, handle that now.
465 if (showDialpadRequest != DIALPAD_REQUEST_NONE) {
466 if (showDialpadRequest == DIALPAD_REQUEST_SHOW) {
467 // Exit fullscreen so that the user has access to the dialpad hide/show button.
468 // This is important when showing the dialpad from within dialer.
469 InCallPresenter.getInstance().setFullScreen(false /* isFullScreen */, true /* force */);
470
471 showDialpadFragment(true /* show */, animateDialpadOnShow /* animate */);
472 animateDialpadOnShow = false;
473
474 DialpadFragment dialpadFragment = getDialpadFragment();
475 if (dialpadFragment != null) {
476 dialpadFragment.setDtmfText(dtmfTextToPrepopulate);
477 dtmfTextToPrepopulate = null;
478 }
479 } else {
480 LogUtil.i("InCallActivity.onResume", "Force-hide the dialpad");
481 if (getDialpadFragment() != null) {
482 showDialpadFragment(false /* show */, false /* animate */);
483 }
484 }
485 showDialpadRequest = DIALPAD_REQUEST_NONE;
486 }
linyuhc3968e62017-11-20 17:40:50 -0800487
linyuhc3968e62017-11-20 17:40:50 -0800488 CallList.getInstance()
489 .onInCallUiShown(getIntent().getBooleanExtra(IntentExtraNames.FOR_FULL_SCREEN, false));
490
Eric Erfanianccca3152017-02-22 16:32:36 -0800491 PseudoScreenState pseudoScreenState = InCallPresenter.getInstance().getPseudoScreenState();
492 pseudoScreenState.addListener(this);
493 onPseudoScreenStateChanged(pseudoScreenState.isOn());
Eric Erfanian2ca43182017-08-31 06:57:16 -0700494 Trace.endSection();
weijiaxu650e7cc2017-10-31 12:38:54 -0700495 // add 1 sec delay to get memory snapshot so that dialer wont react slowly on resume.
496 ThreadUtil.postDelayedOnUiThread(
weijiaxuc950a9b2017-11-06 16:39:04 -0800497 () ->
zachh7a96dc72018-02-20 22:16:03 -0800498 MetricsComponent.get(this)
499 .metrics()
500 .recordMemory(Metrics.INCALL_ACTIVITY_ON_RESUME_MEMORY_EVENT_NAME),
weijiaxu650e7cc2017-10-31 12:38:54 -0700501 1000);
Eric Erfanianccca3152017-02-22 16:32:36 -0800502 }
503
Eric Erfanianccca3152017-02-22 16:32:36 -0800504 @Override
505 protected void onPause() {
Eric Erfanian2ca43182017-08-31 06:57:16 -0700506 Trace.beginSection("InCallActivity.onPause");
Eric Erfanianccca3152017-02-22 16:32:36 -0800507 super.onPause();
linyuh57b093b2017-11-17 14:32:32 -0800508
509 DialpadFragment dialpadFragment = getDialpadFragment();
510 if (dialpadFragment != null) {
511 dialpadFragment.onDialerKeyUp(null);
512 }
513
Eric Erfanianccca3152017-02-22 16:32:36 -0800514 InCallPresenter.getInstance().getPseudoScreenState().removeListener(this);
Eric Erfanian2ca43182017-08-31 06:57:16 -0700515 Trace.endSection();
Eric Erfanianccca3152017-02-22 16:32:36 -0800516 }
517
518 @Override
519 protected void onStop() {
Eric Erfanian2ca43182017-08-31 06:57:16 -0700520 Trace.beginSection("InCallActivity.onStop");
wangqi4d705e52017-09-28 12:23:35 -0700521 isVisible = false;
Eric Erfanianccca3152017-02-22 16:32:36 -0800522 super.onStop();
linyuh57b093b2017-11-17 14:32:32 -0800523
524 // Disconnects the call waiting for a phone account when the activity is hidden (e.g., after the
525 // user presses the home button).
526 // Without this the pending call will get stuck on phone account selection and new calls can't
527 // be created.
528 // Skip this when the screen is locked since the activity may complete its current life cycle
529 // and restart.
linyuhc3968e62017-11-20 17:40:50 -0800530 if (!isRecreating && !getSystemService(KeyguardManager.class).isKeyguardLocked()) {
linyuh57b093b2017-11-17 14:32:32 -0800531 DialerCall waitingForAccountCall = CallList.getInstance().getWaitingForAccountCall();
532 if (waitingForAccountCall != null) {
533 waitingForAccountCall.disconnect();
534 }
535 }
536
537 enableInCallOrientationEventListener(false);
538 InCallPresenter.getInstance().updateIsChangingConfigurations();
539 InCallPresenter.getInstance().onActivityStopped();
linyuhc3968e62017-11-20 17:40:50 -0800540 if (!isRecreating) {
yueg10f6e822018-01-17 15:32:18 -0800541 InCallPresenter.getInstance().onUiShowing(false);
wangqie6060522018-04-05 11:47:15 -0700542 }
543 if (errorDialog != null) {
544 errorDialog.dismiss();
linyuh57b093b2017-11-17 14:32:32 -0800545 }
546
yueg10f6e822018-01-17 15:32:18 -0800547 if (isFinishing()) {
548 InCallPresenter.getInstance().unsetActivity(this);
549 }
550
Eric Erfanian2ca43182017-08-31 06:57:16 -0700551 Trace.endSection();
Eric Erfanianccca3152017-02-22 16:32:36 -0800552 }
553
554 @Override
555 protected void onDestroy() {
Eric Erfanian2ca43182017-08-31 06:57:16 -0700556 Trace.beginSection("InCallActivity.onDestroy");
Eric Erfanianccca3152017-02-22 16:32:36 -0800557 super.onDestroy();
linyuh57b093b2017-11-17 14:32:32 -0800558
559 InCallPresenter.getInstance().unsetActivity(this);
560 InCallPresenter.getInstance().updateIsChangingConfigurations();
Eric Erfanian2ca43182017-08-31 06:57:16 -0700561 Trace.endSection();
Eric Erfanianccca3152017-02-22 16:32:36 -0800562 }
563
564 @Override
565 public void finish() {
566 if (shouldCloseActivityOnFinish()) {
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700567 // When user select incall ui from recents after the call is disconnected, it tries to launch
568 // a new InCallActivity but InCallPresenter is already teared down at this point, which causes
569 // crash.
570 // By calling finishAndRemoveTask() instead of finish() the task associated with
571 // InCallActivity is cleared completely. So system won't try to create a new InCallActivity in
572 // this case.
573 //
574 // Calling finish won't clear the task and normally when an activity finishes it shouldn't
575 // clear the task since there could be parent activity in the same task that's still alive.
576 // But InCallActivity is special since it's singleInstance which means it's root activity and
577 // only instance of activity in the task. So it should be safe to also remove task when
578 // finishing.
579 // It's also necessary in the sense of it's excluded from recents. So whenever the activity
580 // finishes, the task should also be removed since it doesn't make sense to go back to it in
581 // anyway anymore.
582 super.finishAndRemoveTask();
Eric Erfanianccca3152017-02-22 16:32:36 -0800583 }
584 }
585
586 private boolean shouldCloseActivityOnFinish() {
linyuhc3968e62017-11-20 17:40:50 -0800587 if (!isVisible) {
Eric Erfanianccca3152017-02-22 16:32:36 -0800588 LogUtil.i(
589 "InCallActivity.shouldCloseActivityOnFinish",
590 "allowing activity to be closed because it's not visible");
591 return true;
592 }
593
twyen8efb4952017-10-06 16:35:54 -0700594 if (InCallPresenter.getInstance().isInCallUiLocked()) {
Eric Erfanianccca3152017-02-22 16:32:36 -0800595 LogUtil.i(
596 "InCallActivity.shouldCloseActivityOnFinish",
twyen8efb4952017-10-06 16:35:54 -0700597 "in call ui is locked, not closing activity");
Eric Erfanianccca3152017-02-22 16:32:36 -0800598 return false;
599 }
600
601 LogUtil.i(
602 "InCallActivity.shouldCloseActivityOnFinish",
twyen8efb4952017-10-06 16:35:54 -0700603 "activity is visible and has no locks, allowing activity to close");
Eric Erfanianccca3152017-02-22 16:32:36 -0800604 return true;
605 }
606
607 @Override
608 protected void onNewIntent(Intent intent) {
linyuhc3968e62017-11-20 17:40:50 -0800609 LogUtil.enterBlock("InCallActivity.onNewIntent");
Eric Erfanianccca3152017-02-22 16:32:36 -0800610
611 // If the screen is off, we need to make sure it gets turned on for incoming calls.
612 // This normally works just fine thanks to FLAG_TURN_SCREEN_ON but that only works
613 // when the activity is first created. Therefore, to ensure the screen is turned on
614 // for the call waiting case, we recreate() the current activity. There should be no jank from
615 // this since the screen is already off and will remain so until our new activity is up.
linyuhc3968e62017-11-20 17:40:50 -0800616 if (!isVisible) {
617 onNewIntent(intent, true /* isRecreating */);
Eric Erfanianccca3152017-02-22 16:32:36 -0800618 LogUtil.i("InCallActivity.onNewIntent", "Restarting InCallActivity to force screen on.");
619 recreate();
Eric Erfanian10b34a52017-05-04 08:23:17 -0700620 } else {
linyuhc3968e62017-11-20 17:40:50 -0800621 onNewIntent(intent, false /* isRecreating */);
622 }
623 }
624
yuega3305352018-01-09 11:02:47 -0800625 @VisibleForTesting
626 void onNewIntent(Intent intent, boolean isRecreating) {
linyuhc3968e62017-11-20 17:40:50 -0800627 this.isRecreating = isRecreating;
628
629 // We're being re-launched with a new Intent. Since it's possible for a single InCallActivity
630 // instance to persist indefinitely (even if we finish() ourselves), this sequence can
631 // happen any time the InCallActivity needs to be displayed.
632
633 // Stash away the new intent so that we can get it in the future by calling getIntent().
634 // Otherwise getIntent() will return the original Intent from when we first got created.
635 setIntent(intent);
636
637 // Activities are always paused before receiving a new intent, so we can count on our onResume()
638 // method being called next.
639
640 // Just like in onCreate(), handle the intent.
641 // Skip if InCallActivity is going to be recreated since this will be called in onCreate().
642 if (!isRecreating) {
643 internalResolveIntent(intent);
Eric Erfanianccca3152017-02-22 16:32:36 -0800644 }
645 }
646
647 @Override
648 public void onBackPressed() {
linyuh57b093b2017-11-17 14:32:32 -0800649 LogUtil.enterBlock("InCallActivity.onBackPressed");
650
linyuhc3968e62017-11-20 17:40:50 -0800651 if (!isVisible) {
linyuh57b093b2017-11-17 14:32:32 -0800652 return;
Eric Erfanianccca3152017-02-22 16:32:36 -0800653 }
linyuh57b093b2017-11-17 14:32:32 -0800654
655 if (!getCallCardFragmentVisible()) {
656 return;
657 }
658
659 DialpadFragment dialpadFragment = getDialpadFragment();
660 if (dialpadFragment != null && dialpadFragment.isVisible()) {
661 showDialpadFragment(false /* show */, true /* animate */);
662 return;
663 }
664
665 if (CallList.getInstance().getIncomingCall() != null) {
666 LogUtil.i(
667 "InCallActivity.onBackPressed",
668 "Ignore the press of the back key when an incoming call is ringing");
669 return;
670 }
671
672 // Nothing special to do. Fall back to the default behavior.
673 super.onBackPressed();
Eric Erfanianccca3152017-02-22 16:32:36 -0800674 }
675
676 @Override
677 public boolean onOptionsItemSelected(MenuItem item) {
678 LogUtil.i("InCallActivity.onOptionsItemSelected", "item: " + item);
679 if (item.getItemId() == android.R.id.home) {
680 onBackPressed();
681 return true;
682 }
683 return super.onOptionsItemSelected(item);
684 }
685
686 @Override
687 public boolean onKeyUp(int keyCode, KeyEvent event) {
linyuh57b093b2017-11-17 14:32:32 -0800688 DialpadFragment dialpadFragment = getDialpadFragment();
689 if (dialpadFragment != null
690 && dialpadFragment.isVisible()
691 && dialpadFragment.onDialerKeyUp(event)) {
692 return true;
693 }
694
695 if (keyCode == KeyEvent.KEYCODE_CALL) {
696 // Always consume KEYCODE_CALL to ensure the PhoneWindow won't do anything with it.
697 return true;
698 }
699
700 return super.onKeyUp(keyCode, event);
Eric Erfanianccca3152017-02-22 16:32:36 -0800701 }
702
703 @Override
704 public boolean onKeyDown(int keyCode, KeyEvent event) {
linyuh57b093b2017-11-17 14:32:32 -0800705 switch (keyCode) {
706 case KeyEvent.KEYCODE_CALL:
707 if (!InCallPresenter.getInstance().handleCallKey()) {
708 LogUtil.e(
709 "InCallActivity.onKeyDown",
710 "InCallPresenter should always handle KEYCODE_CALL in onKeyDown");
711 }
712 // Always consume KEYCODE_CALL to ensure the PhoneWindow won't do anything with it.
713 return true;
714
715 // Note that KEYCODE_ENDCALL isn't handled here as the standard system-wide handling of it
716 // is exactly what's needed, namely
717 // (1) "hang up" if there's an active call, or
718 // (2) "don't answer" if there's an incoming call.
719 // (See PhoneWindowManager for implementation details.)
720
721 case KeyEvent.KEYCODE_CAMERA:
722 // Consume KEYCODE_CAMERA since it's easy to accidentally press the camera button.
723 return true;
724
725 case KeyEvent.KEYCODE_VOLUME_UP:
726 case KeyEvent.KEYCODE_VOLUME_DOWN:
727 case KeyEvent.KEYCODE_VOLUME_MUTE:
728 // Ringer silencing handled by PhoneWindowManager.
729 break;
730
731 case KeyEvent.KEYCODE_MUTE:
732 TelecomAdapter.getInstance()
733 .mute(!AudioModeProvider.getInstance().getAudioState().isMuted());
734 return true;
735
736 case KeyEvent.KEYCODE_SLASH:
737 // When verbose logging is enabled, dump the view for debugging/testing purposes.
738 if (LogUtil.isVerboseEnabled()) {
739 View decorView = getWindow().getDecorView();
740 LogUtil.v("InCallActivity.onKeyDown", "View dump:\n%s", decorView);
741 return true;
742 }
743 break;
744
745 case KeyEvent.KEYCODE_EQUALS:
746 break;
747
748 default: // fall out
749 }
750
751 // Pass other key events to DialpadFragment's "onDialerKeyDown" method in case the user types
752 // in DTMF (Dual-tone multi-frequency signaling) code.
753 DialpadFragment dialpadFragment = getDialpadFragment();
754 if (dialpadFragment != null
755 && dialpadFragment.isVisible()
756 && dialpadFragment.onDialerKeyDown(event)) {
757 return true;
758 }
759
760 return super.onKeyDown(keyCode, event);
Eric Erfanianccca3152017-02-22 16:32:36 -0800761 }
762
763 public boolean isInCallScreenAnimating() {
764 return false;
765 }
766
767 public void showConferenceFragment(boolean show) {
768 if (show) {
769 startActivity(new Intent(this, ManageConferenceActivity.class));
770 }
771 }
772
linyuhc3968e62017-11-20 17:40:50 -0800773 public void showDialpadFragment(boolean show, boolean animate) {
774 if (show == isDialpadVisible()) {
775 return;
Eric Erfanianccca3152017-02-22 16:32:36 -0800776 }
linyuhc3968e62017-11-20 17:40:50 -0800777
778 FragmentManager dialpadFragmentManager = getDialpadFragmentManager();
779 if (dialpadFragmentManager == null) {
780 LogUtil.i("InCallActivity.showDialpadFragment", "Unable to obtain a FragmentManager");
781 return;
782 }
783
784 if (!animate) {
785 if (show) {
786 showDialpadFragment();
787 } else {
788 hideDialpadFragment();
789 }
790 } else {
791 if (show) {
792 showDialpadFragment();
793 getDialpadFragment().animateShowDialpad();
794 }
795 getDialpadFragment()
796 .getView()
797 .startAnimation(show ? dialpadSlideInAnimation : dialpadSlideOutAnimation);
798 }
799
800 ProximitySensor sensor = InCallPresenter.getInstance().getProximitySensor();
801 if (sensor != null) {
802 sensor.onDialpadVisible(show);
803 }
804 showDialpadRequest = DIALPAD_REQUEST_NONE;
linyuhc3968e62017-11-20 17:40:50 -0800805 }
806
807 private void showDialpadFragment() {
808 FragmentManager dialpadFragmentManager = getDialpadFragmentManager();
809 if (dialpadFragmentManager == null) {
810 return;
811 }
812
813 FragmentTransaction transaction = dialpadFragmentManager.beginTransaction();
814 DialpadFragment dialpadFragment = getDialpadFragment();
815 if (dialpadFragment == null) {
wangqifd4c9f72018-03-08 18:21:50 -0800816 dialpadFragment = new DialpadFragment();
817 transaction.add(getDialpadContainerId(), dialpadFragment, Tags.DIALPAD_FRAGMENT);
linyuhc3968e62017-11-20 17:40:50 -0800818 } else {
819 transaction.show(dialpadFragment);
calderwoodrad5883872017-12-12 15:29:12 -0800820 dialpadFragment.setUserVisibleHint(true);
linyuhc3968e62017-11-20 17:40:50 -0800821 }
wangqifd4c9f72018-03-08 18:21:50 -0800822 // RTT call screen doesn't show end call button inside dialpad, thus the space reserved for end
823 // call button should be removed.
824 dialpadFragment.setShouldShowEndCallSpace(didShowInCallScreen);
linyuhc3968e62017-11-20 17:40:50 -0800825 transaction.commitAllowingStateLoss();
826 dialpadFragmentManager.executePendingTransactions();
827
828 Logger.get(this).logScreenView(ScreenEvent.Type.INCALL_DIALPAD, this);
wangqi73ed6132018-05-21 15:57:36 -0700829 getInCallOrRttCallScreen().onInCallScreenDialpadVisibilityChange(true);
linyuhc3968e62017-11-20 17:40:50 -0800830 }
831
832 private void hideDialpadFragment() {
833 FragmentManager dialpadFragmentManager = getDialpadFragmentManager();
834 if (dialpadFragmentManager == null) {
835 return;
836 }
837
calderwoodrad5883872017-12-12 15:29:12 -0800838 DialpadFragment dialpadFragment = getDialpadFragment();
linyuhc3968e62017-11-20 17:40:50 -0800839 if (dialpadFragment != null) {
840 FragmentTransaction transaction = dialpadFragmentManager.beginTransaction();
841 transaction.hide(dialpadFragment);
842 transaction.commitAllowingStateLoss();
843 dialpadFragmentManager.executePendingTransactions();
calderwoodrad5883872017-12-12 15:29:12 -0800844 dialpadFragment.setUserVisibleHint(false);
wangqi73ed6132018-05-21 15:57:36 -0700845 getInCallOrRttCallScreen().onInCallScreenDialpadVisibilityChange(false);
linyuhc3968e62017-11-20 17:40:50 -0800846 }
Eric Erfanianccca3152017-02-22 16:32:36 -0800847 }
848
849 public boolean isDialpadVisible() {
linyuh69a25062017-11-15 16:18:51 -0800850 DialpadFragment dialpadFragment = getDialpadFragment();
calderwoodraa584bcd2018-01-24 12:19:56 -0800851 return dialpadFragment != null
852 && dialpadFragment.isAdded()
853 && !dialpadFragment.isHidden()
854 && dialpadFragment.getView() != null
855 && dialpadFragment.getUserVisibleHint();
linyuh69a25062017-11-15 16:18:51 -0800856 }
857
linyuhc3968e62017-11-20 17:40:50 -0800858 /** Returns the {@link DialpadFragment} that's shown by this activity, or {@code null} */
linyuh69a25062017-11-15 16:18:51 -0800859 @Nullable
linyuhc3968e62017-11-20 17:40:50 -0800860 private DialpadFragment getDialpadFragment() {
linyuh69a25062017-11-15 16:18:51 -0800861 FragmentManager fragmentManager = getDialpadFragmentManager();
862 if (fragmentManager == null) {
863 return null;
864 }
linyuhc3968e62017-11-20 17:40:50 -0800865 return (DialpadFragment) fragmentManager.findFragmentByTag(Tags.DIALPAD_FRAGMENT);
Eric Erfanianccca3152017-02-22 16:32:36 -0800866 }
867
868 public void onForegroundCallChanged(DialerCall newForegroundCall) {
linyuh57b093b2017-11-17 14:32:32 -0800869 updateTaskDescription();
Eric Erfanianccca3152017-02-22 16:32:36 -0800870 }
871
linyuhc3968e62017-11-20 17:40:50 -0800872 private void updateTaskDescription() {
linyuh57b093b2017-11-17 14:32:32 -0800873 int color =
874 getResources().getBoolean(R.bool.is_layout_landscape)
875 ? ResourcesCompat.getColor(
876 getResources(), R.color.statusbar_background_color, getTheme())
877 : InCallPresenter.getInstance().getThemeColorManager().getSecondaryColor();
878 setTaskDescription(
879 new TaskDescription(
880 getResources().getString(R.string.notification_ongoing_call), null /* icon */, color));
881 }
882
Eric Erfanianccca3152017-02-22 16:32:36 -0800883 public boolean isVisible() {
884 return isVisible;
885 }
886
887 public boolean getCallCardFragmentVisible() {
erfaniand05d8992018-03-20 19:42:26 -0700888 return didShowInCallScreen
889 || didShowVideoCallScreen
890 || didShowRttCallScreen
891 || didShowSpeakEasyScreen;
Eric Erfanianccca3152017-02-22 16:32:36 -0800892 }
893
894 public void dismissKeyguard(boolean dismiss) {
linyuh9c327da2017-11-14 12:33:48 -0800895 if (dismissKeyguard == dismiss) {
896 return;
897 }
898
899 dismissKeyguard = dismiss;
900 if (dismiss) {
901 getWindow().addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);
902 } else {
903 getWindow().clearFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);
904 }
Eric Erfanianccca3152017-02-22 16:32:36 -0800905 }
906
linyuhc3968e62017-11-20 17:40:50 -0800907 public void showDialogForPostCharWait(String callId, String chars) {
yuega489f512018-04-25 12:01:09 -0700908 PostCharDialogFragment fragment = new PostCharDialogFragment(callId, chars);
909 fragment.show(getSupportFragmentManager(), Tags.POST_CHAR_DIALOG_FRAGMENT);
Eric Erfanianccca3152017-02-22 16:32:36 -0800910 }
911
linyuh7b86f562017-11-16 11:24:09 -0800912 public void showDialogOrToastForDisconnectedCall(DisconnectMessage disconnectMessage) {
913 LogUtil.i(
914 "InCallActivity.showDialogOrToastForDisconnectedCall",
915 "disconnect cause: %s",
916 disconnectMessage);
917
918 if (disconnectMessage.dialog == null || isFinishing()) {
919 return;
920 }
921
922 dismissPendingDialogs();
923
924 // Show a toast if the app is in background when a dialog can't be visible.
925 if (!isVisible()) {
926 Toast.makeText(getApplicationContext(), disconnectMessage.toastMessage, Toast.LENGTH_LONG)
927 .show();
928 return;
929 }
930
931 // Show the dialog.
linyuhc3968e62017-11-20 17:40:50 -0800932 errorDialog = disconnectMessage.dialog;
linyuh7b86f562017-11-16 11:24:09 -0800933 InCallUiLock lock = InCallPresenter.getInstance().acquireInCallUiLock("showErrorDialog");
934 disconnectMessage.dialog.setOnDismissListener(
935 dialogInterface -> {
936 lock.release();
937 onDialogDismissed();
938 });
939 disconnectMessage.dialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
940 disconnectMessage.dialog.show();
941 }
942
943 private void onDialogDismissed() {
linyuhc3968e62017-11-20 17:40:50 -0800944 errorDialog = null;
linyuh7b86f562017-11-16 11:24:09 -0800945 CallList.getInstance().onErrorDialogDismissed();
Eric Erfanianccca3152017-02-22 16:32:36 -0800946 }
947
948 public void dismissPendingDialogs() {
linyuhc3968e62017-11-20 17:40:50 -0800949 LogUtil.enterBlock("InCallActivity.dismissPendingDialogs");
linyuhf99f6302017-11-15 11:23:51 -0800950
951 if (!isVisible) {
952 // Defer the dismissing action as the activity is not visible and onSaveInstanceState may have
953 // been called.
Eric Erfanianccca3152017-02-22 16:32:36 -0800954 LogUtil.i(
955 "InCallActivity.dismissPendingDialogs", "defer actions since activity is not visible");
956 needDismissPendingDialogs = true;
linyuhf99f6302017-11-15 11:23:51 -0800957 return;
Eric Erfanianccca3152017-02-22 16:32:36 -0800958 }
linyuhf99f6302017-11-15 11:23:51 -0800959
960 // Dismiss the error dialog
linyuhf99f6302017-11-15 11:23:51 -0800961 if (errorDialog != null) {
962 errorDialog.dismiss();
linyuhc3968e62017-11-20 17:40:50 -0800963 errorDialog = null;
linyuhf99f6302017-11-15 11:23:51 -0800964 }
965
966 // Dismiss the phone account selection dialog
linyuhf99f6302017-11-15 11:23:51 -0800967 if (selectPhoneAccountDialogFragment != null) {
968 selectPhoneAccountDialogFragment.dismiss();
linyuhc3968e62017-11-20 17:40:50 -0800969 selectPhoneAccountDialogFragment = null;
linyuhf99f6302017-11-15 11:23:51 -0800970 }
971
972 // Dismiss the dialog for international call on WiFi
973 InternationalCallOnWifiDialogFragment internationalCallOnWifiFragment =
974 (InternationalCallOnWifiDialogFragment)
linyuhc3968e62017-11-20 17:40:50 -0800975 getSupportFragmentManager().findFragmentByTag(Tags.INTERNATIONAL_CALL_ON_WIFI);
linyuhf99f6302017-11-15 11:23:51 -0800976 if (internationalCallOnWifiFragment != null) {
977 internationalCallOnWifiFragment.dismiss();
978 }
979
980 // Dismiss the answer screen
981 AnswerScreen answerScreen = getAnswerScreen();
982 if (answerScreen != null) {
983 answerScreen.dismissPendingDialogs();
984 }
985
986 needDismissPendingDialogs = false;
Eric Erfanianccca3152017-02-22 16:32:36 -0800987 }
988
linyuhc3968e62017-11-20 17:40:50 -0800989 private void enableInCallOrientationEventListener(boolean enable) {
linyuh69a25062017-11-15 16:18:51 -0800990 if (enable) {
991 inCallOrientationEventListener.enable(true /* notifyDeviceOrientationChange */);
992 } else {
993 inCallOrientationEventListener.disable();
994 }
Eric Erfanianccca3152017-02-22 16:32:36 -0800995 }
996
997 public void setExcludeFromRecents(boolean exclude) {
linyuhc3968e62017-11-20 17:40:50 -0800998 int taskId = getTaskId();
999
1000 List<AppTask> tasks = getSystemService(ActivityManager.class).getAppTasks();
1001 for (AppTask task : tasks) {
1002 try {
1003 if (task.getTaskInfo().id == taskId) {
1004 task.setExcludeFromRecents(exclude);
1005 }
1006 } catch (RuntimeException e) {
1007 LogUtil.e("InCallActivity.setExcludeFromRecents", "RuntimeException:\n%s", e);
1008 }
1009 }
Eric Erfanianccca3152017-02-22 16:32:36 -08001010 }
1011
Eric Erfanianccca3152017-02-22 16:32:36 -08001012 @Nullable
1013 public FragmentManager getDialpadFragmentManager() {
wangqifd4c9f72018-03-08 18:21:50 -08001014 InCallScreen inCallScreen = getInCallOrRttCallScreen();
Eric Erfanianccca3152017-02-22 16:32:36 -08001015 if (inCallScreen != null) {
1016 return inCallScreen.getInCallScreenFragment().getChildFragmentManager();
1017 }
1018 return null;
1019 }
1020
1021 public int getDialpadContainerId() {
wangqifd4c9f72018-03-08 18:21:50 -08001022 return getInCallOrRttCallScreen().getAnswerAndDialpadContainerResourceId();
Eric Erfanianccca3152017-02-22 16:32:36 -08001023 }
1024
1025 @Override
1026 public AnswerScreenDelegate newAnswerScreenDelegate(AnswerScreen answerScreen) {
1027 DialerCall call = CallList.getInstance().getCallById(answerScreen.getCallId());
1028 if (call == null) {
1029 // This is a work around for a bug where we attempt to create a new delegate after the call
1030 // has already been removed. An example of when this can happen is:
1031 // 1. incoming video call in landscape mode
1032 // 2. remote party hangs up
1033 // 3. activity switches from landscape to portrait
1034 // At step #3 the answer fragment will try to create a new answer delegate but the call won't
1035 // exist. In this case we'll simply return a stub delegate that does nothing. This is ok
1036 // because this new state is transient and the activity will be destroyed soon.
1037 LogUtil.i("InCallActivity.onPrimaryCallStateChanged", "call doesn't exist, using stub");
1038 return new AnswerScreenPresenterStub();
1039 } else {
1040 return new AnswerScreenPresenter(
1041 this, answerScreen, CallList.getInstance().getCallById(answerScreen.getCallId()));
1042 }
1043 }
1044
1045 @Override
1046 public InCallScreenDelegate newInCallScreenDelegate() {
1047 return new CallCardPresenter(this);
1048 }
1049
1050 @Override
1051 public InCallButtonUiDelegate newInCallButtonUiDelegate() {
1052 return new CallButtonPresenter(this);
1053 }
1054
1055 @Override
Eric Erfanian90508232017-03-24 09:31:16 -07001056 public VideoCallScreenDelegate newVideoCallScreenDelegate(VideoCallScreen videoCallScreen) {
1057 DialerCall dialerCall = CallList.getInstance().getCallById(videoCallScreen.getCallId());
1058 if (dialerCall != null && dialerCall.getVideoTech().shouldUseSurfaceView()) {
1059 return dialerCall.getVideoTech().createVideoCallScreenDelegate(this, videoCallScreen);
1060 }
Eric Erfanianccca3152017-02-22 16:32:36 -08001061 return new VideoCallPresenter();
1062 }
1063
1064 public void onPrimaryCallStateChanged() {
Eric Erfanian2ca43182017-08-31 06:57:16 -07001065 Trace.beginSection("InCallActivity.onPrimaryCallStateChanged");
Eric Erfanianccca3152017-02-22 16:32:36 -08001066 showMainInCallFragment();
Eric Erfanian2ca43182017-08-31 06:57:16 -07001067 Trace.endSection();
Eric Erfanianccca3152017-02-22 16:32:36 -08001068 }
1069
linyuh7b86f562017-11-16 11:24:09 -08001070 public void showDialogOrToastForWifiHandoverFailure(DialerCall call) {
1071 if (call.showWifiHandoverAlertAsToast()) {
1072 Toast.makeText(this, R.string.video_call_lte_to_wifi_failed_message, Toast.LENGTH_SHORT)
1073 .show();
1074 return;
1075 }
1076
1077 dismissPendingDialogs();
1078
1079 AlertDialog.Builder builder =
1080 new AlertDialog.Builder(this).setTitle(R.string.video_call_lte_to_wifi_failed_title);
1081
1082 // This allows us to use the theme of the dialog instead of the activity
1083 View dialogCheckBoxView =
1084 View.inflate(builder.getContext(), R.layout.video_call_lte_to_wifi_failed, null /* root */);
1085 CheckBox wifiHandoverFailureCheckbox =
1086 (CheckBox) dialogCheckBoxView.findViewById(R.id.video_call_lte_to_wifi_failed_checkbox);
1087 wifiHandoverFailureCheckbox.setChecked(false);
1088
1089 InCallUiLock lock = InCallPresenter.getInstance().acquireInCallUiLock("WifiFailedDialog");
linyuhc3968e62017-11-20 17:40:50 -08001090 errorDialog =
linyuh7b86f562017-11-16 11:24:09 -08001091 builder
1092 .setView(dialogCheckBoxView)
1093 .setMessage(R.string.video_call_lte_to_wifi_failed_message)
1094 .setOnCancelListener(dialogInterface -> onDialogDismissed())
1095 .setPositiveButton(
1096 android.R.string.ok,
1097 (dialogInterface, id) -> {
1098 call.setDoNotShowDialogForHandoffToWifiFailure(
1099 wifiHandoverFailureCheckbox.isChecked());
1100 dialogInterface.cancel();
1101 onDialogDismissed();
1102 })
1103 .setOnDismissListener(dialogInterface -> lock.release())
1104 .create();
linyuh7b86f562017-11-16 11:24:09 -08001105 errorDialog.show();
Eric Erfanianccca3152017-02-22 16:32:36 -08001106 }
1107
linyuh7b86f562017-11-16 11:24:09 -08001108 public void showDialogForInternationalCallOnWifi(@NonNull DialerCall call) {
linyuh7b86f562017-11-16 11:24:09 -08001109 InternationalCallOnWifiDialogFragment fragment =
yuegb47528e2018-04-24 12:12:57 -07001110 InternationalCallOnWifiDialogFragment.newInstance(call.getId());
linyuhc3968e62017-11-20 17:40:50 -08001111 fragment.show(getSupportFragmentManager(), Tags.INTERNATIONAL_CALL_ON_WIFI);
Eric Erfanianc857f902017-05-15 14:05:33 -07001112 }
1113
wangqibc28ea72018-04-02 16:23:00 -07001114 public void showDialogForRttRequest(DialerCall call, int rttRequestId) {
1115 LogUtil.enterBlock("InCallActivity.showDialogForRttRequest");
wangqifb0cfff2018-06-05 11:51:01 -07001116 rttRequestDialogFragment = RttRequestDialogFragment.newInstance(call.getId(), rttRequestId);
1117 rttRequestDialogFragment.show(getSupportFragmentManager(), Tags.RTT_REQUEST_DIALOG);
wangqibc28ea72018-04-02 16:23:00 -07001118 }
1119
Eric Erfanianccca3152017-02-22 16:32:36 -08001120 public void setAllowOrientationChange(boolean allowOrientationChange) {
wangqi9982f0d2017-10-11 17:46:07 -07001121 if (this.allowOrientationChange == allowOrientationChange) {
1122 return;
1123 }
1124 this.allowOrientationChange = allowOrientationChange;
Eric Erfanianccca3152017-02-22 16:32:36 -08001125 if (!allowOrientationChange) {
1126 setRequestedOrientation(InCallOrientationEventListener.ACTIVITY_PREFERENCE_DISALLOW_ROTATION);
1127 } else {
1128 setRequestedOrientation(InCallOrientationEventListener.ACTIVITY_PREFERENCE_ALLOW_ROTATION);
1129 }
1130 enableInCallOrientationEventListener(allowOrientationChange);
1131 }
1132
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001133 public void hideMainInCallFragment() {
linyuhc3968e62017-11-20 17:40:50 -08001134 LogUtil.enterBlock("InCallActivity.hideMainInCallFragment");
1135 if (getCallCardFragmentVisible()) {
Eric Erfanianccca3152017-02-22 16:32:36 -08001136 FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
1137 hideInCallScreenFragment(transaction);
1138 hideVideoCallScreenFragment(transaction);
1139 transaction.commitAllowingStateLoss();
1140 getSupportFragmentManager().executePendingTransactions();
1141 }
1142 }
1143
1144 private void showMainInCallFragment() {
Eric Erfanian2ca43182017-08-31 06:57:16 -07001145 Trace.beginSection("InCallActivity.showMainInCallFragment");
Eric Erfanianccca3152017-02-22 16:32:36 -08001146 // If the activity's onStart method hasn't been called yet then defer doing any work.
1147 if (!isVisible) {
1148 LogUtil.i("InCallActivity.showMainInCallFragment", "not visible yet/anymore");
Eric Erfanian2ca43182017-08-31 06:57:16 -07001149 Trace.endSection();
Eric Erfanianccca3152017-02-22 16:32:36 -08001150 return;
1151 }
1152
1153 // Don't let this be reentrant.
1154 if (isInShowMainInCallFragment) {
1155 LogUtil.i("InCallActivity.showMainInCallFragment", "already in method, bailing");
Eric Erfanian2ca43182017-08-31 06:57:16 -07001156 Trace.endSection();
Eric Erfanianccca3152017-02-22 16:32:36 -08001157 return;
1158 }
1159
1160 isInShowMainInCallFragment = true;
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001161 ShouldShowUiResult shouldShowAnswerUi = getShouldShowAnswerUi();
1162 ShouldShowUiResult shouldShowVideoUi = getShouldShowVideoUi();
wangqi219b8702018-02-13 09:34:41 -08001163 ShouldShowUiResult shouldShowRttUi = getShouldShowRttUi();
erfaniand05d8992018-03-20 19:42:26 -07001164 ShouldShowUiResult shouldShowSpeakEasyUi = getShouldShowSpeakEasyUi();
Eric Erfanianccca3152017-02-22 16:32:36 -08001165 LogUtil.i(
1166 "InCallActivity.showMainInCallFragment",
uabdullah56a4cda2018-05-10 16:38:35 -07001167 "shouldShowAnswerUi: %b, shouldShowRttUi: %b, shouldShowVideoUi: %b, "
1168 + "shouldShowSpeakEasyUi: %b, didShowAnswerScreen: %b, didShowInCallScreen: %b, "
1169 + "didShowRttCallScreen: %b, didShowVideoCallScreen: %b, didShowSpeakEasyScreen: %b",
Eric Erfanianccca3152017-02-22 16:32:36 -08001170 shouldShowAnswerUi.shouldShow,
wangqi219b8702018-02-13 09:34:41 -08001171 shouldShowRttUi.shouldShow,
Eric Erfanian10b34a52017-05-04 08:23:17 -07001172 shouldShowVideoUi.shouldShow,
uabdullah56a4cda2018-05-10 16:38:35 -07001173 shouldShowSpeakEasyUi.shouldShow,
Eric Erfanianccca3152017-02-22 16:32:36 -08001174 didShowAnswerScreen,
1175 didShowInCallScreen,
wangqi219b8702018-02-13 09:34:41 -08001176 didShowRttCallScreen,
erfaniand05d8992018-03-20 19:42:26 -07001177 didShowVideoCallScreen,
1178 didShowSpeakEasyScreen);
Eric Erfanianccca3152017-02-22 16:32:36 -08001179 // Only video call ui allows orientation change.
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001180 setAllowOrientationChange(shouldShowVideoUi.shouldShow);
Eric Erfanianccca3152017-02-22 16:32:36 -08001181
1182 FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
wangqi219b8702018-02-13 09:34:41 -08001183 boolean didChange;
Eric Erfanianccca3152017-02-22 16:32:36 -08001184 if (shouldShowAnswerUi.shouldShow) {
wangqi219b8702018-02-13 09:34:41 -08001185 didChange = hideInCallScreenFragment(transaction);
1186 didChange |= hideVideoCallScreenFragment(transaction);
1187 didChange |= hideRttCallScreenFragment(transaction);
erfaniand05d8992018-03-20 19:42:26 -07001188 didChange |= hideSpeakEasyFragment(transaction);
wangqi219b8702018-02-13 09:34:41 -08001189 didChange |= showAnswerScreenFragment(transaction, shouldShowAnswerUi.call);
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001190 } else if (shouldShowVideoUi.shouldShow) {
wangqi219b8702018-02-13 09:34:41 -08001191 didChange = hideInCallScreenFragment(transaction);
1192 didChange |= showVideoCallScreenFragment(transaction, shouldShowVideoUi.call);
1193 didChange |= hideRttCallScreenFragment(transaction);
erfaniand05d8992018-03-20 19:42:26 -07001194 didChange |= hideSpeakEasyFragment(transaction);
wangqi219b8702018-02-13 09:34:41 -08001195 didChange |= hideAnswerScreenFragment(transaction);
1196 } else if (shouldShowRttUi.shouldShow) {
1197 didChange = hideInCallScreenFragment(transaction);
1198 didChange |= hideVideoCallScreenFragment(transaction);
1199 didChange |= hideAnswerScreenFragment(transaction);
erfaniand05d8992018-03-20 19:42:26 -07001200 didChange |= hideSpeakEasyFragment(transaction);
wangqi219b8702018-02-13 09:34:41 -08001201 didChange |= showRttCallScreenFragment(transaction, shouldShowRttUi.call);
erfaniand05d8992018-03-20 19:42:26 -07001202 } else if (shouldShowSpeakEasyUi.shouldShow) {
1203 didChange = hideInCallScreenFragment(transaction);
1204 didChange |= hideVideoCallScreenFragment(transaction);
1205 didChange |= hideAnswerScreenFragment(transaction);
1206 didChange |= hideRttCallScreenFragment(transaction);
1207 didChange |= showSpeakEasyFragment(transaction, shouldShowSpeakEasyUi.call);
Eric Erfanianccca3152017-02-22 16:32:36 -08001208 } else {
wangqi219b8702018-02-13 09:34:41 -08001209 didChange = showInCallScreenFragment(transaction);
1210 didChange |= hideVideoCallScreenFragment(transaction);
1211 didChange |= hideRttCallScreenFragment(transaction);
erfaniand05d8992018-03-20 19:42:26 -07001212 didChange |= hideSpeakEasyFragment(transaction);
wangqi219b8702018-02-13 09:34:41 -08001213 didChange |= hideAnswerScreenFragment(transaction);
Eric Erfanianccca3152017-02-22 16:32:36 -08001214 }
1215
wangqi219b8702018-02-13 09:34:41 -08001216 if (didChange) {
Eric Erfanian2ca43182017-08-31 06:57:16 -07001217 Trace.beginSection("InCallActivity.commitTransaction");
Eric Erfanianccca3152017-02-22 16:32:36 -08001218 transaction.commitNow();
Eric Erfanian2ca43182017-08-31 06:57:16 -07001219 Trace.endSection();
Eric Erfanianccca3152017-02-22 16:32:36 -08001220 Logger.get(this).logScreenView(ScreenEvent.Type.INCALL, this);
1221 }
1222 isInShowMainInCallFragment = false;
Eric Erfanian2ca43182017-08-31 06:57:16 -07001223 Trace.endSection();
Eric Erfanianccca3152017-02-22 16:32:36 -08001224 }
1225
erfaniand05d8992018-03-20 19:42:26 -07001226 private boolean showSpeakEasyFragment(FragmentTransaction transaction, DialerCall call) {
1227
erfaniand05d8992018-03-20 19:42:26 -07001228 if (didShowSpeakEasyScreen) {
erfanian612d13a2018-04-04 15:27:57 -07001229 if (lastShownSpeakEasyScreenUniqueCallid.equals(call.getUniqueCallId())) {
erfanian12243de2018-04-17 12:17:08 -07001230 LogUtil.i("InCallActivity.showSpeakEasyFragment", "found existing fragment");
erfanian612d13a2018-04-04 15:27:57 -07001231 return false;
1232 }
1233 hideSpeakEasyFragment(transaction);
erfanian12243de2018-04-17 12:17:08 -07001234 LogUtil.i("InCallActivity.showSpeakEasyFragment", "hid existing fragment");
erfaniand05d8992018-03-20 19:42:26 -07001235 }
1236
1237 Optional<Fragment> speakEasyFragment = speakEasyCallManager.getSpeakEasyFragment(call);
1238 if (speakEasyFragment.isPresent()) {
1239 transaction.add(R.id.main, speakEasyFragment.get(), Tags.SPEAK_EASY_SCREEN);
1240 didShowSpeakEasyScreen = true;
erfanian612d13a2018-04-04 15:27:57 -07001241 lastShownSpeakEasyScreenUniqueCallid = call.getUniqueCallId();
erfanian12243de2018-04-17 12:17:08 -07001242 LogUtil.i(
1243 "InCallActivity.showSpeakEasyFragment",
1244 "set fragment for call %s",
1245 lastShownSpeakEasyScreenUniqueCallid);
erfaniand05d8992018-03-20 19:42:26 -07001246 return true;
1247 }
1248 return false;
1249 }
1250
1251 private Fragment getSpeakEasyScreen() {
1252 return getSupportFragmentManager().findFragmentByTag(Tags.SPEAK_EASY_SCREEN);
1253 }
1254
1255 private boolean hideSpeakEasyFragment(FragmentTransaction transaction) {
1256 if (!didShowSpeakEasyScreen) {
1257 return false;
1258 }
1259
1260 Fragment speakEasyFragment = getSpeakEasyScreen();
1261
1262 if (speakEasyFragment != null) {
1263 transaction.remove(speakEasyFragment);
1264 didShowSpeakEasyScreen = false;
1265 return true;
1266 }
1267 return false;
1268 }
1269
erfanian12243de2018-04-17 12:17:08 -07001270 @VisibleForTesting
erfaniand05d8992018-03-20 19:42:26 -07001271 public void setSpeakEasyCallManager(SpeakEasyCallManager speakEasyCallManager) {
erfanian87dbb622018-04-04 15:43:00 -07001272 this.speakEasyCallManager = speakEasyCallManager;
erfaniand05d8992018-03-20 19:42:26 -07001273 }
1274
erfanian12243de2018-04-17 12:17:08 -07001275 @Nullable
erfaniand05d8992018-03-20 19:42:26 -07001276 public SpeakEasyCallManager getSpeakEasyCallManager() {
erfanian12243de2018-04-17 12:17:08 -07001277 if (this.speakEasyCallManager == null) {
1278 this.speakEasyCallManager = InCallPresenter.getInstance().getSpeakEasyCallManager();
1279 }
erfaniand05d8992018-03-20 19:42:26 -07001280 return speakEasyCallManager;
1281 }
1282
1283 private ShouldShowUiResult getShouldShowSpeakEasyUi() {
1284 SpeakEasyCallManager speakEasyCallManager = getSpeakEasyCallManager();
1285
1286 if (speakEasyCallManager == null) {
1287 return new ShouldShowUiResult(false, null);
1288 }
1289
erfanian3bb7cb62018-04-11 09:01:15 -07001290 DialerCall call =
1291 CallList.getInstance().getIncomingCall() != null
1292 ? CallList.getInstance().getIncomingCall()
1293 : CallList.getInstance().getActiveCall();
erfaniand05d8992018-03-20 19:42:26 -07001294
1295 if (call == null) {
erfanian38e0ed42018-06-25 15:24:07 -07001296 // This is a special case where the first call is not automatically resumed
1297 // after the second active call is remotely disconnected.
1298 DialerCall backgroundCall = CallList.getInstance().getBackgroundCall();
1299 if (backgroundCall != null && backgroundCall.isSpeakEasyCall()) {
1300 LogUtil.i("InCallActivity.getShouldShowSpeakEasyUi", "taking call off hold");
1301
1302 backgroundCall.unhold();
1303 return new ShouldShowUiResult(true, backgroundCall);
1304 }
1305
erfaniand05d8992018-03-20 19:42:26 -07001306 return new ShouldShowUiResult(false, call);
1307 }
1308
1309 if (!call.isSpeakEasyCall() || !call.isSpeakEasyEligible()) {
1310 return new ShouldShowUiResult(false, call);
1311 }
1312
1313 Optional<Fragment> speakEasyFragment = speakEasyCallManager.getSpeakEasyFragment(call);
1314
1315 if (!speakEasyFragment.isPresent()) {
1316 return new ShouldShowUiResult(false, call);
1317 }
1318 return new ShouldShowUiResult(true, call);
1319 }
1320
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001321 private ShouldShowUiResult getShouldShowAnswerUi() {
Eric Erfanianccca3152017-02-22 16:32:36 -08001322 DialerCall call = CallList.getInstance().getIncomingCall();
erfanian3bb7cb62018-04-11 09:01:15 -07001323 if (call != null && !call.isSpeakEasyCall()) {
Eric Erfanianccca3152017-02-22 16:32:36 -08001324 LogUtil.i("InCallActivity.getShouldShowAnswerUi", "found incoming call");
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001325 return new ShouldShowUiResult(true, call);
Eric Erfanianccca3152017-02-22 16:32:36 -08001326 }
1327
1328 call = CallList.getInstance().getVideoUpgradeRequestCall();
1329 if (call != null) {
1330 LogUtil.i("InCallActivity.getShouldShowAnswerUi", "found video upgrade request");
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001331 return new ShouldShowUiResult(true, call);
Eric Erfanianccca3152017-02-22 16:32:36 -08001332 }
1333
1334 // Check if we're showing the answer screen and the call is disconnected. If this condition is
1335 // true then we won't switch from the answer UI to the in call UI. This prevents flicker when
1336 // the user rejects an incoming call.
1337 call = CallList.getInstance().getFirstCall();
1338 if (call == null) {
1339 call = CallList.getInstance().getBackgroundCall();
1340 }
wangqibb94ca62018-04-27 14:34:04 -07001341 if (didShowAnswerScreen && (call == null || call.getState() == DialerCallState.DISCONNECTED)) {
Eric Erfanianccca3152017-02-22 16:32:36 -08001342 LogUtil.i("InCallActivity.getShouldShowAnswerUi", "found disconnecting incoming call");
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001343 return new ShouldShowUiResult(true, call);
Eric Erfanianccca3152017-02-22 16:32:36 -08001344 }
1345
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001346 return new ShouldShowUiResult(false, null);
Eric Erfanianccca3152017-02-22 16:32:36 -08001347 }
1348
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001349 private static ShouldShowUiResult getShouldShowVideoUi() {
Eric Erfanianccca3152017-02-22 16:32:36 -08001350 DialerCall call = CallList.getInstance().getFirstCall();
1351 if (call == null) {
1352 LogUtil.i("InCallActivity.getShouldShowVideoUi", "null call");
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001353 return new ShouldShowUiResult(false, null);
Eric Erfanianccca3152017-02-22 16:32:36 -08001354 }
1355
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001356 if (call.isVideoCall()) {
Eric Erfanianccca3152017-02-22 16:32:36 -08001357 LogUtil.i("InCallActivity.getShouldShowVideoUi", "found video call");
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001358 return new ShouldShowUiResult(true, call);
Eric Erfanianccca3152017-02-22 16:32:36 -08001359 }
1360
linyuh8fbecce2017-12-18 13:53:09 -08001361 if (call.hasSentVideoUpgradeRequest() || call.hasReceivedVideoUpgradeRequest()) {
Eric Erfanianccca3152017-02-22 16:32:36 -08001362 LogUtil.i("InCallActivity.getShouldShowVideoUi", "upgrading to video");
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001363 return new ShouldShowUiResult(true, call);
Eric Erfanianccca3152017-02-22 16:32:36 -08001364 }
1365
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001366 return new ShouldShowUiResult(false, null);
Eric Erfanianccca3152017-02-22 16:32:36 -08001367 }
1368
wangqi219b8702018-02-13 09:34:41 -08001369 private static ShouldShowUiResult getShouldShowRttUi() {
1370 DialerCall call = CallList.getInstance().getFirstCall();
1371 if (call == null) {
1372 LogUtil.i("InCallActivity.getShouldShowRttUi", "null call");
1373 return new ShouldShowUiResult(false, null);
1374 }
1375
wangqif6be6172018-03-30 15:57:56 -07001376 if (call.isActiveRttCall()) {
wangqi219b8702018-02-13 09:34:41 -08001377 LogUtil.i("InCallActivity.getShouldShowRttUi", "found rtt call");
1378 return new ShouldShowUiResult(true, call);
1379 }
1380
1381 if (call.hasSentRttUpgradeRequest()) {
1382 LogUtil.i("InCallActivity.getShouldShowRttUi", "upgrading to rtt");
1383 return new ShouldShowUiResult(true, call);
1384 }
1385
1386 return new ShouldShowUiResult(false, null);
1387 }
1388
Eric Erfanianccca3152017-02-22 16:32:36 -08001389 private boolean showAnswerScreenFragment(FragmentTransaction transaction, DialerCall call) {
1390 // When rejecting a call the active call can become null in which case we should continue
1391 // showing the answer screen.
1392 if (didShowAnswerScreen && call == null) {
1393 return false;
1394 }
1395
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001396 Assert.checkArgument(call != null, "didShowAnswerScreen was false but call was still null");
1397
1398 boolean isVideoUpgradeRequest = call.hasReceivedVideoUpgradeRequest();
Eric Erfanianccca3152017-02-22 16:32:36 -08001399
1400 // Check if we're already showing an answer screen for this call.
1401 if (didShowAnswerScreen) {
1402 AnswerScreen answerScreen = getAnswerScreen();
1403 if (answerScreen.getCallId().equals(call.getId())
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001404 && answerScreen.isVideoCall() == call.isVideoCall()
Eric Erfanian2ca43182017-08-31 06:57:16 -07001405 && answerScreen.isVideoUpgradeRequest() == isVideoUpgradeRequest
1406 && !answerScreen.isActionTimeout()) {
1407 LogUtil.d(
1408 "InCallActivity.showAnswerScreenFragment",
1409 "answer fragment exists for same call and has NOT been accepted/rejected/timed out");
Eric Erfanianccca3152017-02-22 16:32:36 -08001410 return false;
1411 }
Eric Erfanian2ca43182017-08-31 06:57:16 -07001412 if (answerScreen.isActionTimeout()) {
1413 LogUtil.i(
1414 "InCallActivity.showAnswerScreenFragment",
1415 "answer fragment exists but has been accepted/rejected and timed out");
1416 } else {
1417 LogUtil.i(
1418 "InCallActivity.showAnswerScreenFragment",
1419 "answer fragment exists but arguments do not match");
1420 }
Eric Erfanianccca3152017-02-22 16:32:36 -08001421 hideAnswerScreenFragment(transaction);
1422 }
1423
1424 // Show a new answer screen.
1425 AnswerScreen answerScreen =
Eric Erfanianfc37b022017-03-21 10:11:17 -07001426 AnswerBindings.createAnswerScreen(
1427 call.getId(),
wangqif6be6172018-03-30 15:57:56 -07001428 call.isActiveRttCall(),
Eric Erfanianfc37b022017-03-21 10:11:17 -07001429 call.isVideoCall(),
1430 isVideoUpgradeRequest,
Eric Erfanian90508232017-03-24 09:31:16 -07001431 call.getVideoTech().isSelfManagedCamera(),
1432 shouldAllowAnswerAndRelease(call),
erfaniand05d8992018-03-20 19:42:26 -07001433 CallList.getInstance().getBackgroundCall() != null,
erfanian89e3d1b2018-05-02 18:50:59 -07001434 getSpeakEasyCallManager().isAvailable(getApplicationContext())
1435 && call.isSpeakEasyEligible());
linyuhc3968e62017-11-20 17:40:50 -08001436 transaction.add(R.id.main, answerScreen.getAnswerScreenFragment(), Tags.ANSWER_SCREEN);
Eric Erfanianccca3152017-02-22 16:32:36 -08001437
1438 Logger.get(this).logScreenView(ScreenEvent.Type.INCOMING_CALL, this);
1439 didShowAnswerScreen = true;
1440 return true;
1441 }
1442
Eric Erfanian90508232017-03-24 09:31:16 -07001443 private boolean shouldAllowAnswerAndRelease(DialerCall call) {
1444 if (CallList.getInstance().getActiveCall() == null) {
1445 LogUtil.i("InCallActivity.shouldAllowAnswerAndRelease", "no active call");
1446 return false;
1447 }
1448 if (getSystemService(TelephonyManager.class).getPhoneType()
1449 == TelephonyManager.PHONE_TYPE_CDMA) {
1450 LogUtil.i("InCallActivity.shouldAllowAnswerAndRelease", "PHONE_TYPE_CDMA not supported");
1451 return false;
1452 }
1453 if (call.isVideoCall() || call.hasReceivedVideoUpgradeRequest()) {
1454 LogUtil.i("InCallActivity.shouldAllowAnswerAndRelease", "video call");
1455 return false;
1456 }
zachh190343a2018-05-31 17:30:46 -07001457 if (!ConfigProviderComponent.get(this)
1458 .getConfigProvider()
linyuhc3968e62017-11-20 17:40:50 -08001459 .getBoolean(ConfigNames.ANSWER_AND_RELEASE_ENABLED, true)) {
Eric Erfanian90508232017-03-24 09:31:16 -07001460 LogUtil.i("InCallActivity.shouldAllowAnswerAndRelease", "disabled by config");
1461 return false;
1462 }
1463
1464 return true;
1465 }
1466
Eric Erfanianccca3152017-02-22 16:32:36 -08001467 private boolean hideAnswerScreenFragment(FragmentTransaction transaction) {
1468 if (!didShowAnswerScreen) {
1469 return false;
1470 }
1471 AnswerScreen answerScreen = getAnswerScreen();
1472 if (answerScreen != null) {
1473 transaction.remove(answerScreen.getAnswerScreenFragment());
1474 }
1475
1476 didShowAnswerScreen = false;
1477 return true;
1478 }
1479
1480 private boolean showInCallScreenFragment(FragmentTransaction transaction) {
1481 if (didShowInCallScreen) {
1482 return false;
1483 }
Eric Erfanian2ca43182017-08-31 06:57:16 -07001484 InCallScreen inCallScreen = InCallBindings.createInCallScreen();
linyuhc3968e62017-11-20 17:40:50 -08001485 transaction.add(R.id.main, inCallScreen.getInCallScreenFragment(), Tags.IN_CALL_SCREEN);
Eric Erfanianccca3152017-02-22 16:32:36 -08001486 Logger.get(this).logScreenView(ScreenEvent.Type.INCALL, this);
1487 didShowInCallScreen = true;
1488 return true;
1489 }
1490
1491 private boolean hideInCallScreenFragment(FragmentTransaction transaction) {
1492 if (!didShowInCallScreen) {
1493 return false;
1494 }
1495 InCallScreen inCallScreen = getInCallScreen();
1496 if (inCallScreen != null) {
Eric Erfanian2ca43182017-08-31 06:57:16 -07001497 transaction.remove(inCallScreen.getInCallScreenFragment());
Eric Erfanianccca3152017-02-22 16:32:36 -08001498 }
1499 didShowInCallScreen = false;
1500 return true;
1501 }
1502
wangqi219b8702018-02-13 09:34:41 -08001503 private boolean showRttCallScreenFragment(FragmentTransaction transaction, DialerCall call) {
1504 if (didShowRttCallScreen) {
wangqi91958f82018-06-06 14:01:47 -07001505 if (getRttCallScreen().getCallId().equals(call.getId())) {
1506 return false;
wangqi219b8702018-02-13 09:34:41 -08001507 }
wangqi91958f82018-06-06 14:01:47 -07001508 LogUtil.i("InCallActivity.showRttCallScreenFragment", "RTT call id doesn't match");
1509 hideRttCallScreenFragment(transaction);
wangqi219b8702018-02-13 09:34:41 -08001510 }
1511 RttCallScreen rttCallScreen = RttBindings.createRttCallScreen(call.getId());
1512 transaction.add(R.id.main, rttCallScreen.getRttCallScreenFragment(), Tags.RTT_CALL_SCREEN);
1513 Logger.get(this).logScreenView(ScreenEvent.Type.INCALL, this);
1514 didShowRttCallScreen = true;
wangqifb0cfff2018-06-05 11:51:01 -07001515 // In some cases such as VZW, RTT request will be automatically accepted by modem. So the dialog
1516 // won't make any sense and should be dismissed if it's already switched to RTT.
1517 if (rttRequestDialogFragment != null) {
1518 LogUtil.i("InCallActivity.showRttCallScreenFragment", "dismiss RTT request dialog");
1519 rttRequestDialogFragment.dismiss();
1520 rttRequestDialogFragment = null;
1521 }
wangqi219b8702018-02-13 09:34:41 -08001522 return true;
1523 }
1524
1525 private boolean hideRttCallScreenFragment(FragmentTransaction transaction) {
1526 if (!didShowRttCallScreen) {
1527 return false;
1528 }
1529 RttCallScreen rttCallScreen = getRttCallScreen();
1530 if (rttCallScreen != null) {
1531 transaction.remove(rttCallScreen.getRttCallScreenFragment());
1532 }
1533 didShowRttCallScreen = false;
1534 return true;
1535 }
1536
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001537 private boolean showVideoCallScreenFragment(FragmentTransaction transaction, DialerCall call) {
Eric Erfanianccca3152017-02-22 16:32:36 -08001538 if (didShowVideoCallScreen) {
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001539 VideoCallScreen videoCallScreen = getVideoCallScreen();
1540 if (videoCallScreen.getCallId().equals(call.getId())) {
1541 return false;
1542 }
1543 LogUtil.i(
1544 "InCallActivity.showVideoCallScreenFragment",
1545 "video call fragment exists but arguments do not match");
1546 hideVideoCallScreenFragment(transaction);
Eric Erfanianccca3152017-02-22 16:32:36 -08001547 }
1548
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001549 LogUtil.i("InCallActivity.showVideoCallScreenFragment", "call: %s", call);
1550
Eric Erfanian90508232017-03-24 09:31:16 -07001551 VideoCallScreen videoCallScreen =
1552 VideoBindings.createVideoCallScreen(
1553 call.getId(), call.getVideoTech().shouldUseSurfaceView());
linyuhc3968e62017-11-20 17:40:50 -08001554 transaction.add(
1555 R.id.main, videoCallScreen.getVideoCallScreenFragment(), Tags.VIDEO_CALL_SCREEN);
Eric Erfanianccca3152017-02-22 16:32:36 -08001556
1557 Logger.get(this).logScreenView(ScreenEvent.Type.INCALL, this);
1558 didShowVideoCallScreen = true;
1559 return true;
1560 }
1561
1562 private boolean hideVideoCallScreenFragment(FragmentTransaction transaction) {
1563 if (!didShowVideoCallScreen) {
1564 return false;
1565 }
1566 VideoCallScreen videoCallScreen = getVideoCallScreen();
1567 if (videoCallScreen != null) {
1568 transaction.remove(videoCallScreen.getVideoCallScreenFragment());
1569 }
1570 didShowVideoCallScreen = false;
1571 return true;
1572 }
1573
linyuhc3968e62017-11-20 17:40:50 -08001574 private AnswerScreen getAnswerScreen() {
1575 return (AnswerScreen) getSupportFragmentManager().findFragmentByTag(Tags.ANSWER_SCREEN);
Eric Erfanianccca3152017-02-22 16:32:36 -08001576 }
1577
linyuhc3968e62017-11-20 17:40:50 -08001578 private InCallScreen getInCallScreen() {
1579 return (InCallScreen) getSupportFragmentManager().findFragmentByTag(Tags.IN_CALL_SCREEN);
Eric Erfanianccca3152017-02-22 16:32:36 -08001580 }
1581
linyuhc3968e62017-11-20 17:40:50 -08001582 private VideoCallScreen getVideoCallScreen() {
1583 return (VideoCallScreen) getSupportFragmentManager().findFragmentByTag(Tags.VIDEO_CALL_SCREEN);
Eric Erfanianccca3152017-02-22 16:32:36 -08001584 }
1585
wangqi219b8702018-02-13 09:34:41 -08001586 private RttCallScreen getRttCallScreen() {
1587 return (RttCallScreen) getSupportFragmentManager().findFragmentByTag(Tags.RTT_CALL_SCREEN);
1588 }
1589
wangqifd4c9f72018-03-08 18:21:50 -08001590 private InCallScreen getInCallOrRttCallScreen() {
1591 InCallScreen inCallScreen = null;
1592 if (didShowInCallScreen) {
1593 inCallScreen = getInCallScreen();
1594 }
1595 if (didShowRttCallScreen) {
1596 inCallScreen = getRttCallScreen();
1597 }
1598 return inCallScreen;
1599 }
1600
Eric Erfanianccca3152017-02-22 16:32:36 -08001601 @Override
1602 public void onPseudoScreenStateChanged(boolean isOn) {
1603 LogUtil.i("InCallActivity.onPseudoScreenStateChanged", "isOn: " + isOn);
1604 pseudoBlackScreenOverlay.setVisibility(isOn ? View.GONE : View.VISIBLE);
1605 }
1606
1607 /**
1608 * For some touch related issue, turning off the screen can be faked by drawing a black view over
1609 * the activity. All touch events started when the screen is "off" is rejected.
1610 *
1611 * @see PseudoScreenState
1612 */
1613 @Override
1614 public boolean dispatchTouchEvent(MotionEvent event) {
1615 // Reject any gesture that started when the screen is in the fake off state.
1616 if (touchDownWhenPseudoScreenOff) {
1617 if (event.getAction() == MotionEvent.ACTION_UP) {
1618 touchDownWhenPseudoScreenOff = false;
1619 }
1620 return true;
1621 }
1622 // Reject all touch event when the screen is in the fake off state.
1623 if (!InCallPresenter.getInstance().getPseudoScreenState().isOn()) {
1624 if (event.getAction() == MotionEvent.ACTION_DOWN) {
1625 touchDownWhenPseudoScreenOff = true;
1626 LogUtil.i("InCallActivity.dispatchTouchEvent", "touchDownWhenPseudoScreenOff");
1627 }
1628 return true;
1629 }
1630 return super.dispatchTouchEvent(event);
1631 }
1632
wangqi219b8702018-02-13 09:34:41 -08001633 @Override
1634 public RttCallScreenDelegate newRttCallScreenDelegate(RttCallScreen videoCallScreen) {
1635 return new RttCallPresenter();
1636 }
1637
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001638 private static class ShouldShowUiResult {
Eric Erfanianccca3152017-02-22 16:32:36 -08001639 public final boolean shouldShow;
1640 public final DialerCall call;
1641
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001642 ShouldShowUiResult(boolean shouldShow, DialerCall call) {
Eric Erfanianccca3152017-02-22 16:32:36 -08001643 this.shouldShow = shouldShow;
1644 this.call = call;
1645 }
1646 }
linyuhc3968e62017-11-20 17:40:50 -08001647
1648 private static final class IntentExtraNames {
1649 static final String FOR_FULL_SCREEN = "InCallActivity.for_full_screen_intent";
1650 static final String NEW_OUTGOING_CALL = "InCallActivity.new_outgoing_call";
1651 static final String SHOW_DIALPAD = "InCallActivity.show_dialpad";
1652 }
1653
1654 private static final class KeysForSavedInstance {
1655 static final String DIALPAD_TEXT = "InCallActivity.dialpad_text";
1656 static final String DID_SHOW_ANSWER_SCREEN = "did_show_answer_screen";
1657 static final String DID_SHOW_IN_CALL_SCREEN = "did_show_in_call_screen";
1658 static final String DID_SHOW_VIDEO_CALL_SCREEN = "did_show_video_call_screen";
wangqi153af2f2018-02-15 16:21:49 -08001659 static final String DID_SHOW_RTT_CALL_SCREEN = "did_show_rtt_call_screen";
erfaniand05d8992018-03-20 19:42:26 -07001660 static final String DID_SHOW_SPEAK_EASY_SCREEN = "did_show_speak_easy_screen";
linyuhc3968e62017-11-20 17:40:50 -08001661 }
1662
1663 /** Request codes for pending intents. */
1664 public static final class PendingIntentRequestCodes {
1665 static final int NON_FULL_SCREEN = 0;
1666 static final int FULL_SCREEN = 1;
1667 static final int BUBBLE = 2;
1668 }
1669
1670 private static final class Tags {
1671 static final String ANSWER_SCREEN = "tag_answer_screen";
1672 static final String DIALPAD_FRAGMENT = "tag_dialpad_fragment";
1673 static final String IN_CALL_SCREEN = "tag_in_call_screen";
1674 static final String INTERNATIONAL_CALL_ON_WIFI = "tag_international_call_on_wifi";
1675 static final String SELECT_ACCOUNT_FRAGMENT = "tag_select_account_fragment";
1676 static final String VIDEO_CALL_SCREEN = "tag_video_call_screen";
wangqi219b8702018-02-13 09:34:41 -08001677 static final String RTT_CALL_SCREEN = "tag_rtt_call_screen";
linyuhc3968e62017-11-20 17:40:50 -08001678 static final String POST_CHAR_DIALOG_FRAGMENT = "tag_post_char_dialog_fragment";
erfaniand05d8992018-03-20 19:42:26 -07001679 static final String SPEAK_EASY_SCREEN = "tag_speak_easy_screen";
wangqibc28ea72018-04-02 16:23:00 -07001680 static final String RTT_REQUEST_DIALOG = "tag_rtt_request_dialog";
linyuhc3968e62017-11-20 17:40:50 -08001681 }
1682
1683 private static final class ConfigNames {
1684 static final String ANSWER_AND_RELEASE_ENABLED = "answer_and_release_enabled";
1685 }
1686
linyuhc3968e62017-11-20 17:40:50 -08001687 private static final class SelectPhoneAccountListener
1688 extends SelectPhoneAccountDialogFragment.SelectPhoneAccountListener {
1689 private static final String TAG = SelectPhoneAccountListener.class.getCanonicalName();
1690
twyen73a74c32018-03-07 12:12:24 -08001691 private final Context appContext;
1692
1693 SelectPhoneAccountListener(Context appContext) {
1694 this.appContext = appContext;
1695 }
1696
linyuhc3968e62017-11-20 17:40:50 -08001697 @Override
1698 public void onPhoneAccountSelected(
1699 PhoneAccountHandle selectedAccountHandle, boolean setDefault, String callId) {
1700 DialerCall call = CallList.getInstance().getCallById(callId);
1701 LogUtil.i(TAG, "Phone account select with call:\n%s", call);
1702
1703 if (call != null) {
twyen73a74c32018-03-07 12:12:24 -08001704 call.phoneAccountSelected(selectedAccountHandle, false);
1705 if (call.getPreferredAccountRecorder() != null) {
1706 call.getPreferredAccountRecorder().record(appContext, selectedAccountHandle, setDefault);
1707 }
linyuhc3968e62017-11-20 17:40:50 -08001708 }
1709 }
1710
1711 @Override
1712 public void onDialogDismissed(String callId) {
1713 DialerCall call = CallList.getInstance().getCallById(callId);
1714 LogUtil.i(TAG, "Disconnecting call:\n%s" + call);
1715
1716 if (call != null) {
1717 call.disconnect();
1718 }
1719 }
1720 }
Eric Erfanianccca3152017-02-22 16:32:36 -08001721}