blob: 3ff1d269d0efe4a895df28aad74873df9e52790c [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 Erfanian4ca9e8d2018-07-10 18:37:03 +000028import android.graphics.drawable.GradientDrawable;
29import android.graphics.drawable.GradientDrawable.Orientation;
Eric Erfanianccca3152017-02-22 16:32:36 -080030import android.os.Bundle;
Eric Erfanian2ca43182017-08-31 06:57:16 -070031import android.os.Trace;
Eric Erfanian4ca9e8d2018-07-10 18:37:03 +000032import android.support.annotation.ColorInt;
33import android.support.annotation.FloatRange;
linyuhc3968e62017-11-20 17:40:50 -080034import android.support.annotation.IntDef;
Eric Erfanianc857f902017-05-15 14:05:33 -070035import android.support.annotation.NonNull;
Eric Erfanianccca3152017-02-22 16:32:36 -080036import android.support.annotation.Nullable;
linyuhc3968e62017-11-20 17:40:50 -080037import android.support.annotation.VisibleForTesting;
wangqibc28ea72018-04-02 16:23:00 -070038import android.support.v4.app.DialogFragment;
erfaniand05d8992018-03-20 19:42:26 -070039import android.support.v4.app.Fragment;
Eric Erfanianccca3152017-02-22 16:32:36 -080040import android.support.v4.app.FragmentManager;
41import android.support.v4.app.FragmentTransaction;
linyuh57b093b2017-11-17 14:32:32 -080042import android.support.v4.content.res.ResourcesCompat;
Eric Erfanian4ca9e8d2018-07-10 18:37:03 +000043import android.support.v4.graphics.ColorUtils;
twyen73a74c32018-03-07 12:12:24 -080044import android.telecom.Call;
linyuhc3968e62017-11-20 17:40:50 -080045import android.telecom.CallAudioState;
46import android.telecom.PhoneAccountHandle;
Eric Erfanian90508232017-03-24 09:31:16 -070047import android.telephony.TelephonyManager;
Eric Erfanianccca3152017-02-22 16:32:36 -080048import android.view.KeyEvent;
49import android.view.MenuItem;
50import android.view.MotionEvent;
51import android.view.View;
linyuh9c327da2017-11-14 12:33:48 -080052import android.view.WindowManager;
linyuhc3968e62017-11-20 17:40:50 -080053import android.view.animation.Animation;
54import android.view.animation.AnimationUtils;
linyuh7b86f562017-11-16 11:24:09 -080055import android.widget.CheckBox;
56import android.widget.Toast;
linyuhf99f6302017-11-15 11:23:51 -080057import com.android.contacts.common.widget.SelectPhoneAccountDialogFragment;
linyuhc3968e62017-11-20 17:40:50 -080058import com.android.dialer.animation.AnimUtils;
59import com.android.dialer.animation.AnimationListenerAdapter;
Eric Erfaniand5e47f62017-03-15 14:41:07 -070060import com.android.dialer.common.Assert;
Eric Erfanianccca3152017-02-22 16:32:36 -080061import com.android.dialer.common.LogUtil;
twyen73a74c32018-03-07 12:12:24 -080062import com.android.dialer.common.concurrent.DialerExecutorComponent;
weijiaxu650e7cc2017-10-31 12:38:54 -070063import com.android.dialer.common.concurrent.ThreadUtil;
twyena1723252018-04-24 17:02:57 -070064import com.android.dialer.common.concurrent.UiListener;
zachh190343a2018-05-31 17:30:46 -070065import com.android.dialer.configprovider.ConfigProviderComponent;
Eric Erfanianccca3152017-02-22 16:32:36 -080066import com.android.dialer.logging.Logger;
Eric Erfanian8369df02017-05-03 10:27:13 -070067import com.android.dialer.logging.ScreenEvent;
zachh7a96dc72018-02-20 22:16:03 -080068import com.android.dialer.metrics.Metrics;
69import com.android.dialer.metrics.MetricsComponent;
twyen73a74c32018-03-07 12:12:24 -080070import com.android.dialer.preferredsim.PreferredAccountRecorder;
71import com.android.dialer.preferredsim.PreferredAccountWorker;
twyena1723252018-04-24 17:02:57 -070072import com.android.dialer.preferredsim.PreferredAccountWorker.Result;
twyen56f79ba2018-04-30 14:25:46 -070073import com.android.dialer.preferredsim.PreferredSimComponent;
linyuhc3968e62017-11-20 17:40:50 -080074import com.android.dialer.util.ViewUtil;
Eric Erfanianccca3152017-02-22 16:32:36 -080075import com.android.incallui.answer.bindings.AnswerBindings;
76import com.android.incallui.answer.protocol.AnswerScreen;
77import com.android.incallui.answer.protocol.AnswerScreenDelegate;
78import com.android.incallui.answer.protocol.AnswerScreenDelegateFactory;
79import com.android.incallui.answerproximitysensor.PseudoScreenState;
linyuh57b093b2017-11-17 14:32:32 -080080import com.android.incallui.audiomode.AudioModeProvider;
Eric Erfanianccca3152017-02-22 16:32:36 -080081import com.android.incallui.call.CallList;
82import com.android.incallui.call.DialerCall;
linyuh57b093b2017-11-17 14:32:32 -080083import com.android.incallui.call.TelecomAdapter;
wangqibb94ca62018-04-27 14:34:04 -070084import com.android.incallui.call.state.DialerCallState;
Eric Erfanian2ca43182017-08-31 06:57:16 -070085import com.android.incallui.callpending.CallPendingActivity;
86import com.android.incallui.disconnectdialog.DisconnectMessage;
Eric Erfanianccca3152017-02-22 16:32:36 -080087import com.android.incallui.incall.bindings.InCallBindings;
88import com.android.incallui.incall.protocol.InCallButtonUiDelegate;
89import com.android.incallui.incall.protocol.InCallButtonUiDelegateFactory;
90import com.android.incallui.incall.protocol.InCallScreen;
91import com.android.incallui.incall.protocol.InCallScreenDelegate;
92import com.android.incallui.incall.protocol.InCallScreenDelegateFactory;
linyuh7b86f562017-11-16 11:24:09 -080093import com.android.incallui.incalluilock.InCallUiLock;
wangqi219b8702018-02-13 09:34:41 -080094import com.android.incallui.rtt.bindings.RttBindings;
95import com.android.incallui.rtt.protocol.RttCallScreen;
96import com.android.incallui.rtt.protocol.RttCallScreenDelegate;
97import com.android.incallui.rtt.protocol.RttCallScreenDelegateFactory;
erfaniand05d8992018-03-20 19:42:26 -070098import com.android.incallui.speakeasy.SpeakEasyCallManager;
linyuhf99f6302017-11-15 11:23:51 -080099import com.android.incallui.telecomeventui.InternationalCallOnWifiDialogFragment;
Eric Erfanianccca3152017-02-22 16:32:36 -0800100import com.android.incallui.video.bindings.VideoBindings;
101import com.android.incallui.video.protocol.VideoCallScreen;
102import com.android.incallui.video.protocol.VideoCallScreenDelegate;
103import com.android.incallui.video.protocol.VideoCallScreenDelegateFactory;
twyena1723252018-04-24 17:02:57 -0700104import com.google.common.util.concurrent.ListenableFuture;
linyuhc3968e62017-11-20 17:40:50 -0800105import java.lang.annotation.Retention;
106import java.lang.annotation.RetentionPolicy;
107import java.util.ArrayList;
108import java.util.List;
erfanian58672a62018-06-29 10:02:43 -0700109import java.util.Optional;
Eric Erfanianccca3152017-02-22 16:32:36 -0800110
111/** Version of {@link InCallActivity} that shows the new UI */
112public class InCallActivity extends TransactionSafeFragmentActivity
113 implements AnswerScreenDelegateFactory,
114 InCallScreenDelegateFactory,
115 InCallButtonUiDelegateFactory,
116 VideoCallScreenDelegateFactory,
wangqi219b8702018-02-13 09:34:41 -0800117 RttCallScreenDelegateFactory,
Eric Erfanianccca3152017-02-22 16:32:36 -0800118 PseudoScreenState.StateChangedListener {
119
linyuhc3968e62017-11-20 17:40:50 -0800120 @Retention(RetentionPolicy.SOURCE)
121 @IntDef({
122 DIALPAD_REQUEST_NONE,
123 DIALPAD_REQUEST_SHOW,
124 DIALPAD_REQUEST_HIDE,
125 })
126 @interface DialpadRequestType {}
Eric Erfanian2ca43182017-08-31 06:57:16 -0700127
linyuhc3968e62017-11-20 17:40:50 -0800128 private static final int DIALPAD_REQUEST_NONE = 1;
129 private static final int DIALPAD_REQUEST_SHOW = 2;
130 private static final int DIALPAD_REQUEST_HIDE = 3;
linyuh57b093b2017-11-17 14:32:32 -0800131
erfanian58672a62018-06-29 10:02:43 -0700132 private static Optional<Integer> audioRouteForTesting = Optional.empty();
linyuh57b093b2017-11-17 14:32:32 -0800133
twyen73a74c32018-03-07 12:12:24 -0800134 private SelectPhoneAccountListener selectPhoneAccountListener;
twyena1723252018-04-24 17:02:57 -0700135 private UiListener<Result> preferredAccountWorkerResultListener;
Eric Erfanianccca3152017-02-22 16:32:36 -0800136
linyuhc3968e62017-11-20 17:40:50 -0800137 private Animation dialpadSlideInAnimation;
138 private Animation dialpadSlideOutAnimation;
139 private Dialog errorDialog;
Eric Erfanian4ca9e8d2018-07-10 18:37:03 +0000140 private GradientDrawable backgroundDrawable;
linyuh69a25062017-11-15 16:18:51 -0800141 private InCallOrientationEventListener inCallOrientationEventListener;
linyuhc3968e62017-11-20 17:40:50 -0800142 private View pseudoBlackScreenOverlay;
143 private SelectPhoneAccountDialogFragment selectPhoneAccountDialogFragment;
144 private String dtmfTextToPrepopulate;
linyuhc3968e62017-11-20 17:40:50 -0800145 private boolean allowOrientationChange;
146 private boolean animateDialpadOnShow;
Eric Erfanianccca3152017-02-22 16:32:36 -0800147 private boolean didShowAnswerScreen;
148 private boolean didShowInCallScreen;
149 private boolean didShowVideoCallScreen;
wangqi219b8702018-02-13 09:34:41 -0800150 private boolean didShowRttCallScreen;
erfaniand05d8992018-03-20 19:42:26 -0700151 private boolean didShowSpeakEasyScreen;
erfanian612d13a2018-04-04 15:27:57 -0700152 private String lastShownSpeakEasyScreenUniqueCallid = "";
linyuh9c327da2017-11-14 12:33:48 -0800153 private boolean dismissKeyguard;
Eric Erfanianccca3152017-02-22 16:32:36 -0800154 private boolean isInShowMainInCallFragment;
linyuhc3968e62017-11-20 17:40:50 -0800155 private boolean isRecreating; // whether the activity is going to be recreated
156 private boolean isVisible;
Eric Erfanianccca3152017-02-22 16:32:36 -0800157 private boolean needDismissPendingDialogs;
linyuhc3968e62017-11-20 17:40:50 -0800158 private boolean touchDownWhenPseudoScreenOff;
Eric Erfanian4ca9e8d2018-07-10 18:37:03 +0000159 private int[] backgroundDrawableColors;
linyuhc3968e62017-11-20 17:40:50 -0800160 @DialpadRequestType private int showDialpadRequest = DIALPAD_REQUEST_NONE;
erfaniand05d8992018-03-20 19:42:26 -0700161 private SpeakEasyCallManager speakEasyCallManager;
wangqifb0cfff2018-06-05 11:51:01 -0700162 private DialogFragment rttRequestDialogFragment;
Eric Erfanianccca3152017-02-22 16:32:36 -0800163
164 public static Intent getIntent(
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700165 Context context, boolean showDialpad, boolean newOutgoingCall, boolean isForFullScreen) {
Eric Erfanianccca3152017-02-22 16:32:36 -0800166 Intent intent = new Intent(Intent.ACTION_MAIN, null);
167 intent.setFlags(Intent.FLAG_ACTIVITY_NO_USER_ACTION | Intent.FLAG_ACTIVITY_NEW_TASK);
168 intent.setClass(context, InCallActivity.class);
linyuhc3968e62017-11-20 17:40:50 -0800169 if (showDialpad) {
170 intent.putExtra(IntentExtraNames.SHOW_DIALPAD, true);
171 }
172 intent.putExtra(IntentExtraNames.NEW_OUTGOING_CALL, newOutgoingCall);
173 intent.putExtra(IntentExtraNames.FOR_FULL_SCREEN, isForFullScreen);
Eric Erfanianccca3152017-02-22 16:32:36 -0800174 return intent;
175 }
176
177 @Override
178 protected void onResumeFragments() {
179 super.onResumeFragments();
180 if (needDismissPendingDialogs) {
181 dismissPendingDialogs();
182 }
183 }
184
185 @Override
linyuhc3968e62017-11-20 17:40:50 -0800186 protected void onCreate(Bundle bundle) {
Eric Erfanian2ca43182017-08-31 06:57:16 -0700187 Trace.beginSection("InCallActivity.onCreate");
linyuhc3968e62017-11-20 17:40:50 -0800188 super.onCreate(bundle);
Eric Erfanianccca3152017-02-22 16:32:36 -0800189
twyena1723252018-04-24 17:02:57 -0700190 preferredAccountWorkerResultListener =
191 DialerExecutorComponent.get(this)
192 .createUiListener(getFragmentManager(), "preferredAccountWorkerResultListener");
193
twyen73a74c32018-03-07 12:12:24 -0800194 selectPhoneAccountListener = new SelectPhoneAccountListener(getApplicationContext());
195
linyuhc3968e62017-11-20 17:40:50 -0800196 if (bundle != null) {
197 didShowAnswerScreen = bundle.getBoolean(KeysForSavedInstance.DID_SHOW_ANSWER_SCREEN);
198 didShowInCallScreen = bundle.getBoolean(KeysForSavedInstance.DID_SHOW_IN_CALL_SCREEN);
199 didShowVideoCallScreen = bundle.getBoolean(KeysForSavedInstance.DID_SHOW_VIDEO_CALL_SCREEN);
wangqi153af2f2018-02-15 16:21:49 -0800200 didShowRttCallScreen = bundle.getBoolean(KeysForSavedInstance.DID_SHOW_RTT_CALL_SCREEN);
wangqic46cfd22018-05-22 15:10:05 -0700201 didShowSpeakEasyScreen = bundle.getBoolean(KeysForSavedInstance.DID_SHOW_SPEAK_EASY_SCREEN);
Eric Erfanianccca3152017-02-22 16:32:36 -0800202 }
203
linyuhc3968e62017-11-20 17:40:50 -0800204 setWindowFlags();
205 setContentView(R.layout.incall_screen);
206 internalResolveIntent(getIntent());
207
208 boolean isLandscape =
209 getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE;
210 boolean isRtl = ViewUtil.isRtl();
211 if (isLandscape) {
212 dialpadSlideInAnimation =
213 AnimationUtils.loadAnimation(
214 this, isRtl ? R.anim.dialpad_slide_in_left : R.anim.dialpad_slide_in_right);
215 dialpadSlideOutAnimation =
216 AnimationUtils.loadAnimation(
217 this, isRtl ? R.anim.dialpad_slide_out_left : R.anim.dialpad_slide_out_right);
218 } else {
219 dialpadSlideInAnimation = AnimationUtils.loadAnimation(this, R.anim.dialpad_slide_in_bottom);
220 dialpadSlideOutAnimation =
221 AnimationUtils.loadAnimation(this, R.anim.dialpad_slide_out_bottom);
222 }
223 dialpadSlideInAnimation.setInterpolator(AnimUtils.EASE_IN);
224 dialpadSlideOutAnimation.setInterpolator(AnimUtils.EASE_OUT);
225 dialpadSlideOutAnimation.setAnimationListener(
226 new AnimationListenerAdapter() {
227 @Override
228 public void onAnimationEnd(Animation animation) {
229 hideDialpadFragment();
230 }
231 });
232
233 if (bundle != null && showDialpadRequest == DIALPAD_REQUEST_NONE) {
234 // If the dialpad was shown before, set related variables so that it can be shown and
235 // populated with the previous DTMF text during onResume().
236 if (bundle.containsKey(IntentExtraNames.SHOW_DIALPAD)) {
237 boolean showDialpad = bundle.getBoolean(IntentExtraNames.SHOW_DIALPAD);
238 showDialpadRequest = showDialpad ? DIALPAD_REQUEST_SHOW : DIALPAD_REQUEST_HIDE;
239 animateDialpadOnShow = false;
240 }
241 dtmfTextToPrepopulate = bundle.getString(KeysForSavedInstance.DIALPAD_TEXT);
242
243 SelectPhoneAccountDialogFragment selectPhoneAccountDialogFragment =
244 (SelectPhoneAccountDialogFragment)
245 getFragmentManager().findFragmentByTag(Tags.SELECT_ACCOUNT_FRAGMENT);
246 if (selectPhoneAccountDialogFragment != null) {
247 selectPhoneAccountDialogFragment.setListener(selectPhoneAccountListener);
248 }
249 }
250
linyuh69a25062017-11-15 16:18:51 -0800251 inCallOrientationEventListener = new InCallOrientationEventListener(this);
Eric Erfanianccca3152017-02-22 16:32:36 -0800252
253 getWindow()
254 .getDecorView()
255 .setSystemUiVisibility(
256 View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
257
258 pseudoBlackScreenOverlay = findViewById(R.id.psuedo_black_screen_overlay);
Eric Erfanian2ca43182017-08-31 06:57:16 -0700259 sendBroadcast(CallPendingActivity.getFinishBroadcast());
260 Trace.endSection();
zachh7a96dc72018-02-20 22:16:03 -0800261 MetricsComponent.get(this)
262 .metrics()
263 .stopTimer(Metrics.ON_CALL_ADDED_TO_ON_INCALL_UI_SHOWN_INCOMING);
264 MetricsComponent.get(this)
265 .metrics()
266 .stopTimer(Metrics.ON_CALL_ADDED_TO_ON_INCALL_UI_SHOWN_OUTGOING);
Eric Erfanianccca3152017-02-22 16:32:36 -0800267 }
268
linyuhc3968e62017-11-20 17:40:50 -0800269 private void setWindowFlags() {
270 // Allow the activity to be shown when the screen is locked and filter out touch events that are
271 // "too fat".
272 int flags =
273 WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
274 | WindowManager.LayoutParams.FLAG_IGNORE_CHEEK_PRESSES;
275
linyuhf79d1cb2017-12-15 17:49:56 -0800276 // When the audio stream is not via Bluetooth, turn on the screen once the activity is shown.
277 // When the audio stream is via Bluetooth, turn on the screen only for an incoming call.
linyuhc3968e62017-11-20 17:40:50 -0800278 final int audioRoute = getAudioRoute();
linyuhf79d1cb2017-12-15 17:49:56 -0800279 if (audioRoute != CallAudioState.ROUTE_BLUETOOTH
280 || CallList.getInstance().getIncomingCall() != null) {
linyuhc3968e62017-11-20 17:40:50 -0800281 flags |= WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON;
282 }
283
284 getWindow().addFlags(flags);
285 }
286
287 private static int getAudioRoute() {
288 if (audioRouteForTesting.isPresent()) {
289 return audioRouteForTesting.get();
290 }
291
292 return AudioModeProvider.getInstance().getAudioState().getRoute();
293 }
294
295 @VisibleForTesting(otherwise = VisibleForTesting.NONE)
296 public static void setAudioRouteForTesting(int audioRoute) {
297 audioRouteForTesting = Optional.of(audioRoute);
298 }
299
300 private void internalResolveIntent(Intent intent) {
301 if (!intent.getAction().equals(Intent.ACTION_MAIN)) {
302 return;
303 }
304
305 if (intent.hasExtra(IntentExtraNames.SHOW_DIALPAD)) {
306 // IntentExtraNames.SHOW_DIALPAD can be used to specify whether the DTMF dialpad should be
307 // initially visible. If the extra is absent, leave the dialpad in its previous state.
308 boolean showDialpad = intent.getBooleanExtra(IntentExtraNames.SHOW_DIALPAD, false);
309 relaunchedFromDialer(showDialpad);
310 }
311
312 DialerCall outgoingCall = CallList.getInstance().getOutgoingCall();
313 if (outgoingCall == null) {
314 outgoingCall = CallList.getInstance().getPendingOutgoingCall();
315 }
316 if (intent.getBooleanExtra(IntentExtraNames.NEW_OUTGOING_CALL, false)) {
317 intent.removeExtra(IntentExtraNames.NEW_OUTGOING_CALL);
318
319 // InCallActivity is responsible for disconnecting a new outgoing call if there is no way of
320 // making it (i.e. no valid call capable accounts).
linyuh122fb0b2018-03-26 13:35:32 -0700321 if (InCallPresenter.isCallWithNoValidAccounts(outgoingCall)) {
linyuhc3968e62017-11-20 17:40:50 -0800322 LogUtil.i(
323 "InCallActivity.internalResolveIntent", "Call with no valid accounts, disconnecting");
324 outgoingCall.disconnect();
325 }
326
327 dismissKeyguard(true);
328 }
329
330 if (showPhoneAccountSelectionDialog()) {
331 hideMainInCallFragment();
332 }
333 }
334
335 /**
336 * When relaunching from the dialer app, {@code showDialpad} indicates whether the dialpad should
337 * be shown on launch.
338 *
339 * @param showDialpad {@code true} to indicate the dialpad should be shown on launch, and {@code
340 * false} to indicate no change should be made to the dialpad visibility.
341 */
342 private void relaunchedFromDialer(boolean showDialpad) {
343 showDialpadRequest = showDialpad ? DIALPAD_REQUEST_SHOW : DIALPAD_REQUEST_NONE;
344 animateDialpadOnShow = true;
345
346 if (showDialpadRequest == DIALPAD_REQUEST_SHOW) {
347 // If there's only one line in use, AND it's on hold, then we're sure the user
348 // wants to use the dialpad toward the exact line, so un-hold the holding line.
349 DialerCall call = CallList.getInstance().getActiveOrBackgroundCall();
wangqibb94ca62018-04-27 14:34:04 -0700350 if (call != null && call.getState() == DialerCallState.ONHOLD) {
linyuhc3968e62017-11-20 17:40:50 -0800351 call.unhold();
352 }
353 }
354 }
355
356 /**
357 * Show a phone account selection dialog if there is a call waiting for phone account selection.
358 *
359 * @return true if the dialog was shown.
360 */
361 private boolean showPhoneAccountSelectionDialog() {
362 DialerCall waitingForAccountCall = CallList.getInstance().getWaitingForAccountCall();
363 if (waitingForAccountCall == null) {
364 return false;
365 }
366
twyen56f79ba2018-04-30 14:25:46 -0700367 PreferredAccountWorker preferredAccountWorker =
368 PreferredSimComponent.get(this).preferredAccountWorker();
linyuhc3968e62017-11-20 17:40:50 -0800369
twyen56f79ba2018-04-30 14:25:46 -0700370 Bundle extras = waitingForAccountCall.getIntentExtras();
371 List<PhoneAccountHandle> phoneAccountHandles =
372 extras == null
373 ? new ArrayList<>()
374 : extras.getParcelableArrayList(Call.AVAILABLE_PHONE_ACCOUNTS);
375
376 ListenableFuture<PreferredAccountWorker.Result> preferredAccountFuture =
377 preferredAccountWorker.selectAccount(
378 waitingForAccountCall.getNumber(), phoneAccountHandles);
twyena1723252018-04-24 17:02:57 -0700379 preferredAccountWorkerResultListener.listen(
380 this,
381 preferredAccountFuture,
382 result -> {
twyen56f79ba2018-04-30 14:25:46 -0700383 String callId = waitingForAccountCall.getId();
384 if (result.getSelectedPhoneAccountHandle().isPresent()) {
twyena1723252018-04-24 17:02:57 -0700385 selectPhoneAccountListener.onPhoneAccountSelected(
twyen56f79ba2018-04-30 14:25:46 -0700386 result.getSelectedPhoneAccountHandle().get(), false, callId);
twyena1723252018-04-24 17:02:57 -0700387 return;
388 }
twyen66adad02018-04-24 13:51:08 -0700389
linyuhf62092d2018-06-07 11:03:48 -0700390 if (!isVisible()) {
391 LogUtil.i(
392 "InCallActivity.showPhoneAccountSelectionDialog",
393 "activity ended before result returned");
394 return;
395 }
396
twyena1723252018-04-24 17:02:57 -0700397 waitingForAccountCall.setPreferredAccountRecorder(
398 new PreferredAccountRecorder(
399 waitingForAccountCall.getNumber(),
400 result.getSuggestion().orNull(),
401 result.getDataId().orNull()));
twyena1723252018-04-24 17:02:57 -0700402 selectPhoneAccountDialogFragment =
403 SelectPhoneAccountDialogFragment.newInstance(
twyen56f79ba2018-04-30 14:25:46 -0700404 result.getDialogOptionsBuilder().get().setCallId(callId).build(),
405 selectPhoneAccountListener);
twyena1723252018-04-24 17:02:57 -0700406 selectPhoneAccountDialogFragment.show(getFragmentManager(), Tags.SELECT_ACCOUNT_FRAGMENT);
407 },
408 throwable -> {
409 throw new RuntimeException(throwable);
410 });
twyen73a74c32018-03-07 12:12:24 -0800411
linyuhc3968e62017-11-20 17:40:50 -0800412 return true;
413 }
414
Eric Erfanianccca3152017-02-22 16:32:36 -0800415 @Override
416 protected void onSaveInstanceState(Bundle out) {
linyuh57b093b2017-11-17 14:32:32 -0800417 LogUtil.enterBlock("InCallActivity.onSaveInstanceState");
418
419 // TODO: DialpadFragment should handle this as part of its own state
linyuhc3968e62017-11-20 17:40:50 -0800420 out.putBoolean(IntentExtraNames.SHOW_DIALPAD, isDialpadVisible());
linyuh57b093b2017-11-17 14:32:32 -0800421 DialpadFragment dialpadFragment = getDialpadFragment();
422 if (dialpadFragment != null) {
linyuhc3968e62017-11-20 17:40:50 -0800423 out.putString(KeysForSavedInstance.DIALPAD_TEXT, dialpadFragment.getDtmfText());
linyuh57b093b2017-11-17 14:32:32 -0800424 }
425
linyuhc3968e62017-11-20 17:40:50 -0800426 out.putBoolean(KeysForSavedInstance.DID_SHOW_ANSWER_SCREEN, didShowAnswerScreen);
427 out.putBoolean(KeysForSavedInstance.DID_SHOW_IN_CALL_SCREEN, didShowInCallScreen);
428 out.putBoolean(KeysForSavedInstance.DID_SHOW_VIDEO_CALL_SCREEN, didShowVideoCallScreen);
wangqi153af2f2018-02-15 16:21:49 -0800429 out.putBoolean(KeysForSavedInstance.DID_SHOW_RTT_CALL_SCREEN, didShowRttCallScreen);
erfaniand05d8992018-03-20 19:42:26 -0700430 out.putBoolean(KeysForSavedInstance.DID_SHOW_SPEAK_EASY_SCREEN, didShowSpeakEasyScreen);
linyuh57b093b2017-11-17 14:32:32 -0800431
Eric Erfanianccca3152017-02-22 16:32:36 -0800432 super.onSaveInstanceState(out);
433 isVisible = false;
434 }
435
436 @Override
437 protected void onStart() {
Eric Erfanian2ca43182017-08-31 06:57:16 -0700438 Trace.beginSection("InCallActivity.onStart");
Eric Erfanianccca3152017-02-22 16:32:36 -0800439 super.onStart();
linyuh57b093b2017-11-17 14:32:32 -0800440
Eric Erfanianccca3152017-02-22 16:32:36 -0800441 isVisible = true;
442 showMainInCallFragment();
linyuh57b093b2017-11-17 14:32:32 -0800443
444 InCallPresenter.getInstance().setActivity(this);
445 enableInCallOrientationEventListener(
446 getRequestedOrientation()
447 == InCallOrientationEventListener.ACTIVITY_PREFERENCE_ALLOW_ROTATION);
448 InCallPresenter.getInstance().onActivityStarted();
449
yueg10f6e822018-01-17 15:32:18 -0800450 if (!isRecreating) {
451 InCallPresenter.getInstance().onUiShowing(true);
452 }
453
linyuh437ae952018-03-26 12:46:18 -0700454 if (isInMultiWindowMode() && !getResources().getBoolean(R.bool.incall_dialpad_allowed)) {
Eric Erfanianccca3152017-02-22 16:32:36 -0800455 // Hide the dialpad because there may not be enough room
456 showDialpadFragment(false, false);
457 }
linyuh57b093b2017-11-17 14:32:32 -0800458
Eric Erfanian2ca43182017-08-31 06:57:16 -0700459 Trace.endSection();
Eric Erfanianccca3152017-02-22 16:32:36 -0800460 }
461
462 @Override
463 protected void onResume() {
Eric Erfanian2ca43182017-08-31 06:57:16 -0700464 Trace.beginSection("InCallActivity.onResume");
Eric Erfanianccca3152017-02-22 16:32:36 -0800465 super.onResume();
linyuhc3968e62017-11-20 17:40:50 -0800466
467 if (!InCallPresenter.getInstance().isReadyForTearDown()) {
468 updateTaskDescription();
linyuhc3968e62017-11-20 17:40:50 -0800469 }
470
471 // If there is a pending request to show or hide the dialpad, handle that now.
472 if (showDialpadRequest != DIALPAD_REQUEST_NONE) {
473 if (showDialpadRequest == DIALPAD_REQUEST_SHOW) {
474 // Exit fullscreen so that the user has access to the dialpad hide/show button.
475 // This is important when showing the dialpad from within dialer.
476 InCallPresenter.getInstance().setFullScreen(false /* isFullScreen */, true /* force */);
477
478 showDialpadFragment(true /* show */, animateDialpadOnShow /* animate */);
479 animateDialpadOnShow = false;
480
481 DialpadFragment dialpadFragment = getDialpadFragment();
482 if (dialpadFragment != null) {
483 dialpadFragment.setDtmfText(dtmfTextToPrepopulate);
484 dtmfTextToPrepopulate = null;
485 }
486 } else {
487 LogUtil.i("InCallActivity.onResume", "Force-hide the dialpad");
488 if (getDialpadFragment() != null) {
489 showDialpadFragment(false /* show */, false /* animate */);
490 }
491 }
492 showDialpadRequest = DIALPAD_REQUEST_NONE;
493 }
linyuhc3968e62017-11-20 17:40:50 -0800494
linyuhc3968e62017-11-20 17:40:50 -0800495 CallList.getInstance()
496 .onInCallUiShown(getIntent().getBooleanExtra(IntentExtraNames.FOR_FULL_SCREEN, false));
497
Eric Erfanianccca3152017-02-22 16:32:36 -0800498 PseudoScreenState pseudoScreenState = InCallPresenter.getInstance().getPseudoScreenState();
499 pseudoScreenState.addListener(this);
500 onPseudoScreenStateChanged(pseudoScreenState.isOn());
Eric Erfanian2ca43182017-08-31 06:57:16 -0700501 Trace.endSection();
weijiaxu650e7cc2017-10-31 12:38:54 -0700502 // add 1 sec delay to get memory snapshot so that dialer wont react slowly on resume.
503 ThreadUtil.postDelayedOnUiThread(
weijiaxuc950a9b2017-11-06 16:39:04 -0800504 () ->
zachh7a96dc72018-02-20 22:16:03 -0800505 MetricsComponent.get(this)
506 .metrics()
507 .recordMemory(Metrics.INCALL_ACTIVITY_ON_RESUME_MEMORY_EVENT_NAME),
weijiaxu650e7cc2017-10-31 12:38:54 -0700508 1000);
Eric Erfanianccca3152017-02-22 16:32:36 -0800509 }
510
Eric Erfanianccca3152017-02-22 16:32:36 -0800511 @Override
512 protected void onPause() {
Eric Erfanian2ca43182017-08-31 06:57:16 -0700513 Trace.beginSection("InCallActivity.onPause");
Eric Erfanianccca3152017-02-22 16:32:36 -0800514 super.onPause();
linyuh57b093b2017-11-17 14:32:32 -0800515
516 DialpadFragment dialpadFragment = getDialpadFragment();
517 if (dialpadFragment != null) {
518 dialpadFragment.onDialerKeyUp(null);
519 }
520
Eric Erfanianccca3152017-02-22 16:32:36 -0800521 InCallPresenter.getInstance().getPseudoScreenState().removeListener(this);
Eric Erfanian2ca43182017-08-31 06:57:16 -0700522 Trace.endSection();
Eric Erfanianccca3152017-02-22 16:32:36 -0800523 }
524
525 @Override
526 protected void onStop() {
Eric Erfanian2ca43182017-08-31 06:57:16 -0700527 Trace.beginSection("InCallActivity.onStop");
wangqi4d705e52017-09-28 12:23:35 -0700528 isVisible = false;
Eric Erfanianccca3152017-02-22 16:32:36 -0800529 super.onStop();
linyuh57b093b2017-11-17 14:32:32 -0800530
531 // Disconnects the call waiting for a phone account when the activity is hidden (e.g., after the
532 // user presses the home button).
533 // Without this the pending call will get stuck on phone account selection and new calls can't
534 // be created.
535 // Skip this when the screen is locked since the activity may complete its current life cycle
536 // and restart.
linyuhc3968e62017-11-20 17:40:50 -0800537 if (!isRecreating && !getSystemService(KeyguardManager.class).isKeyguardLocked()) {
linyuh57b093b2017-11-17 14:32:32 -0800538 DialerCall waitingForAccountCall = CallList.getInstance().getWaitingForAccountCall();
539 if (waitingForAccountCall != null) {
540 waitingForAccountCall.disconnect();
541 }
542 }
543
544 enableInCallOrientationEventListener(false);
545 InCallPresenter.getInstance().updateIsChangingConfigurations();
546 InCallPresenter.getInstance().onActivityStopped();
linyuhc3968e62017-11-20 17:40:50 -0800547 if (!isRecreating) {
yueg10f6e822018-01-17 15:32:18 -0800548 InCallPresenter.getInstance().onUiShowing(false);
wangqie6060522018-04-05 11:47:15 -0700549 }
550 if (errorDialog != null) {
551 errorDialog.dismiss();
linyuh57b093b2017-11-17 14:32:32 -0800552 }
553
yueg10f6e822018-01-17 15:32:18 -0800554 if (isFinishing()) {
555 InCallPresenter.getInstance().unsetActivity(this);
556 }
557
Eric Erfanian2ca43182017-08-31 06:57:16 -0700558 Trace.endSection();
Eric Erfanianccca3152017-02-22 16:32:36 -0800559 }
560
561 @Override
562 protected void onDestroy() {
Eric Erfanian2ca43182017-08-31 06:57:16 -0700563 Trace.beginSection("InCallActivity.onDestroy");
Eric Erfanianccca3152017-02-22 16:32:36 -0800564 super.onDestroy();
linyuh57b093b2017-11-17 14:32:32 -0800565
566 InCallPresenter.getInstance().unsetActivity(this);
567 InCallPresenter.getInstance().updateIsChangingConfigurations();
Eric Erfanian2ca43182017-08-31 06:57:16 -0700568 Trace.endSection();
Eric Erfanianccca3152017-02-22 16:32:36 -0800569 }
570
571 @Override
572 public void finish() {
573 if (shouldCloseActivityOnFinish()) {
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700574 // When user select incall ui from recents after the call is disconnected, it tries to launch
575 // a new InCallActivity but InCallPresenter is already teared down at this point, which causes
576 // crash.
577 // By calling finishAndRemoveTask() instead of finish() the task associated with
578 // InCallActivity is cleared completely. So system won't try to create a new InCallActivity in
579 // this case.
580 //
581 // Calling finish won't clear the task and normally when an activity finishes it shouldn't
582 // clear the task since there could be parent activity in the same task that's still alive.
583 // But InCallActivity is special since it's singleInstance which means it's root activity and
584 // only instance of activity in the task. So it should be safe to also remove task when
585 // finishing.
586 // It's also necessary in the sense of it's excluded from recents. So whenever the activity
587 // finishes, the task should also be removed since it doesn't make sense to go back to it in
588 // anyway anymore.
589 super.finishAndRemoveTask();
Eric Erfanianccca3152017-02-22 16:32:36 -0800590 }
591 }
592
593 private boolean shouldCloseActivityOnFinish() {
linyuhc3968e62017-11-20 17:40:50 -0800594 if (!isVisible) {
Eric Erfanianccca3152017-02-22 16:32:36 -0800595 LogUtil.i(
596 "InCallActivity.shouldCloseActivityOnFinish",
597 "allowing activity to be closed because it's not visible");
598 return true;
599 }
600
twyen8efb4952017-10-06 16:35:54 -0700601 if (InCallPresenter.getInstance().isInCallUiLocked()) {
Eric Erfanianccca3152017-02-22 16:32:36 -0800602 LogUtil.i(
603 "InCallActivity.shouldCloseActivityOnFinish",
twyen8efb4952017-10-06 16:35:54 -0700604 "in call ui is locked, not closing activity");
Eric Erfanianccca3152017-02-22 16:32:36 -0800605 return false;
606 }
607
608 LogUtil.i(
609 "InCallActivity.shouldCloseActivityOnFinish",
twyen8efb4952017-10-06 16:35:54 -0700610 "activity is visible and has no locks, allowing activity to close");
Eric Erfanianccca3152017-02-22 16:32:36 -0800611 return true;
612 }
613
614 @Override
615 protected void onNewIntent(Intent intent) {
linyuhc3968e62017-11-20 17:40:50 -0800616 LogUtil.enterBlock("InCallActivity.onNewIntent");
Eric Erfanianccca3152017-02-22 16:32:36 -0800617
618 // If the screen is off, we need to make sure it gets turned on for incoming calls.
619 // This normally works just fine thanks to FLAG_TURN_SCREEN_ON but that only works
620 // when the activity is first created. Therefore, to ensure the screen is turned on
621 // for the call waiting case, we recreate() the current activity. There should be no jank from
622 // this since the screen is already off and will remain so until our new activity is up.
linyuhc3968e62017-11-20 17:40:50 -0800623 if (!isVisible) {
624 onNewIntent(intent, true /* isRecreating */);
Eric Erfanianccca3152017-02-22 16:32:36 -0800625 LogUtil.i("InCallActivity.onNewIntent", "Restarting InCallActivity to force screen on.");
626 recreate();
Eric Erfanian10b34a52017-05-04 08:23:17 -0700627 } else {
linyuhc3968e62017-11-20 17:40:50 -0800628 onNewIntent(intent, false /* isRecreating */);
629 }
630 }
631
yuega3305352018-01-09 11:02:47 -0800632 @VisibleForTesting
633 void onNewIntent(Intent intent, boolean isRecreating) {
linyuhc3968e62017-11-20 17:40:50 -0800634 this.isRecreating = isRecreating;
635
636 // We're being re-launched with a new Intent. Since it's possible for a single InCallActivity
637 // instance to persist indefinitely (even if we finish() ourselves), this sequence can
638 // happen any time the InCallActivity needs to be displayed.
639
640 // Stash away the new intent so that we can get it in the future by calling getIntent().
641 // Otherwise getIntent() will return the original Intent from when we first got created.
642 setIntent(intent);
643
644 // Activities are always paused before receiving a new intent, so we can count on our onResume()
645 // method being called next.
646
647 // Just like in onCreate(), handle the intent.
648 // Skip if InCallActivity is going to be recreated since this will be called in onCreate().
649 if (!isRecreating) {
650 internalResolveIntent(intent);
Eric Erfanianccca3152017-02-22 16:32:36 -0800651 }
652 }
653
654 @Override
655 public void onBackPressed() {
linyuh57b093b2017-11-17 14:32:32 -0800656 LogUtil.enterBlock("InCallActivity.onBackPressed");
657
linyuhc3968e62017-11-20 17:40:50 -0800658 if (!isVisible) {
linyuh57b093b2017-11-17 14:32:32 -0800659 return;
Eric Erfanianccca3152017-02-22 16:32:36 -0800660 }
linyuh57b093b2017-11-17 14:32:32 -0800661
662 if (!getCallCardFragmentVisible()) {
663 return;
664 }
665
666 DialpadFragment dialpadFragment = getDialpadFragment();
667 if (dialpadFragment != null && dialpadFragment.isVisible()) {
668 showDialpadFragment(false /* show */, true /* animate */);
669 return;
670 }
671
672 if (CallList.getInstance().getIncomingCall() != null) {
673 LogUtil.i(
674 "InCallActivity.onBackPressed",
675 "Ignore the press of the back key when an incoming call is ringing");
676 return;
677 }
678
679 // Nothing special to do. Fall back to the default behavior.
680 super.onBackPressed();
Eric Erfanianccca3152017-02-22 16:32:36 -0800681 }
682
683 @Override
684 public boolean onOptionsItemSelected(MenuItem item) {
685 LogUtil.i("InCallActivity.onOptionsItemSelected", "item: " + item);
686 if (item.getItemId() == android.R.id.home) {
687 onBackPressed();
688 return true;
689 }
690 return super.onOptionsItemSelected(item);
691 }
692
693 @Override
694 public boolean onKeyUp(int keyCode, KeyEvent event) {
linyuh57b093b2017-11-17 14:32:32 -0800695 DialpadFragment dialpadFragment = getDialpadFragment();
696 if (dialpadFragment != null
697 && dialpadFragment.isVisible()
698 && dialpadFragment.onDialerKeyUp(event)) {
699 return true;
700 }
701
702 if (keyCode == KeyEvent.KEYCODE_CALL) {
703 // Always consume KEYCODE_CALL to ensure the PhoneWindow won't do anything with it.
704 return true;
705 }
706
707 return super.onKeyUp(keyCode, event);
Eric Erfanianccca3152017-02-22 16:32:36 -0800708 }
709
710 @Override
711 public boolean onKeyDown(int keyCode, KeyEvent event) {
linyuh57b093b2017-11-17 14:32:32 -0800712 switch (keyCode) {
713 case KeyEvent.KEYCODE_CALL:
714 if (!InCallPresenter.getInstance().handleCallKey()) {
715 LogUtil.e(
716 "InCallActivity.onKeyDown",
717 "InCallPresenter should always handle KEYCODE_CALL in onKeyDown");
718 }
719 // Always consume KEYCODE_CALL to ensure the PhoneWindow won't do anything with it.
720 return true;
721
722 // Note that KEYCODE_ENDCALL isn't handled here as the standard system-wide handling of it
723 // is exactly what's needed, namely
724 // (1) "hang up" if there's an active call, or
725 // (2) "don't answer" if there's an incoming call.
726 // (See PhoneWindowManager for implementation details.)
727
728 case KeyEvent.KEYCODE_CAMERA:
729 // Consume KEYCODE_CAMERA since it's easy to accidentally press the camera button.
730 return true;
731
732 case KeyEvent.KEYCODE_VOLUME_UP:
733 case KeyEvent.KEYCODE_VOLUME_DOWN:
734 case KeyEvent.KEYCODE_VOLUME_MUTE:
735 // Ringer silencing handled by PhoneWindowManager.
736 break;
737
738 case KeyEvent.KEYCODE_MUTE:
739 TelecomAdapter.getInstance()
740 .mute(!AudioModeProvider.getInstance().getAudioState().isMuted());
741 return true;
742
743 case KeyEvent.KEYCODE_SLASH:
744 // When verbose logging is enabled, dump the view for debugging/testing purposes.
745 if (LogUtil.isVerboseEnabled()) {
746 View decorView = getWindow().getDecorView();
747 LogUtil.v("InCallActivity.onKeyDown", "View dump:\n%s", decorView);
748 return true;
749 }
750 break;
751
752 case KeyEvent.KEYCODE_EQUALS:
753 break;
754
755 default: // fall out
756 }
757
758 // Pass other key events to DialpadFragment's "onDialerKeyDown" method in case the user types
759 // in DTMF (Dual-tone multi-frequency signaling) code.
760 DialpadFragment dialpadFragment = getDialpadFragment();
761 if (dialpadFragment != null
762 && dialpadFragment.isVisible()
763 && dialpadFragment.onDialerKeyDown(event)) {
764 return true;
765 }
766
767 return super.onKeyDown(keyCode, event);
Eric Erfanianccca3152017-02-22 16:32:36 -0800768 }
769
770 public boolean isInCallScreenAnimating() {
771 return false;
772 }
773
774 public void showConferenceFragment(boolean show) {
775 if (show) {
776 startActivity(new Intent(this, ManageConferenceActivity.class));
777 }
778 }
779
linyuhc3968e62017-11-20 17:40:50 -0800780 public void showDialpadFragment(boolean show, boolean animate) {
781 if (show == isDialpadVisible()) {
782 return;
Eric Erfanianccca3152017-02-22 16:32:36 -0800783 }
linyuhc3968e62017-11-20 17:40:50 -0800784
785 FragmentManager dialpadFragmentManager = getDialpadFragmentManager();
786 if (dialpadFragmentManager == null) {
787 LogUtil.i("InCallActivity.showDialpadFragment", "Unable to obtain a FragmentManager");
788 return;
789 }
790
791 if (!animate) {
792 if (show) {
793 showDialpadFragment();
794 } else {
795 hideDialpadFragment();
796 }
797 } else {
798 if (show) {
799 showDialpadFragment();
800 getDialpadFragment().animateShowDialpad();
801 }
802 getDialpadFragment()
803 .getView()
804 .startAnimation(show ? dialpadSlideInAnimation : dialpadSlideOutAnimation);
805 }
806
807 ProximitySensor sensor = InCallPresenter.getInstance().getProximitySensor();
808 if (sensor != null) {
809 sensor.onDialpadVisible(show);
810 }
811 showDialpadRequest = DIALPAD_REQUEST_NONE;
linyuhc3968e62017-11-20 17:40:50 -0800812 }
813
814 private void showDialpadFragment() {
815 FragmentManager dialpadFragmentManager = getDialpadFragmentManager();
816 if (dialpadFragmentManager == null) {
817 return;
818 }
819
820 FragmentTransaction transaction = dialpadFragmentManager.beginTransaction();
821 DialpadFragment dialpadFragment = getDialpadFragment();
822 if (dialpadFragment == null) {
wangqifd4c9f72018-03-08 18:21:50 -0800823 dialpadFragment = new DialpadFragment();
824 transaction.add(getDialpadContainerId(), dialpadFragment, Tags.DIALPAD_FRAGMENT);
linyuhc3968e62017-11-20 17:40:50 -0800825 } else {
826 transaction.show(dialpadFragment);
calderwoodrad5883872017-12-12 15:29:12 -0800827 dialpadFragment.setUserVisibleHint(true);
linyuhc3968e62017-11-20 17:40:50 -0800828 }
wangqifd4c9f72018-03-08 18:21:50 -0800829 // RTT call screen doesn't show end call button inside dialpad, thus the space reserved for end
830 // call button should be removed.
831 dialpadFragment.setShouldShowEndCallSpace(didShowInCallScreen);
linyuhc3968e62017-11-20 17:40:50 -0800832 transaction.commitAllowingStateLoss();
833 dialpadFragmentManager.executePendingTransactions();
834
835 Logger.get(this).logScreenView(ScreenEvent.Type.INCALL_DIALPAD, this);
wangqi73ed6132018-05-21 15:57:36 -0700836 getInCallOrRttCallScreen().onInCallScreenDialpadVisibilityChange(true);
linyuhc3968e62017-11-20 17:40:50 -0800837 }
838
839 private void hideDialpadFragment() {
840 FragmentManager dialpadFragmentManager = getDialpadFragmentManager();
841 if (dialpadFragmentManager == null) {
842 return;
843 }
844
calderwoodrad5883872017-12-12 15:29:12 -0800845 DialpadFragment dialpadFragment = getDialpadFragment();
linyuhc3968e62017-11-20 17:40:50 -0800846 if (dialpadFragment != null) {
847 FragmentTransaction transaction = dialpadFragmentManager.beginTransaction();
848 transaction.hide(dialpadFragment);
849 transaction.commitAllowingStateLoss();
850 dialpadFragmentManager.executePendingTransactions();
calderwoodrad5883872017-12-12 15:29:12 -0800851 dialpadFragment.setUserVisibleHint(false);
wangqi73ed6132018-05-21 15:57:36 -0700852 getInCallOrRttCallScreen().onInCallScreenDialpadVisibilityChange(false);
linyuhc3968e62017-11-20 17:40:50 -0800853 }
Eric Erfanianccca3152017-02-22 16:32:36 -0800854 }
855
856 public boolean isDialpadVisible() {
linyuh69a25062017-11-15 16:18:51 -0800857 DialpadFragment dialpadFragment = getDialpadFragment();
calderwoodraa584bcd2018-01-24 12:19:56 -0800858 return dialpadFragment != null
859 && dialpadFragment.isAdded()
860 && !dialpadFragment.isHidden()
861 && dialpadFragment.getView() != null
862 && dialpadFragment.getUserVisibleHint();
linyuh69a25062017-11-15 16:18:51 -0800863 }
864
linyuhc3968e62017-11-20 17:40:50 -0800865 /** Returns the {@link DialpadFragment} that's shown by this activity, or {@code null} */
linyuh69a25062017-11-15 16:18:51 -0800866 @Nullable
linyuhc3968e62017-11-20 17:40:50 -0800867 private DialpadFragment getDialpadFragment() {
linyuh69a25062017-11-15 16:18:51 -0800868 FragmentManager fragmentManager = getDialpadFragmentManager();
869 if (fragmentManager == null) {
870 return null;
871 }
linyuhc3968e62017-11-20 17:40:50 -0800872 return (DialpadFragment) fragmentManager.findFragmentByTag(Tags.DIALPAD_FRAGMENT);
Eric Erfanianccca3152017-02-22 16:32:36 -0800873 }
874
875 public void onForegroundCallChanged(DialerCall newForegroundCall) {
linyuh57b093b2017-11-17 14:32:32 -0800876 updateTaskDescription();
Eric Erfanian4ca9e8d2018-07-10 18:37:03 +0000877
878 if (newForegroundCall == null || !didShowAnswerScreen) {
879 LogUtil.v("InCallActivity.onForegroundCallChanged", "resetting background color");
880 updateWindowBackgroundColor(0 /* progress */);
881 }
Eric Erfanianccca3152017-02-22 16:32:36 -0800882 }
883
linyuhc3968e62017-11-20 17:40:50 -0800884 private void updateTaskDescription() {
linyuh57b093b2017-11-17 14:32:32 -0800885 int color =
886 getResources().getBoolean(R.bool.is_layout_landscape)
887 ? ResourcesCompat.getColor(
888 getResources(), R.color.statusbar_background_color, getTheme())
889 : InCallPresenter.getInstance().getThemeColorManager().getSecondaryColor();
890 setTaskDescription(
891 new TaskDescription(
892 getResources().getString(R.string.notification_ongoing_call), null /* icon */, color));
893 }
894
Eric Erfanian4ca9e8d2018-07-10 18:37:03 +0000895 public void updateWindowBackgroundColor(@FloatRange(from = -1f, to = 1.0f) float progress) {
896 ThemeColorManager themeColorManager = InCallPresenter.getInstance().getThemeColorManager();
897 @ColorInt int top;
898 @ColorInt int middle;
899 @ColorInt int bottom;
900 @ColorInt int gray = 0x66000000;
901
902 if (isInMultiWindowMode()) {
903 top = themeColorManager.getBackgroundColorSolid();
904 middle = themeColorManager.getBackgroundColorSolid();
905 bottom = themeColorManager.getBackgroundColorSolid();
906 } else {
907 top = themeColorManager.getBackgroundColorTop();
908 middle = themeColorManager.getBackgroundColorMiddle();
909 bottom = themeColorManager.getBackgroundColorBottom();
910 }
911
912 if (progress < 0) {
913 float correctedProgress = Math.abs(progress);
914 top = ColorUtils.blendARGB(top, gray, correctedProgress);
915 middle = ColorUtils.blendARGB(middle, gray, correctedProgress);
916 bottom = ColorUtils.blendARGB(bottom, gray, correctedProgress);
917 }
918
919 boolean backgroundDirty = false;
920 if (backgroundDrawable == null) {
921 backgroundDrawableColors = new int[] {top, middle, bottom};
922 backgroundDrawable = new GradientDrawable(Orientation.TOP_BOTTOM, backgroundDrawableColors);
923 backgroundDirty = true;
924 } else {
925 if (backgroundDrawableColors[0] != top) {
926 backgroundDrawableColors[0] = top;
927 backgroundDirty = true;
928 }
929 if (backgroundDrawableColors[1] != middle) {
930 backgroundDrawableColors[1] = middle;
931 backgroundDirty = true;
932 }
933 if (backgroundDrawableColors[2] != bottom) {
934 backgroundDrawableColors[2] = bottom;
935 backgroundDirty = true;
936 }
937 if (backgroundDirty) {
938 backgroundDrawable.setColors(backgroundDrawableColors);
939 }
940 }
941
942 if (backgroundDirty) {
943 getWindow().setBackgroundDrawable(backgroundDrawable);
944 }
945 }
946
Eric Erfanianccca3152017-02-22 16:32:36 -0800947 public boolean isVisible() {
948 return isVisible;
949 }
950
951 public boolean getCallCardFragmentVisible() {
erfaniand05d8992018-03-20 19:42:26 -0700952 return didShowInCallScreen
953 || didShowVideoCallScreen
954 || didShowRttCallScreen
955 || didShowSpeakEasyScreen;
Eric Erfanianccca3152017-02-22 16:32:36 -0800956 }
957
958 public void dismissKeyguard(boolean dismiss) {
linyuh9c327da2017-11-14 12:33:48 -0800959 if (dismissKeyguard == dismiss) {
960 return;
961 }
962
963 dismissKeyguard = dismiss;
964 if (dismiss) {
965 getWindow().addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);
966 } else {
967 getWindow().clearFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);
968 }
Eric Erfanianccca3152017-02-22 16:32:36 -0800969 }
970
linyuhc3968e62017-11-20 17:40:50 -0800971 public void showDialogForPostCharWait(String callId, String chars) {
yuega489f512018-04-25 12:01:09 -0700972 PostCharDialogFragment fragment = new PostCharDialogFragment(callId, chars);
973 fragment.show(getSupportFragmentManager(), Tags.POST_CHAR_DIALOG_FRAGMENT);
Eric Erfanianccca3152017-02-22 16:32:36 -0800974 }
975
linyuh7b86f562017-11-16 11:24:09 -0800976 public void showDialogOrToastForDisconnectedCall(DisconnectMessage disconnectMessage) {
977 LogUtil.i(
978 "InCallActivity.showDialogOrToastForDisconnectedCall",
979 "disconnect cause: %s",
980 disconnectMessage);
981
982 if (disconnectMessage.dialog == null || isFinishing()) {
983 return;
984 }
985
986 dismissPendingDialogs();
987
988 // Show a toast if the app is in background when a dialog can't be visible.
989 if (!isVisible()) {
990 Toast.makeText(getApplicationContext(), disconnectMessage.toastMessage, Toast.LENGTH_LONG)
991 .show();
992 return;
993 }
994
995 // Show the dialog.
linyuhc3968e62017-11-20 17:40:50 -0800996 errorDialog = disconnectMessage.dialog;
linyuh7b86f562017-11-16 11:24:09 -0800997 InCallUiLock lock = InCallPresenter.getInstance().acquireInCallUiLock("showErrorDialog");
998 disconnectMessage.dialog.setOnDismissListener(
999 dialogInterface -> {
1000 lock.release();
1001 onDialogDismissed();
1002 });
1003 disconnectMessage.dialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
1004 disconnectMessage.dialog.show();
1005 }
1006
1007 private void onDialogDismissed() {
linyuhc3968e62017-11-20 17:40:50 -08001008 errorDialog = null;
linyuh7b86f562017-11-16 11:24:09 -08001009 CallList.getInstance().onErrorDialogDismissed();
Eric Erfanianccca3152017-02-22 16:32:36 -08001010 }
1011
1012 public void dismissPendingDialogs() {
linyuhc3968e62017-11-20 17:40:50 -08001013 LogUtil.enterBlock("InCallActivity.dismissPendingDialogs");
linyuhf99f6302017-11-15 11:23:51 -08001014
1015 if (!isVisible) {
1016 // Defer the dismissing action as the activity is not visible and onSaveInstanceState may have
1017 // been called.
Eric Erfanianccca3152017-02-22 16:32:36 -08001018 LogUtil.i(
1019 "InCallActivity.dismissPendingDialogs", "defer actions since activity is not visible");
1020 needDismissPendingDialogs = true;
linyuhf99f6302017-11-15 11:23:51 -08001021 return;
Eric Erfanianccca3152017-02-22 16:32:36 -08001022 }
linyuhf99f6302017-11-15 11:23:51 -08001023
1024 // Dismiss the error dialog
linyuhf99f6302017-11-15 11:23:51 -08001025 if (errorDialog != null) {
1026 errorDialog.dismiss();
linyuhc3968e62017-11-20 17:40:50 -08001027 errorDialog = null;
linyuhf99f6302017-11-15 11:23:51 -08001028 }
1029
1030 // Dismiss the phone account selection dialog
linyuhf99f6302017-11-15 11:23:51 -08001031 if (selectPhoneAccountDialogFragment != null) {
1032 selectPhoneAccountDialogFragment.dismiss();
linyuhc3968e62017-11-20 17:40:50 -08001033 selectPhoneAccountDialogFragment = null;
linyuhf99f6302017-11-15 11:23:51 -08001034 }
1035
1036 // Dismiss the dialog for international call on WiFi
1037 InternationalCallOnWifiDialogFragment internationalCallOnWifiFragment =
1038 (InternationalCallOnWifiDialogFragment)
linyuhc3968e62017-11-20 17:40:50 -08001039 getSupportFragmentManager().findFragmentByTag(Tags.INTERNATIONAL_CALL_ON_WIFI);
linyuhf99f6302017-11-15 11:23:51 -08001040 if (internationalCallOnWifiFragment != null) {
1041 internationalCallOnWifiFragment.dismiss();
1042 }
1043
1044 // Dismiss the answer screen
1045 AnswerScreen answerScreen = getAnswerScreen();
1046 if (answerScreen != null) {
1047 answerScreen.dismissPendingDialogs();
1048 }
1049
1050 needDismissPendingDialogs = false;
Eric Erfanianccca3152017-02-22 16:32:36 -08001051 }
1052
linyuhc3968e62017-11-20 17:40:50 -08001053 private void enableInCallOrientationEventListener(boolean enable) {
linyuh69a25062017-11-15 16:18:51 -08001054 if (enable) {
1055 inCallOrientationEventListener.enable(true /* notifyDeviceOrientationChange */);
1056 } else {
1057 inCallOrientationEventListener.disable();
1058 }
Eric Erfanianccca3152017-02-22 16:32:36 -08001059 }
1060
1061 public void setExcludeFromRecents(boolean exclude) {
linyuhc3968e62017-11-20 17:40:50 -08001062 int taskId = getTaskId();
1063
1064 List<AppTask> tasks = getSystemService(ActivityManager.class).getAppTasks();
1065 for (AppTask task : tasks) {
1066 try {
1067 if (task.getTaskInfo().id == taskId) {
1068 task.setExcludeFromRecents(exclude);
1069 }
1070 } catch (RuntimeException e) {
1071 LogUtil.e("InCallActivity.setExcludeFromRecents", "RuntimeException:\n%s", e);
1072 }
1073 }
Eric Erfanianccca3152017-02-22 16:32:36 -08001074 }
1075
Eric Erfanianccca3152017-02-22 16:32:36 -08001076 @Nullable
1077 public FragmentManager getDialpadFragmentManager() {
wangqifd4c9f72018-03-08 18:21:50 -08001078 InCallScreen inCallScreen = getInCallOrRttCallScreen();
Eric Erfanianccca3152017-02-22 16:32:36 -08001079 if (inCallScreen != null) {
1080 return inCallScreen.getInCallScreenFragment().getChildFragmentManager();
1081 }
1082 return null;
1083 }
1084
1085 public int getDialpadContainerId() {
wangqifd4c9f72018-03-08 18:21:50 -08001086 return getInCallOrRttCallScreen().getAnswerAndDialpadContainerResourceId();
Eric Erfanianccca3152017-02-22 16:32:36 -08001087 }
1088
1089 @Override
1090 public AnswerScreenDelegate newAnswerScreenDelegate(AnswerScreen answerScreen) {
1091 DialerCall call = CallList.getInstance().getCallById(answerScreen.getCallId());
1092 if (call == null) {
1093 // This is a work around for a bug where we attempt to create a new delegate after the call
1094 // has already been removed. An example of when this can happen is:
1095 // 1. incoming video call in landscape mode
1096 // 2. remote party hangs up
1097 // 3. activity switches from landscape to portrait
1098 // At step #3 the answer fragment will try to create a new answer delegate but the call won't
1099 // exist. In this case we'll simply return a stub delegate that does nothing. This is ok
1100 // because this new state is transient and the activity will be destroyed soon.
1101 LogUtil.i("InCallActivity.onPrimaryCallStateChanged", "call doesn't exist, using stub");
1102 return new AnswerScreenPresenterStub();
1103 } else {
1104 return new AnswerScreenPresenter(
1105 this, answerScreen, CallList.getInstance().getCallById(answerScreen.getCallId()));
1106 }
1107 }
1108
1109 @Override
1110 public InCallScreenDelegate newInCallScreenDelegate() {
1111 return new CallCardPresenter(this);
1112 }
1113
1114 @Override
1115 public InCallButtonUiDelegate newInCallButtonUiDelegate() {
1116 return new CallButtonPresenter(this);
1117 }
1118
1119 @Override
Eric Erfanian90508232017-03-24 09:31:16 -07001120 public VideoCallScreenDelegate newVideoCallScreenDelegate(VideoCallScreen videoCallScreen) {
1121 DialerCall dialerCall = CallList.getInstance().getCallById(videoCallScreen.getCallId());
1122 if (dialerCall != null && dialerCall.getVideoTech().shouldUseSurfaceView()) {
1123 return dialerCall.getVideoTech().createVideoCallScreenDelegate(this, videoCallScreen);
1124 }
Eric Erfanianccca3152017-02-22 16:32:36 -08001125 return new VideoCallPresenter();
1126 }
1127
1128 public void onPrimaryCallStateChanged() {
Eric Erfanian2ca43182017-08-31 06:57:16 -07001129 Trace.beginSection("InCallActivity.onPrimaryCallStateChanged");
Eric Erfanianccca3152017-02-22 16:32:36 -08001130 showMainInCallFragment();
Eric Erfanian2ca43182017-08-31 06:57:16 -07001131 Trace.endSection();
Eric Erfanianccca3152017-02-22 16:32:36 -08001132 }
1133
linyuh7b86f562017-11-16 11:24:09 -08001134 public void showDialogOrToastForWifiHandoverFailure(DialerCall call) {
1135 if (call.showWifiHandoverAlertAsToast()) {
1136 Toast.makeText(this, R.string.video_call_lte_to_wifi_failed_message, Toast.LENGTH_SHORT)
1137 .show();
1138 return;
1139 }
1140
1141 dismissPendingDialogs();
1142
1143 AlertDialog.Builder builder =
1144 new AlertDialog.Builder(this).setTitle(R.string.video_call_lte_to_wifi_failed_title);
1145
1146 // This allows us to use the theme of the dialog instead of the activity
1147 View dialogCheckBoxView =
1148 View.inflate(builder.getContext(), R.layout.video_call_lte_to_wifi_failed, null /* root */);
1149 CheckBox wifiHandoverFailureCheckbox =
1150 (CheckBox) dialogCheckBoxView.findViewById(R.id.video_call_lte_to_wifi_failed_checkbox);
1151 wifiHandoverFailureCheckbox.setChecked(false);
1152
1153 InCallUiLock lock = InCallPresenter.getInstance().acquireInCallUiLock("WifiFailedDialog");
linyuhc3968e62017-11-20 17:40:50 -08001154 errorDialog =
linyuh7b86f562017-11-16 11:24:09 -08001155 builder
1156 .setView(dialogCheckBoxView)
1157 .setMessage(R.string.video_call_lte_to_wifi_failed_message)
1158 .setOnCancelListener(dialogInterface -> onDialogDismissed())
1159 .setPositiveButton(
1160 android.R.string.ok,
1161 (dialogInterface, id) -> {
1162 call.setDoNotShowDialogForHandoffToWifiFailure(
1163 wifiHandoverFailureCheckbox.isChecked());
1164 dialogInterface.cancel();
1165 onDialogDismissed();
1166 })
1167 .setOnDismissListener(dialogInterface -> lock.release())
1168 .create();
linyuh7b86f562017-11-16 11:24:09 -08001169 errorDialog.show();
Eric Erfanianccca3152017-02-22 16:32:36 -08001170 }
1171
linyuh7b86f562017-11-16 11:24:09 -08001172 public void showDialogForInternationalCallOnWifi(@NonNull DialerCall call) {
linyuh7b86f562017-11-16 11:24:09 -08001173 InternationalCallOnWifiDialogFragment fragment =
yuegb47528e2018-04-24 12:12:57 -07001174 InternationalCallOnWifiDialogFragment.newInstance(call.getId());
linyuhc3968e62017-11-20 17:40:50 -08001175 fragment.show(getSupportFragmentManager(), Tags.INTERNATIONAL_CALL_ON_WIFI);
Eric Erfanianc857f902017-05-15 14:05:33 -07001176 }
1177
wangqibc28ea72018-04-02 16:23:00 -07001178 public void showDialogForRttRequest(DialerCall call, int rttRequestId) {
1179 LogUtil.enterBlock("InCallActivity.showDialogForRttRequest");
wangqifb0cfff2018-06-05 11:51:01 -07001180 rttRequestDialogFragment = RttRequestDialogFragment.newInstance(call.getId(), rttRequestId);
1181 rttRequestDialogFragment.show(getSupportFragmentManager(), Tags.RTT_REQUEST_DIALOG);
wangqibc28ea72018-04-02 16:23:00 -07001182 }
1183
Eric Erfanianccca3152017-02-22 16:32:36 -08001184 public void setAllowOrientationChange(boolean allowOrientationChange) {
wangqi9982f0d2017-10-11 17:46:07 -07001185 if (this.allowOrientationChange == allowOrientationChange) {
1186 return;
1187 }
1188 this.allowOrientationChange = allowOrientationChange;
Eric Erfanianccca3152017-02-22 16:32:36 -08001189 if (!allowOrientationChange) {
1190 setRequestedOrientation(InCallOrientationEventListener.ACTIVITY_PREFERENCE_DISALLOW_ROTATION);
1191 } else {
1192 setRequestedOrientation(InCallOrientationEventListener.ACTIVITY_PREFERENCE_ALLOW_ROTATION);
1193 }
1194 enableInCallOrientationEventListener(allowOrientationChange);
1195 }
1196
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001197 public void hideMainInCallFragment() {
linyuhc3968e62017-11-20 17:40:50 -08001198 LogUtil.enterBlock("InCallActivity.hideMainInCallFragment");
1199 if (getCallCardFragmentVisible()) {
Eric Erfanianccca3152017-02-22 16:32:36 -08001200 FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
1201 hideInCallScreenFragment(transaction);
1202 hideVideoCallScreenFragment(transaction);
1203 transaction.commitAllowingStateLoss();
1204 getSupportFragmentManager().executePendingTransactions();
1205 }
1206 }
1207
1208 private void showMainInCallFragment() {
Eric Erfanian2ca43182017-08-31 06:57:16 -07001209 Trace.beginSection("InCallActivity.showMainInCallFragment");
Eric Erfanianccca3152017-02-22 16:32:36 -08001210 // If the activity's onStart method hasn't been called yet then defer doing any work.
1211 if (!isVisible) {
1212 LogUtil.i("InCallActivity.showMainInCallFragment", "not visible yet/anymore");
Eric Erfanian2ca43182017-08-31 06:57:16 -07001213 Trace.endSection();
Eric Erfanianccca3152017-02-22 16:32:36 -08001214 return;
1215 }
1216
1217 // Don't let this be reentrant.
1218 if (isInShowMainInCallFragment) {
1219 LogUtil.i("InCallActivity.showMainInCallFragment", "already in method, bailing");
Eric Erfanian2ca43182017-08-31 06:57:16 -07001220 Trace.endSection();
Eric Erfanianccca3152017-02-22 16:32:36 -08001221 return;
1222 }
1223
1224 isInShowMainInCallFragment = true;
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001225 ShouldShowUiResult shouldShowAnswerUi = getShouldShowAnswerUi();
1226 ShouldShowUiResult shouldShowVideoUi = getShouldShowVideoUi();
wangqi219b8702018-02-13 09:34:41 -08001227 ShouldShowUiResult shouldShowRttUi = getShouldShowRttUi();
erfaniand05d8992018-03-20 19:42:26 -07001228 ShouldShowUiResult shouldShowSpeakEasyUi = getShouldShowSpeakEasyUi();
Eric Erfanianccca3152017-02-22 16:32:36 -08001229 LogUtil.i(
1230 "InCallActivity.showMainInCallFragment",
uabdullah56a4cda2018-05-10 16:38:35 -07001231 "shouldShowAnswerUi: %b, shouldShowRttUi: %b, shouldShowVideoUi: %b, "
1232 + "shouldShowSpeakEasyUi: %b, didShowAnswerScreen: %b, didShowInCallScreen: %b, "
1233 + "didShowRttCallScreen: %b, didShowVideoCallScreen: %b, didShowSpeakEasyScreen: %b",
Eric Erfanianccca3152017-02-22 16:32:36 -08001234 shouldShowAnswerUi.shouldShow,
wangqi219b8702018-02-13 09:34:41 -08001235 shouldShowRttUi.shouldShow,
Eric Erfanian10b34a52017-05-04 08:23:17 -07001236 shouldShowVideoUi.shouldShow,
uabdullah56a4cda2018-05-10 16:38:35 -07001237 shouldShowSpeakEasyUi.shouldShow,
Eric Erfanianccca3152017-02-22 16:32:36 -08001238 didShowAnswerScreen,
1239 didShowInCallScreen,
wangqi219b8702018-02-13 09:34:41 -08001240 didShowRttCallScreen,
erfaniand05d8992018-03-20 19:42:26 -07001241 didShowVideoCallScreen,
1242 didShowSpeakEasyScreen);
Eric Erfanianccca3152017-02-22 16:32:36 -08001243 // Only video call ui allows orientation change.
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001244 setAllowOrientationChange(shouldShowVideoUi.shouldShow);
Eric Erfanianccca3152017-02-22 16:32:36 -08001245
1246 FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
wangqi219b8702018-02-13 09:34:41 -08001247 boolean didChange;
Eric Erfanianccca3152017-02-22 16:32:36 -08001248 if (shouldShowAnswerUi.shouldShow) {
wangqi219b8702018-02-13 09:34:41 -08001249 didChange = hideInCallScreenFragment(transaction);
1250 didChange |= hideVideoCallScreenFragment(transaction);
1251 didChange |= hideRttCallScreenFragment(transaction);
erfaniand05d8992018-03-20 19:42:26 -07001252 didChange |= hideSpeakEasyFragment(transaction);
wangqi219b8702018-02-13 09:34:41 -08001253 didChange |= showAnswerScreenFragment(transaction, shouldShowAnswerUi.call);
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001254 } else if (shouldShowVideoUi.shouldShow) {
wangqi219b8702018-02-13 09:34:41 -08001255 didChange = hideInCallScreenFragment(transaction);
1256 didChange |= showVideoCallScreenFragment(transaction, shouldShowVideoUi.call);
1257 didChange |= hideRttCallScreenFragment(transaction);
erfaniand05d8992018-03-20 19:42:26 -07001258 didChange |= hideSpeakEasyFragment(transaction);
wangqi219b8702018-02-13 09:34:41 -08001259 didChange |= hideAnswerScreenFragment(transaction);
1260 } else if (shouldShowRttUi.shouldShow) {
1261 didChange = hideInCallScreenFragment(transaction);
1262 didChange |= hideVideoCallScreenFragment(transaction);
1263 didChange |= hideAnswerScreenFragment(transaction);
erfaniand05d8992018-03-20 19:42:26 -07001264 didChange |= hideSpeakEasyFragment(transaction);
wangqi219b8702018-02-13 09:34:41 -08001265 didChange |= showRttCallScreenFragment(transaction, shouldShowRttUi.call);
erfaniand05d8992018-03-20 19:42:26 -07001266 } else if (shouldShowSpeakEasyUi.shouldShow) {
1267 didChange = hideInCallScreenFragment(transaction);
1268 didChange |= hideVideoCallScreenFragment(transaction);
1269 didChange |= hideAnswerScreenFragment(transaction);
1270 didChange |= hideRttCallScreenFragment(transaction);
1271 didChange |= showSpeakEasyFragment(transaction, shouldShowSpeakEasyUi.call);
Eric Erfanianccca3152017-02-22 16:32:36 -08001272 } else {
wangqi219b8702018-02-13 09:34:41 -08001273 didChange = showInCallScreenFragment(transaction);
1274 didChange |= hideVideoCallScreenFragment(transaction);
1275 didChange |= hideRttCallScreenFragment(transaction);
erfaniand05d8992018-03-20 19:42:26 -07001276 didChange |= hideSpeakEasyFragment(transaction);
wangqi219b8702018-02-13 09:34:41 -08001277 didChange |= hideAnswerScreenFragment(transaction);
Eric Erfanianccca3152017-02-22 16:32:36 -08001278 }
1279
wangqi219b8702018-02-13 09:34:41 -08001280 if (didChange) {
Eric Erfanian2ca43182017-08-31 06:57:16 -07001281 Trace.beginSection("InCallActivity.commitTransaction");
Eric Erfanianccca3152017-02-22 16:32:36 -08001282 transaction.commitNow();
Eric Erfanian2ca43182017-08-31 06:57:16 -07001283 Trace.endSection();
Eric Erfanianccca3152017-02-22 16:32:36 -08001284 Logger.get(this).logScreenView(ScreenEvent.Type.INCALL, this);
1285 }
1286 isInShowMainInCallFragment = false;
Eric Erfanian2ca43182017-08-31 06:57:16 -07001287 Trace.endSection();
Eric Erfanianccca3152017-02-22 16:32:36 -08001288 }
1289
erfaniand05d8992018-03-20 19:42:26 -07001290 private boolean showSpeakEasyFragment(FragmentTransaction transaction, DialerCall call) {
1291
erfaniand05d8992018-03-20 19:42:26 -07001292 if (didShowSpeakEasyScreen) {
erfanian612d13a2018-04-04 15:27:57 -07001293 if (lastShownSpeakEasyScreenUniqueCallid.equals(call.getUniqueCallId())) {
erfanian12243de2018-04-17 12:17:08 -07001294 LogUtil.i("InCallActivity.showSpeakEasyFragment", "found existing fragment");
erfanian612d13a2018-04-04 15:27:57 -07001295 return false;
1296 }
1297 hideSpeakEasyFragment(transaction);
erfanian12243de2018-04-17 12:17:08 -07001298 LogUtil.i("InCallActivity.showSpeakEasyFragment", "hid existing fragment");
erfaniand05d8992018-03-20 19:42:26 -07001299 }
1300
1301 Optional<Fragment> speakEasyFragment = speakEasyCallManager.getSpeakEasyFragment(call);
1302 if (speakEasyFragment.isPresent()) {
1303 transaction.add(R.id.main, speakEasyFragment.get(), Tags.SPEAK_EASY_SCREEN);
1304 didShowSpeakEasyScreen = true;
erfanian612d13a2018-04-04 15:27:57 -07001305 lastShownSpeakEasyScreenUniqueCallid = call.getUniqueCallId();
erfanian12243de2018-04-17 12:17:08 -07001306 LogUtil.i(
1307 "InCallActivity.showSpeakEasyFragment",
1308 "set fragment for call %s",
1309 lastShownSpeakEasyScreenUniqueCallid);
erfaniand05d8992018-03-20 19:42:26 -07001310 return true;
1311 }
1312 return false;
1313 }
1314
1315 private Fragment getSpeakEasyScreen() {
1316 return getSupportFragmentManager().findFragmentByTag(Tags.SPEAK_EASY_SCREEN);
1317 }
1318
1319 private boolean hideSpeakEasyFragment(FragmentTransaction transaction) {
1320 if (!didShowSpeakEasyScreen) {
1321 return false;
1322 }
1323
1324 Fragment speakEasyFragment = getSpeakEasyScreen();
1325
1326 if (speakEasyFragment != null) {
1327 transaction.remove(speakEasyFragment);
1328 didShowSpeakEasyScreen = false;
1329 return true;
1330 }
1331 return false;
1332 }
1333
erfanian12243de2018-04-17 12:17:08 -07001334 @VisibleForTesting
erfaniand05d8992018-03-20 19:42:26 -07001335 public void setSpeakEasyCallManager(SpeakEasyCallManager speakEasyCallManager) {
erfanian87dbb622018-04-04 15:43:00 -07001336 this.speakEasyCallManager = speakEasyCallManager;
erfaniand05d8992018-03-20 19:42:26 -07001337 }
1338
erfanian12243de2018-04-17 12:17:08 -07001339 @Nullable
erfaniand05d8992018-03-20 19:42:26 -07001340 public SpeakEasyCallManager getSpeakEasyCallManager() {
erfanian12243de2018-04-17 12:17:08 -07001341 if (this.speakEasyCallManager == null) {
1342 this.speakEasyCallManager = InCallPresenter.getInstance().getSpeakEasyCallManager();
1343 }
erfaniand05d8992018-03-20 19:42:26 -07001344 return speakEasyCallManager;
1345 }
1346
1347 private ShouldShowUiResult getShouldShowSpeakEasyUi() {
1348 SpeakEasyCallManager speakEasyCallManager = getSpeakEasyCallManager();
1349
1350 if (speakEasyCallManager == null) {
1351 return new ShouldShowUiResult(false, null);
1352 }
1353
erfanian3bb7cb62018-04-11 09:01:15 -07001354 DialerCall call =
1355 CallList.getInstance().getIncomingCall() != null
1356 ? CallList.getInstance().getIncomingCall()
1357 : CallList.getInstance().getActiveCall();
erfaniand05d8992018-03-20 19:42:26 -07001358
1359 if (call == null) {
erfanian38e0ed42018-06-25 15:24:07 -07001360 // This is a special case where the first call is not automatically resumed
1361 // after the second active call is remotely disconnected.
1362 DialerCall backgroundCall = CallList.getInstance().getBackgroundCall();
1363 if (backgroundCall != null && backgroundCall.isSpeakEasyCall()) {
1364 LogUtil.i("InCallActivity.getShouldShowSpeakEasyUi", "taking call off hold");
1365
1366 backgroundCall.unhold();
1367 return new ShouldShowUiResult(true, backgroundCall);
1368 }
1369
erfaniand05d8992018-03-20 19:42:26 -07001370 return new ShouldShowUiResult(false, call);
1371 }
1372
1373 if (!call.isSpeakEasyCall() || !call.isSpeakEasyEligible()) {
1374 return new ShouldShowUiResult(false, call);
1375 }
1376
1377 Optional<Fragment> speakEasyFragment = speakEasyCallManager.getSpeakEasyFragment(call);
1378
1379 if (!speakEasyFragment.isPresent()) {
1380 return new ShouldShowUiResult(false, call);
1381 }
1382 return new ShouldShowUiResult(true, call);
1383 }
1384
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001385 private ShouldShowUiResult getShouldShowAnswerUi() {
Eric Erfanianccca3152017-02-22 16:32:36 -08001386 DialerCall call = CallList.getInstance().getIncomingCall();
erfanian3bb7cb62018-04-11 09:01:15 -07001387 if (call != null && !call.isSpeakEasyCall()) {
Eric Erfanianccca3152017-02-22 16:32:36 -08001388 LogUtil.i("InCallActivity.getShouldShowAnswerUi", "found incoming call");
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001389 return new ShouldShowUiResult(true, call);
Eric Erfanianccca3152017-02-22 16:32:36 -08001390 }
1391
1392 call = CallList.getInstance().getVideoUpgradeRequestCall();
1393 if (call != null) {
1394 LogUtil.i("InCallActivity.getShouldShowAnswerUi", "found video upgrade request");
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001395 return new ShouldShowUiResult(true, call);
Eric Erfanianccca3152017-02-22 16:32:36 -08001396 }
1397
1398 // Check if we're showing the answer screen and the call is disconnected. If this condition is
1399 // true then we won't switch from the answer UI to the in call UI. This prevents flicker when
1400 // the user rejects an incoming call.
1401 call = CallList.getInstance().getFirstCall();
1402 if (call == null) {
1403 call = CallList.getInstance().getBackgroundCall();
1404 }
wangqibb94ca62018-04-27 14:34:04 -07001405 if (didShowAnswerScreen && (call == null || call.getState() == DialerCallState.DISCONNECTED)) {
Eric Erfanianccca3152017-02-22 16:32:36 -08001406 LogUtil.i("InCallActivity.getShouldShowAnswerUi", "found disconnecting incoming call");
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001407 return new ShouldShowUiResult(true, call);
Eric Erfanianccca3152017-02-22 16:32:36 -08001408 }
1409
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001410 return new ShouldShowUiResult(false, null);
Eric Erfanianccca3152017-02-22 16:32:36 -08001411 }
1412
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001413 private static ShouldShowUiResult getShouldShowVideoUi() {
Eric Erfanianccca3152017-02-22 16:32:36 -08001414 DialerCall call = CallList.getInstance().getFirstCall();
1415 if (call == null) {
1416 LogUtil.i("InCallActivity.getShouldShowVideoUi", "null call");
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001417 return new ShouldShowUiResult(false, null);
Eric Erfanianccca3152017-02-22 16:32:36 -08001418 }
1419
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001420 if (call.isVideoCall()) {
Eric Erfanianccca3152017-02-22 16:32:36 -08001421 LogUtil.i("InCallActivity.getShouldShowVideoUi", "found video call");
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001422 return new ShouldShowUiResult(true, call);
Eric Erfanianccca3152017-02-22 16:32:36 -08001423 }
1424
linyuh8fbecce2017-12-18 13:53:09 -08001425 if (call.hasSentVideoUpgradeRequest() || call.hasReceivedVideoUpgradeRequest()) {
Eric Erfanianccca3152017-02-22 16:32:36 -08001426 LogUtil.i("InCallActivity.getShouldShowVideoUi", "upgrading to video");
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001427 return new ShouldShowUiResult(true, call);
Eric Erfanianccca3152017-02-22 16:32:36 -08001428 }
1429
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001430 return new ShouldShowUiResult(false, null);
Eric Erfanianccca3152017-02-22 16:32:36 -08001431 }
1432
wangqi219b8702018-02-13 09:34:41 -08001433 private static ShouldShowUiResult getShouldShowRttUi() {
1434 DialerCall call = CallList.getInstance().getFirstCall();
1435 if (call == null) {
1436 LogUtil.i("InCallActivity.getShouldShowRttUi", "null call");
1437 return new ShouldShowUiResult(false, null);
1438 }
1439
wangqif6be6172018-03-30 15:57:56 -07001440 if (call.isActiveRttCall()) {
wangqi219b8702018-02-13 09:34:41 -08001441 LogUtil.i("InCallActivity.getShouldShowRttUi", "found rtt call");
1442 return new ShouldShowUiResult(true, call);
1443 }
1444
1445 if (call.hasSentRttUpgradeRequest()) {
1446 LogUtil.i("InCallActivity.getShouldShowRttUi", "upgrading to rtt");
1447 return new ShouldShowUiResult(true, call);
1448 }
1449
1450 return new ShouldShowUiResult(false, null);
1451 }
1452
Eric Erfanianccca3152017-02-22 16:32:36 -08001453 private boolean showAnswerScreenFragment(FragmentTransaction transaction, DialerCall call) {
1454 // When rejecting a call the active call can become null in which case we should continue
1455 // showing the answer screen.
1456 if (didShowAnswerScreen && call == null) {
1457 return false;
1458 }
1459
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001460 Assert.checkArgument(call != null, "didShowAnswerScreen was false but call was still null");
1461
1462 boolean isVideoUpgradeRequest = call.hasReceivedVideoUpgradeRequest();
Eric Erfanianccca3152017-02-22 16:32:36 -08001463
1464 // Check if we're already showing an answer screen for this call.
1465 if (didShowAnswerScreen) {
1466 AnswerScreen answerScreen = getAnswerScreen();
1467 if (answerScreen.getCallId().equals(call.getId())
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001468 && answerScreen.isVideoCall() == call.isVideoCall()
Eric Erfanian2ca43182017-08-31 06:57:16 -07001469 && answerScreen.isVideoUpgradeRequest() == isVideoUpgradeRequest
1470 && !answerScreen.isActionTimeout()) {
1471 LogUtil.d(
1472 "InCallActivity.showAnswerScreenFragment",
1473 "answer fragment exists for same call and has NOT been accepted/rejected/timed out");
Eric Erfanianccca3152017-02-22 16:32:36 -08001474 return false;
1475 }
Eric Erfanian2ca43182017-08-31 06:57:16 -07001476 if (answerScreen.isActionTimeout()) {
1477 LogUtil.i(
1478 "InCallActivity.showAnswerScreenFragment",
1479 "answer fragment exists but has been accepted/rejected and timed out");
1480 } else {
1481 LogUtil.i(
1482 "InCallActivity.showAnswerScreenFragment",
1483 "answer fragment exists but arguments do not match");
1484 }
Eric Erfanianccca3152017-02-22 16:32:36 -08001485 hideAnswerScreenFragment(transaction);
1486 }
1487
1488 // Show a new answer screen.
1489 AnswerScreen answerScreen =
Eric Erfanianfc37b022017-03-21 10:11:17 -07001490 AnswerBindings.createAnswerScreen(
1491 call.getId(),
wangqif6be6172018-03-30 15:57:56 -07001492 call.isActiveRttCall(),
Eric Erfanianfc37b022017-03-21 10:11:17 -07001493 call.isVideoCall(),
1494 isVideoUpgradeRequest,
Eric Erfanian90508232017-03-24 09:31:16 -07001495 call.getVideoTech().isSelfManagedCamera(),
1496 shouldAllowAnswerAndRelease(call),
erfaniand05d8992018-03-20 19:42:26 -07001497 CallList.getInstance().getBackgroundCall() != null,
erfanian89e3d1b2018-05-02 18:50:59 -07001498 getSpeakEasyCallManager().isAvailable(getApplicationContext())
1499 && call.isSpeakEasyEligible());
linyuhc3968e62017-11-20 17:40:50 -08001500 transaction.add(R.id.main, answerScreen.getAnswerScreenFragment(), Tags.ANSWER_SCREEN);
Eric Erfanianccca3152017-02-22 16:32:36 -08001501
1502 Logger.get(this).logScreenView(ScreenEvent.Type.INCOMING_CALL, this);
1503 didShowAnswerScreen = true;
1504 return true;
1505 }
1506
Eric Erfanian90508232017-03-24 09:31:16 -07001507 private boolean shouldAllowAnswerAndRelease(DialerCall call) {
1508 if (CallList.getInstance().getActiveCall() == null) {
1509 LogUtil.i("InCallActivity.shouldAllowAnswerAndRelease", "no active call");
1510 return false;
1511 }
1512 if (getSystemService(TelephonyManager.class).getPhoneType()
1513 == TelephonyManager.PHONE_TYPE_CDMA) {
1514 LogUtil.i("InCallActivity.shouldAllowAnswerAndRelease", "PHONE_TYPE_CDMA not supported");
1515 return false;
1516 }
1517 if (call.isVideoCall() || call.hasReceivedVideoUpgradeRequest()) {
1518 LogUtil.i("InCallActivity.shouldAllowAnswerAndRelease", "video call");
1519 return false;
1520 }
zachh190343a2018-05-31 17:30:46 -07001521 if (!ConfigProviderComponent.get(this)
1522 .getConfigProvider()
linyuhc3968e62017-11-20 17:40:50 -08001523 .getBoolean(ConfigNames.ANSWER_AND_RELEASE_ENABLED, true)) {
Eric Erfanian90508232017-03-24 09:31:16 -07001524 LogUtil.i("InCallActivity.shouldAllowAnswerAndRelease", "disabled by config");
1525 return false;
1526 }
1527
1528 return true;
1529 }
1530
Eric Erfanianccca3152017-02-22 16:32:36 -08001531 private boolean hideAnswerScreenFragment(FragmentTransaction transaction) {
1532 if (!didShowAnswerScreen) {
1533 return false;
1534 }
1535 AnswerScreen answerScreen = getAnswerScreen();
1536 if (answerScreen != null) {
1537 transaction.remove(answerScreen.getAnswerScreenFragment());
1538 }
1539
1540 didShowAnswerScreen = false;
1541 return true;
1542 }
1543
1544 private boolean showInCallScreenFragment(FragmentTransaction transaction) {
1545 if (didShowInCallScreen) {
1546 return false;
1547 }
Eric Erfanian2ca43182017-08-31 06:57:16 -07001548 InCallScreen inCallScreen = InCallBindings.createInCallScreen();
linyuhc3968e62017-11-20 17:40:50 -08001549 transaction.add(R.id.main, inCallScreen.getInCallScreenFragment(), Tags.IN_CALL_SCREEN);
Eric Erfanianccca3152017-02-22 16:32:36 -08001550 Logger.get(this).logScreenView(ScreenEvent.Type.INCALL, this);
1551 didShowInCallScreen = true;
1552 return true;
1553 }
1554
1555 private boolean hideInCallScreenFragment(FragmentTransaction transaction) {
1556 if (!didShowInCallScreen) {
1557 return false;
1558 }
1559 InCallScreen inCallScreen = getInCallScreen();
1560 if (inCallScreen != null) {
Eric Erfanian2ca43182017-08-31 06:57:16 -07001561 transaction.remove(inCallScreen.getInCallScreenFragment());
Eric Erfanianccca3152017-02-22 16:32:36 -08001562 }
1563 didShowInCallScreen = false;
1564 return true;
1565 }
1566
wangqi219b8702018-02-13 09:34:41 -08001567 private boolean showRttCallScreenFragment(FragmentTransaction transaction, DialerCall call) {
1568 if (didShowRttCallScreen) {
wangqi91958f82018-06-06 14:01:47 -07001569 if (getRttCallScreen().getCallId().equals(call.getId())) {
1570 return false;
wangqi219b8702018-02-13 09:34:41 -08001571 }
wangqi91958f82018-06-06 14:01:47 -07001572 LogUtil.i("InCallActivity.showRttCallScreenFragment", "RTT call id doesn't match");
1573 hideRttCallScreenFragment(transaction);
wangqi219b8702018-02-13 09:34:41 -08001574 }
1575 RttCallScreen rttCallScreen = RttBindings.createRttCallScreen(call.getId());
1576 transaction.add(R.id.main, rttCallScreen.getRttCallScreenFragment(), Tags.RTT_CALL_SCREEN);
1577 Logger.get(this).logScreenView(ScreenEvent.Type.INCALL, this);
1578 didShowRttCallScreen = true;
wangqifb0cfff2018-06-05 11:51:01 -07001579 // In some cases such as VZW, RTT request will be automatically accepted by modem. So the dialog
1580 // won't make any sense and should be dismissed if it's already switched to RTT.
1581 if (rttRequestDialogFragment != null) {
1582 LogUtil.i("InCallActivity.showRttCallScreenFragment", "dismiss RTT request dialog");
1583 rttRequestDialogFragment.dismiss();
1584 rttRequestDialogFragment = null;
1585 }
wangqi219b8702018-02-13 09:34:41 -08001586 return true;
1587 }
1588
1589 private boolean hideRttCallScreenFragment(FragmentTransaction transaction) {
1590 if (!didShowRttCallScreen) {
1591 return false;
1592 }
1593 RttCallScreen rttCallScreen = getRttCallScreen();
1594 if (rttCallScreen != null) {
1595 transaction.remove(rttCallScreen.getRttCallScreenFragment());
1596 }
1597 didShowRttCallScreen = false;
1598 return true;
1599 }
1600
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001601 private boolean showVideoCallScreenFragment(FragmentTransaction transaction, DialerCall call) {
Eric Erfanianccca3152017-02-22 16:32:36 -08001602 if (didShowVideoCallScreen) {
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001603 VideoCallScreen videoCallScreen = getVideoCallScreen();
1604 if (videoCallScreen.getCallId().equals(call.getId())) {
1605 return false;
1606 }
1607 LogUtil.i(
1608 "InCallActivity.showVideoCallScreenFragment",
1609 "video call fragment exists but arguments do not match");
1610 hideVideoCallScreenFragment(transaction);
Eric Erfanianccca3152017-02-22 16:32:36 -08001611 }
1612
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001613 LogUtil.i("InCallActivity.showVideoCallScreenFragment", "call: %s", call);
1614
Eric Erfanian90508232017-03-24 09:31:16 -07001615 VideoCallScreen videoCallScreen =
1616 VideoBindings.createVideoCallScreen(
1617 call.getId(), call.getVideoTech().shouldUseSurfaceView());
linyuhc3968e62017-11-20 17:40:50 -08001618 transaction.add(
1619 R.id.main, videoCallScreen.getVideoCallScreenFragment(), Tags.VIDEO_CALL_SCREEN);
Eric Erfanianccca3152017-02-22 16:32:36 -08001620
1621 Logger.get(this).logScreenView(ScreenEvent.Type.INCALL, this);
1622 didShowVideoCallScreen = true;
1623 return true;
1624 }
1625
1626 private boolean hideVideoCallScreenFragment(FragmentTransaction transaction) {
1627 if (!didShowVideoCallScreen) {
1628 return false;
1629 }
1630 VideoCallScreen videoCallScreen = getVideoCallScreen();
1631 if (videoCallScreen != null) {
1632 transaction.remove(videoCallScreen.getVideoCallScreenFragment());
1633 }
1634 didShowVideoCallScreen = false;
1635 return true;
1636 }
1637
linyuhc3968e62017-11-20 17:40:50 -08001638 private AnswerScreen getAnswerScreen() {
1639 return (AnswerScreen) getSupportFragmentManager().findFragmentByTag(Tags.ANSWER_SCREEN);
Eric Erfanianccca3152017-02-22 16:32:36 -08001640 }
1641
linyuhc3968e62017-11-20 17:40:50 -08001642 private InCallScreen getInCallScreen() {
1643 return (InCallScreen) getSupportFragmentManager().findFragmentByTag(Tags.IN_CALL_SCREEN);
Eric Erfanianccca3152017-02-22 16:32:36 -08001644 }
1645
linyuhc3968e62017-11-20 17:40:50 -08001646 private VideoCallScreen getVideoCallScreen() {
1647 return (VideoCallScreen) getSupportFragmentManager().findFragmentByTag(Tags.VIDEO_CALL_SCREEN);
Eric Erfanianccca3152017-02-22 16:32:36 -08001648 }
1649
wangqi219b8702018-02-13 09:34:41 -08001650 private RttCallScreen getRttCallScreen() {
1651 return (RttCallScreen) getSupportFragmentManager().findFragmentByTag(Tags.RTT_CALL_SCREEN);
1652 }
1653
wangqifd4c9f72018-03-08 18:21:50 -08001654 private InCallScreen getInCallOrRttCallScreen() {
1655 InCallScreen inCallScreen = null;
1656 if (didShowInCallScreen) {
1657 inCallScreen = getInCallScreen();
1658 }
1659 if (didShowRttCallScreen) {
1660 inCallScreen = getRttCallScreen();
1661 }
1662 return inCallScreen;
1663 }
1664
Eric Erfanianccca3152017-02-22 16:32:36 -08001665 @Override
1666 public void onPseudoScreenStateChanged(boolean isOn) {
1667 LogUtil.i("InCallActivity.onPseudoScreenStateChanged", "isOn: " + isOn);
1668 pseudoBlackScreenOverlay.setVisibility(isOn ? View.GONE : View.VISIBLE);
1669 }
1670
1671 /**
1672 * For some touch related issue, turning off the screen can be faked by drawing a black view over
1673 * the activity. All touch events started when the screen is "off" is rejected.
1674 *
1675 * @see PseudoScreenState
1676 */
1677 @Override
1678 public boolean dispatchTouchEvent(MotionEvent event) {
1679 // Reject any gesture that started when the screen is in the fake off state.
1680 if (touchDownWhenPseudoScreenOff) {
1681 if (event.getAction() == MotionEvent.ACTION_UP) {
1682 touchDownWhenPseudoScreenOff = false;
1683 }
1684 return true;
1685 }
1686 // Reject all touch event when the screen is in the fake off state.
1687 if (!InCallPresenter.getInstance().getPseudoScreenState().isOn()) {
1688 if (event.getAction() == MotionEvent.ACTION_DOWN) {
1689 touchDownWhenPseudoScreenOff = true;
1690 LogUtil.i("InCallActivity.dispatchTouchEvent", "touchDownWhenPseudoScreenOff");
1691 }
1692 return true;
1693 }
1694 return super.dispatchTouchEvent(event);
1695 }
1696
wangqi219b8702018-02-13 09:34:41 -08001697 @Override
1698 public RttCallScreenDelegate newRttCallScreenDelegate(RttCallScreen videoCallScreen) {
1699 return new RttCallPresenter();
1700 }
1701
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001702 private static class ShouldShowUiResult {
Eric Erfanianccca3152017-02-22 16:32:36 -08001703 public final boolean shouldShow;
1704 public final DialerCall call;
1705
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001706 ShouldShowUiResult(boolean shouldShow, DialerCall call) {
Eric Erfanianccca3152017-02-22 16:32:36 -08001707 this.shouldShow = shouldShow;
1708 this.call = call;
1709 }
1710 }
linyuhc3968e62017-11-20 17:40:50 -08001711
1712 private static final class IntentExtraNames {
1713 static final String FOR_FULL_SCREEN = "InCallActivity.for_full_screen_intent";
1714 static final String NEW_OUTGOING_CALL = "InCallActivity.new_outgoing_call";
1715 static final String SHOW_DIALPAD = "InCallActivity.show_dialpad";
1716 }
1717
1718 private static final class KeysForSavedInstance {
1719 static final String DIALPAD_TEXT = "InCallActivity.dialpad_text";
1720 static final String DID_SHOW_ANSWER_SCREEN = "did_show_answer_screen";
1721 static final String DID_SHOW_IN_CALL_SCREEN = "did_show_in_call_screen";
1722 static final String DID_SHOW_VIDEO_CALL_SCREEN = "did_show_video_call_screen";
wangqi153af2f2018-02-15 16:21:49 -08001723 static final String DID_SHOW_RTT_CALL_SCREEN = "did_show_rtt_call_screen";
erfaniand05d8992018-03-20 19:42:26 -07001724 static final String DID_SHOW_SPEAK_EASY_SCREEN = "did_show_speak_easy_screen";
linyuhc3968e62017-11-20 17:40:50 -08001725 }
1726
1727 /** Request codes for pending intents. */
1728 public static final class PendingIntentRequestCodes {
1729 static final int NON_FULL_SCREEN = 0;
1730 static final int FULL_SCREEN = 1;
1731 static final int BUBBLE = 2;
1732 }
1733
1734 private static final class Tags {
1735 static final String ANSWER_SCREEN = "tag_answer_screen";
1736 static final String DIALPAD_FRAGMENT = "tag_dialpad_fragment";
1737 static final String IN_CALL_SCREEN = "tag_in_call_screen";
1738 static final String INTERNATIONAL_CALL_ON_WIFI = "tag_international_call_on_wifi";
1739 static final String SELECT_ACCOUNT_FRAGMENT = "tag_select_account_fragment";
1740 static final String VIDEO_CALL_SCREEN = "tag_video_call_screen";
wangqi219b8702018-02-13 09:34:41 -08001741 static final String RTT_CALL_SCREEN = "tag_rtt_call_screen";
linyuhc3968e62017-11-20 17:40:50 -08001742 static final String POST_CHAR_DIALOG_FRAGMENT = "tag_post_char_dialog_fragment";
erfaniand05d8992018-03-20 19:42:26 -07001743 static final String SPEAK_EASY_SCREEN = "tag_speak_easy_screen";
wangqibc28ea72018-04-02 16:23:00 -07001744 static final String RTT_REQUEST_DIALOG = "tag_rtt_request_dialog";
linyuhc3968e62017-11-20 17:40:50 -08001745 }
1746
1747 private static final class ConfigNames {
1748 static final String ANSWER_AND_RELEASE_ENABLED = "answer_and_release_enabled";
1749 }
1750
linyuhc3968e62017-11-20 17:40:50 -08001751 private static final class SelectPhoneAccountListener
1752 extends SelectPhoneAccountDialogFragment.SelectPhoneAccountListener {
1753 private static final String TAG = SelectPhoneAccountListener.class.getCanonicalName();
1754
twyen73a74c32018-03-07 12:12:24 -08001755 private final Context appContext;
1756
1757 SelectPhoneAccountListener(Context appContext) {
1758 this.appContext = appContext;
1759 }
1760
linyuhc3968e62017-11-20 17:40:50 -08001761 @Override
1762 public void onPhoneAccountSelected(
1763 PhoneAccountHandle selectedAccountHandle, boolean setDefault, String callId) {
1764 DialerCall call = CallList.getInstance().getCallById(callId);
1765 LogUtil.i(TAG, "Phone account select with call:\n%s", call);
1766
1767 if (call != null) {
twyen73a74c32018-03-07 12:12:24 -08001768 call.phoneAccountSelected(selectedAccountHandle, false);
1769 if (call.getPreferredAccountRecorder() != null) {
1770 call.getPreferredAccountRecorder().record(appContext, selectedAccountHandle, setDefault);
1771 }
linyuhc3968e62017-11-20 17:40:50 -08001772 }
1773 }
1774
1775 @Override
1776 public void onDialogDismissed(String callId) {
1777 DialerCall call = CallList.getInstance().getCallById(callId);
1778 LogUtil.i(TAG, "Disconnecting call:\n%s" + call);
1779
1780 if (call != null) {
1781 call.disconnect();
1782 }
1783 }
1784 }
Eric Erfanianccca3152017-02-22 16:32:36 -08001785}