blob: a550ddeaee43a63096b0020db3e050606f7d5537 [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.graphics.drawable.GradientDrawable;
29import android.graphics.drawable.GradientDrawable.Orientation;
30import android.os.Bundle;
Eric Erfanian2ca43182017-08-31 06:57:16 -070031import android.os.Trace;
Eric Erfanianccca3152017-02-22 16:32:36 -080032import 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 Erfanianccca3152017-02-22 16:32:36 -080043import 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;
linyuhc3968e62017-11-20 17:40:50 -0800104import com.google.common.base.Optional;
twyena1723252018-04-24 17:02:57 -0700105import com.google.common.util.concurrent.ListenableFuture;
linyuhc3968e62017-11-20 17:40:50 -0800106import java.lang.annotation.Retention;
107import java.lang.annotation.RetentionPolicy;
108import java.util.ArrayList;
109import java.util.List;
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
linyuhc3968e62017-11-20 17:40:50 -0800132 private static Optional<Integer> audioRouteForTesting = Optional.absent();
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;
140 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;
159 private int[] backgroundDrawableColors;
160 @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 -> {
twyen3b2c7812018-04-30 12:13:06 -0700383 if (!isVisible()) {
384 LogUtil.i(
385 "CallingAccountSelector.showPhoneAccountSelectionDialog",
386 "activity ended before result returned");
387 return;
388 }
twyen56f79ba2018-04-30 14:25:46 -0700389 String callId = waitingForAccountCall.getId();
390 if (result.getSelectedPhoneAccountHandle().isPresent()) {
twyena1723252018-04-24 17:02:57 -0700391 selectPhoneAccountListener.onPhoneAccountSelected(
twyen56f79ba2018-04-30 14:25:46 -0700392 result.getSelectedPhoneAccountHandle().get(), false, callId);
twyena1723252018-04-24 17:02:57 -0700393 return;
394 }
twyen66adad02018-04-24 13:51:08 -0700395
twyena1723252018-04-24 17:02:57 -0700396 waitingForAccountCall.setPreferredAccountRecorder(
397 new PreferredAccountRecorder(
398 waitingForAccountCall.getNumber(),
399 result.getSuggestion().orNull(),
400 result.getDataId().orNull()));
twyena1723252018-04-24 17:02:57 -0700401 selectPhoneAccountDialogFragment =
402 SelectPhoneAccountDialogFragment.newInstance(
twyen56f79ba2018-04-30 14:25:46 -0700403 result.getDialogOptionsBuilder().get().setCallId(callId).build(),
404 selectPhoneAccountListener);
twyena1723252018-04-24 17:02:57 -0700405 selectPhoneAccountDialogFragment.show(getFragmentManager(), Tags.SELECT_ACCOUNT_FRAGMENT);
406 },
407 throwable -> {
408 throw new RuntimeException(throwable);
409 });
twyen73a74c32018-03-07 12:12:24 -0800410
linyuhc3968e62017-11-20 17:40:50 -0800411 return true;
412 }
413
Eric Erfanianccca3152017-02-22 16:32:36 -0800414 @Override
415 protected void onSaveInstanceState(Bundle out) {
linyuh57b093b2017-11-17 14:32:32 -0800416 LogUtil.enterBlock("InCallActivity.onSaveInstanceState");
417
418 // TODO: DialpadFragment should handle this as part of its own state
linyuhc3968e62017-11-20 17:40:50 -0800419 out.putBoolean(IntentExtraNames.SHOW_DIALPAD, isDialpadVisible());
linyuh57b093b2017-11-17 14:32:32 -0800420 DialpadFragment dialpadFragment = getDialpadFragment();
421 if (dialpadFragment != null) {
linyuhc3968e62017-11-20 17:40:50 -0800422 out.putString(KeysForSavedInstance.DIALPAD_TEXT, dialpadFragment.getDtmfText());
linyuh57b093b2017-11-17 14:32:32 -0800423 }
424
linyuhc3968e62017-11-20 17:40:50 -0800425 out.putBoolean(KeysForSavedInstance.DID_SHOW_ANSWER_SCREEN, didShowAnswerScreen);
426 out.putBoolean(KeysForSavedInstance.DID_SHOW_IN_CALL_SCREEN, didShowInCallScreen);
427 out.putBoolean(KeysForSavedInstance.DID_SHOW_VIDEO_CALL_SCREEN, didShowVideoCallScreen);
wangqi153af2f2018-02-15 16:21:49 -0800428 out.putBoolean(KeysForSavedInstance.DID_SHOW_RTT_CALL_SCREEN, didShowRttCallScreen);
erfaniand05d8992018-03-20 19:42:26 -0700429 out.putBoolean(KeysForSavedInstance.DID_SHOW_SPEAK_EASY_SCREEN, didShowSpeakEasyScreen);
linyuh57b093b2017-11-17 14:32:32 -0800430
Eric Erfanianccca3152017-02-22 16:32:36 -0800431 super.onSaveInstanceState(out);
432 isVisible = false;
433 }
434
435 @Override
436 protected void onStart() {
Eric Erfanian2ca43182017-08-31 06:57:16 -0700437 Trace.beginSection("InCallActivity.onStart");
Eric Erfanianccca3152017-02-22 16:32:36 -0800438 super.onStart();
linyuh57b093b2017-11-17 14:32:32 -0800439
Eric Erfanianccca3152017-02-22 16:32:36 -0800440 isVisible = true;
441 showMainInCallFragment();
linyuh57b093b2017-11-17 14:32:32 -0800442
443 InCallPresenter.getInstance().setActivity(this);
444 enableInCallOrientationEventListener(
445 getRequestedOrientation()
446 == InCallOrientationEventListener.ACTIVITY_PREFERENCE_ALLOW_ROTATION);
447 InCallPresenter.getInstance().onActivityStarted();
448
yueg10f6e822018-01-17 15:32:18 -0800449 if (!isRecreating) {
450 InCallPresenter.getInstance().onUiShowing(true);
451 }
452
linyuh437ae952018-03-26 12:46:18 -0700453 if (isInMultiWindowMode() && !getResources().getBoolean(R.bool.incall_dialpad_allowed)) {
Eric Erfanianccca3152017-02-22 16:32:36 -0800454 // Hide the dialpad because there may not be enough room
455 showDialpadFragment(false, false);
456 }
linyuh57b093b2017-11-17 14:32:32 -0800457
Eric Erfanian2ca43182017-08-31 06:57:16 -0700458 Trace.endSection();
Eric Erfanianccca3152017-02-22 16:32:36 -0800459 }
460
461 @Override
462 protected void onResume() {
Eric Erfanian2ca43182017-08-31 06:57:16 -0700463 Trace.beginSection("InCallActivity.onResume");
Eric Erfanianccca3152017-02-22 16:32:36 -0800464 super.onResume();
linyuhc3968e62017-11-20 17:40:50 -0800465
466 if (!InCallPresenter.getInstance().isReadyForTearDown()) {
467 updateTaskDescription();
linyuhc3968e62017-11-20 17:40:50 -0800468 }
469
470 // If there is a pending request to show or hide the dialpad, handle that now.
471 if (showDialpadRequest != DIALPAD_REQUEST_NONE) {
472 if (showDialpadRequest == DIALPAD_REQUEST_SHOW) {
473 // Exit fullscreen so that the user has access to the dialpad hide/show button.
474 // This is important when showing the dialpad from within dialer.
475 InCallPresenter.getInstance().setFullScreen(false /* isFullScreen */, true /* force */);
476
477 showDialpadFragment(true /* show */, animateDialpadOnShow /* animate */);
478 animateDialpadOnShow = false;
479
480 DialpadFragment dialpadFragment = getDialpadFragment();
481 if (dialpadFragment != null) {
482 dialpadFragment.setDtmfText(dtmfTextToPrepopulate);
483 dtmfTextToPrepopulate = null;
484 }
485 } else {
486 LogUtil.i("InCallActivity.onResume", "Force-hide the dialpad");
487 if (getDialpadFragment() != null) {
488 showDialpadFragment(false /* show */, false /* animate */);
489 }
490 }
491 showDialpadRequest = DIALPAD_REQUEST_NONE;
492 }
linyuhc3968e62017-11-20 17:40:50 -0800493
linyuhc3968e62017-11-20 17:40:50 -0800494 CallList.getInstance()
495 .onInCallUiShown(getIntent().getBooleanExtra(IntentExtraNames.FOR_FULL_SCREEN, false));
496
Eric Erfanianccca3152017-02-22 16:32:36 -0800497 PseudoScreenState pseudoScreenState = InCallPresenter.getInstance().getPseudoScreenState();
498 pseudoScreenState.addListener(this);
499 onPseudoScreenStateChanged(pseudoScreenState.isOn());
Eric Erfanian2ca43182017-08-31 06:57:16 -0700500 Trace.endSection();
weijiaxu650e7cc2017-10-31 12:38:54 -0700501 // add 1 sec delay to get memory snapshot so that dialer wont react slowly on resume.
502 ThreadUtil.postDelayedOnUiThread(
weijiaxuc950a9b2017-11-06 16:39:04 -0800503 () ->
zachh7a96dc72018-02-20 22:16:03 -0800504 MetricsComponent.get(this)
505 .metrics()
506 .recordMemory(Metrics.INCALL_ACTIVITY_ON_RESUME_MEMORY_EVENT_NAME),
weijiaxu650e7cc2017-10-31 12:38:54 -0700507 1000);
Eric Erfanianccca3152017-02-22 16:32:36 -0800508 }
509
Eric Erfanianccca3152017-02-22 16:32:36 -0800510 @Override
511 protected void onPause() {
Eric Erfanian2ca43182017-08-31 06:57:16 -0700512 Trace.beginSection("InCallActivity.onPause");
Eric Erfanianccca3152017-02-22 16:32:36 -0800513 super.onPause();
linyuh57b093b2017-11-17 14:32:32 -0800514
515 DialpadFragment dialpadFragment = getDialpadFragment();
516 if (dialpadFragment != null) {
517 dialpadFragment.onDialerKeyUp(null);
518 }
519
Eric Erfanianccca3152017-02-22 16:32:36 -0800520 InCallPresenter.getInstance().getPseudoScreenState().removeListener(this);
Eric Erfanian2ca43182017-08-31 06:57:16 -0700521 Trace.endSection();
Eric Erfanianccca3152017-02-22 16:32:36 -0800522 }
523
524 @Override
525 protected void onStop() {
Eric Erfanian2ca43182017-08-31 06:57:16 -0700526 Trace.beginSection("InCallActivity.onStop");
wangqi4d705e52017-09-28 12:23:35 -0700527 isVisible = false;
Eric Erfanianccca3152017-02-22 16:32:36 -0800528 super.onStop();
linyuh57b093b2017-11-17 14:32:32 -0800529
530 // Disconnects the call waiting for a phone account when the activity is hidden (e.g., after the
531 // user presses the home button).
532 // Without this the pending call will get stuck on phone account selection and new calls can't
533 // be created.
534 // Skip this when the screen is locked since the activity may complete its current life cycle
535 // and restart.
linyuhc3968e62017-11-20 17:40:50 -0800536 if (!isRecreating && !getSystemService(KeyguardManager.class).isKeyguardLocked()) {
linyuh57b093b2017-11-17 14:32:32 -0800537 DialerCall waitingForAccountCall = CallList.getInstance().getWaitingForAccountCall();
538 if (waitingForAccountCall != null) {
539 waitingForAccountCall.disconnect();
540 }
541 }
542
543 enableInCallOrientationEventListener(false);
544 InCallPresenter.getInstance().updateIsChangingConfigurations();
545 InCallPresenter.getInstance().onActivityStopped();
linyuhc3968e62017-11-20 17:40:50 -0800546 if (!isRecreating) {
yueg10f6e822018-01-17 15:32:18 -0800547 InCallPresenter.getInstance().onUiShowing(false);
wangqie6060522018-04-05 11:47:15 -0700548 }
549 if (errorDialog != null) {
550 errorDialog.dismiss();
linyuh57b093b2017-11-17 14:32:32 -0800551 }
552
yueg10f6e822018-01-17 15:32:18 -0800553 if (isFinishing()) {
554 InCallPresenter.getInstance().unsetActivity(this);
555 }
556
Eric Erfanian2ca43182017-08-31 06:57:16 -0700557 Trace.endSection();
Eric Erfanianccca3152017-02-22 16:32:36 -0800558 }
559
560 @Override
561 protected void onDestroy() {
Eric Erfanian2ca43182017-08-31 06:57:16 -0700562 Trace.beginSection("InCallActivity.onDestroy");
Eric Erfanianccca3152017-02-22 16:32:36 -0800563 super.onDestroy();
linyuh57b093b2017-11-17 14:32:32 -0800564
565 InCallPresenter.getInstance().unsetActivity(this);
566 InCallPresenter.getInstance().updateIsChangingConfigurations();
Eric Erfanian2ca43182017-08-31 06:57:16 -0700567 Trace.endSection();
Eric Erfanianccca3152017-02-22 16:32:36 -0800568 }
569
570 @Override
571 public void finish() {
572 if (shouldCloseActivityOnFinish()) {
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700573 // When user select incall ui from recents after the call is disconnected, it tries to launch
574 // a new InCallActivity but InCallPresenter is already teared down at this point, which causes
575 // crash.
576 // By calling finishAndRemoveTask() instead of finish() the task associated with
577 // InCallActivity is cleared completely. So system won't try to create a new InCallActivity in
578 // this case.
579 //
580 // Calling finish won't clear the task and normally when an activity finishes it shouldn't
581 // clear the task since there could be parent activity in the same task that's still alive.
582 // But InCallActivity is special since it's singleInstance which means it's root activity and
583 // only instance of activity in the task. So it should be safe to also remove task when
584 // finishing.
585 // It's also necessary in the sense of it's excluded from recents. So whenever the activity
586 // finishes, the task should also be removed since it doesn't make sense to go back to it in
587 // anyway anymore.
588 super.finishAndRemoveTask();
Eric Erfanianccca3152017-02-22 16:32:36 -0800589 }
590 }
591
592 private boolean shouldCloseActivityOnFinish() {
linyuhc3968e62017-11-20 17:40:50 -0800593 if (!isVisible) {
Eric Erfanianccca3152017-02-22 16:32:36 -0800594 LogUtil.i(
595 "InCallActivity.shouldCloseActivityOnFinish",
596 "allowing activity to be closed because it's not visible");
597 return true;
598 }
599
twyen8efb4952017-10-06 16:35:54 -0700600 if (InCallPresenter.getInstance().isInCallUiLocked()) {
Eric Erfanianccca3152017-02-22 16:32:36 -0800601 LogUtil.i(
602 "InCallActivity.shouldCloseActivityOnFinish",
twyen8efb4952017-10-06 16:35:54 -0700603 "in call ui is locked, not closing activity");
Eric Erfanianccca3152017-02-22 16:32:36 -0800604 return false;
605 }
606
607 LogUtil.i(
608 "InCallActivity.shouldCloseActivityOnFinish",
twyen8efb4952017-10-06 16:35:54 -0700609 "activity is visible and has no locks, allowing activity to close");
Eric Erfanianccca3152017-02-22 16:32:36 -0800610 return true;
611 }
612
613 @Override
614 protected void onNewIntent(Intent intent) {
linyuhc3968e62017-11-20 17:40:50 -0800615 LogUtil.enterBlock("InCallActivity.onNewIntent");
Eric Erfanianccca3152017-02-22 16:32:36 -0800616
617 // If the screen is off, we need to make sure it gets turned on for incoming calls.
618 // This normally works just fine thanks to FLAG_TURN_SCREEN_ON but that only works
619 // when the activity is first created. Therefore, to ensure the screen is turned on
620 // for the call waiting case, we recreate() the current activity. There should be no jank from
621 // this since the screen is already off and will remain so until our new activity is up.
linyuhc3968e62017-11-20 17:40:50 -0800622 if (!isVisible) {
623 onNewIntent(intent, true /* isRecreating */);
Eric Erfanianccca3152017-02-22 16:32:36 -0800624 LogUtil.i("InCallActivity.onNewIntent", "Restarting InCallActivity to force screen on.");
625 recreate();
Eric Erfanian10b34a52017-05-04 08:23:17 -0700626 } else {
linyuhc3968e62017-11-20 17:40:50 -0800627 onNewIntent(intent, false /* isRecreating */);
628 }
629 }
630
yuega3305352018-01-09 11:02:47 -0800631 @VisibleForTesting
632 void onNewIntent(Intent intent, boolean isRecreating) {
linyuhc3968e62017-11-20 17:40:50 -0800633 this.isRecreating = isRecreating;
634
635 // We're being re-launched with a new Intent. Since it's possible for a single InCallActivity
636 // instance to persist indefinitely (even if we finish() ourselves), this sequence can
637 // happen any time the InCallActivity needs to be displayed.
638
639 // Stash away the new intent so that we can get it in the future by calling getIntent().
640 // Otherwise getIntent() will return the original Intent from when we first got created.
641 setIntent(intent);
642
643 // Activities are always paused before receiving a new intent, so we can count on our onResume()
644 // method being called next.
645
646 // Just like in onCreate(), handle the intent.
647 // Skip if InCallActivity is going to be recreated since this will be called in onCreate().
648 if (!isRecreating) {
649 internalResolveIntent(intent);
Eric Erfanianccca3152017-02-22 16:32:36 -0800650 }
651 }
652
653 @Override
654 public void onBackPressed() {
linyuh57b093b2017-11-17 14:32:32 -0800655 LogUtil.enterBlock("InCallActivity.onBackPressed");
656
linyuhc3968e62017-11-20 17:40:50 -0800657 if (!isVisible) {
linyuh57b093b2017-11-17 14:32:32 -0800658 return;
Eric Erfanianccca3152017-02-22 16:32:36 -0800659 }
linyuh57b093b2017-11-17 14:32:32 -0800660
661 if (!getCallCardFragmentVisible()) {
662 return;
663 }
664
665 DialpadFragment dialpadFragment = getDialpadFragment();
666 if (dialpadFragment != null && dialpadFragment.isVisible()) {
667 showDialpadFragment(false /* show */, true /* animate */);
668 return;
669 }
670
671 if (CallList.getInstance().getIncomingCall() != null) {
672 LogUtil.i(
673 "InCallActivity.onBackPressed",
674 "Ignore the press of the back key when an incoming call is ringing");
675 return;
676 }
677
678 // Nothing special to do. Fall back to the default behavior.
679 super.onBackPressed();
Eric Erfanianccca3152017-02-22 16:32:36 -0800680 }
681
682 @Override
683 public boolean onOptionsItemSelected(MenuItem item) {
684 LogUtil.i("InCallActivity.onOptionsItemSelected", "item: " + item);
685 if (item.getItemId() == android.R.id.home) {
686 onBackPressed();
687 return true;
688 }
689 return super.onOptionsItemSelected(item);
690 }
691
692 @Override
693 public boolean onKeyUp(int keyCode, KeyEvent event) {
linyuh57b093b2017-11-17 14:32:32 -0800694 DialpadFragment dialpadFragment = getDialpadFragment();
695 if (dialpadFragment != null
696 && dialpadFragment.isVisible()
697 && dialpadFragment.onDialerKeyUp(event)) {
698 return true;
699 }
700
701 if (keyCode == KeyEvent.KEYCODE_CALL) {
702 // Always consume KEYCODE_CALL to ensure the PhoneWindow won't do anything with it.
703 return true;
704 }
705
706 return super.onKeyUp(keyCode, event);
Eric Erfanianccca3152017-02-22 16:32:36 -0800707 }
708
709 @Override
710 public boolean onKeyDown(int keyCode, KeyEvent event) {
linyuh57b093b2017-11-17 14:32:32 -0800711 switch (keyCode) {
712 case KeyEvent.KEYCODE_CALL:
713 if (!InCallPresenter.getInstance().handleCallKey()) {
714 LogUtil.e(
715 "InCallActivity.onKeyDown",
716 "InCallPresenter should always handle KEYCODE_CALL in onKeyDown");
717 }
718 // Always consume KEYCODE_CALL to ensure the PhoneWindow won't do anything with it.
719 return true;
720
721 // Note that KEYCODE_ENDCALL isn't handled here as the standard system-wide handling of it
722 // is exactly what's needed, namely
723 // (1) "hang up" if there's an active call, or
724 // (2) "don't answer" if there's an incoming call.
725 // (See PhoneWindowManager for implementation details.)
726
727 case KeyEvent.KEYCODE_CAMERA:
728 // Consume KEYCODE_CAMERA since it's easy to accidentally press the camera button.
729 return true;
730
731 case KeyEvent.KEYCODE_VOLUME_UP:
732 case KeyEvent.KEYCODE_VOLUME_DOWN:
733 case KeyEvent.KEYCODE_VOLUME_MUTE:
734 // Ringer silencing handled by PhoneWindowManager.
735 break;
736
737 case KeyEvent.KEYCODE_MUTE:
738 TelecomAdapter.getInstance()
739 .mute(!AudioModeProvider.getInstance().getAudioState().isMuted());
740 return true;
741
742 case KeyEvent.KEYCODE_SLASH:
743 // When verbose logging is enabled, dump the view for debugging/testing purposes.
744 if (LogUtil.isVerboseEnabled()) {
745 View decorView = getWindow().getDecorView();
746 LogUtil.v("InCallActivity.onKeyDown", "View dump:\n%s", decorView);
747 return true;
748 }
749 break;
750
751 case KeyEvent.KEYCODE_EQUALS:
752 break;
753
754 default: // fall out
755 }
756
757 // Pass other key events to DialpadFragment's "onDialerKeyDown" method in case the user types
758 // in DTMF (Dual-tone multi-frequency signaling) code.
759 DialpadFragment dialpadFragment = getDialpadFragment();
760 if (dialpadFragment != null
761 && dialpadFragment.isVisible()
762 && dialpadFragment.onDialerKeyDown(event)) {
763 return true;
764 }
765
766 return super.onKeyDown(keyCode, event);
Eric Erfanianccca3152017-02-22 16:32:36 -0800767 }
768
769 public boolean isInCallScreenAnimating() {
770 return false;
771 }
772
773 public void showConferenceFragment(boolean show) {
774 if (show) {
775 startActivity(new Intent(this, ManageConferenceActivity.class));
776 }
777 }
778
linyuhc3968e62017-11-20 17:40:50 -0800779 public void showDialpadFragment(boolean show, boolean animate) {
780 if (show == isDialpadVisible()) {
781 return;
Eric Erfanianccca3152017-02-22 16:32:36 -0800782 }
linyuhc3968e62017-11-20 17:40:50 -0800783
784 FragmentManager dialpadFragmentManager = getDialpadFragmentManager();
785 if (dialpadFragmentManager == null) {
786 LogUtil.i("InCallActivity.showDialpadFragment", "Unable to obtain a FragmentManager");
787 return;
788 }
789
790 if (!animate) {
791 if (show) {
792 showDialpadFragment();
793 } else {
794 hideDialpadFragment();
795 }
796 } else {
797 if (show) {
798 showDialpadFragment();
799 getDialpadFragment().animateShowDialpad();
800 }
801 getDialpadFragment()
802 .getView()
803 .startAnimation(show ? dialpadSlideInAnimation : dialpadSlideOutAnimation);
804 }
805
806 ProximitySensor sensor = InCallPresenter.getInstance().getProximitySensor();
807 if (sensor != null) {
808 sensor.onDialpadVisible(show);
809 }
810 showDialpadRequest = DIALPAD_REQUEST_NONE;
linyuhc3968e62017-11-20 17:40:50 -0800811 }
812
813 private void showDialpadFragment() {
814 FragmentManager dialpadFragmentManager = getDialpadFragmentManager();
815 if (dialpadFragmentManager == null) {
816 return;
817 }
818
819 FragmentTransaction transaction = dialpadFragmentManager.beginTransaction();
820 DialpadFragment dialpadFragment = getDialpadFragment();
821 if (dialpadFragment == null) {
wangqifd4c9f72018-03-08 18:21:50 -0800822 dialpadFragment = new DialpadFragment();
823 transaction.add(getDialpadContainerId(), dialpadFragment, Tags.DIALPAD_FRAGMENT);
linyuhc3968e62017-11-20 17:40:50 -0800824 } else {
825 transaction.show(dialpadFragment);
calderwoodrad5883872017-12-12 15:29:12 -0800826 dialpadFragment.setUserVisibleHint(true);
linyuhc3968e62017-11-20 17:40:50 -0800827 }
wangqifd4c9f72018-03-08 18:21:50 -0800828 // RTT call screen doesn't show end call button inside dialpad, thus the space reserved for end
829 // call button should be removed.
830 dialpadFragment.setShouldShowEndCallSpace(didShowInCallScreen);
linyuhc3968e62017-11-20 17:40:50 -0800831 transaction.commitAllowingStateLoss();
832 dialpadFragmentManager.executePendingTransactions();
833
834 Logger.get(this).logScreenView(ScreenEvent.Type.INCALL_DIALPAD, this);
wangqi73ed6132018-05-21 15:57:36 -0700835 getInCallOrRttCallScreen().onInCallScreenDialpadVisibilityChange(true);
linyuhc3968e62017-11-20 17:40:50 -0800836 }
837
838 private void hideDialpadFragment() {
839 FragmentManager dialpadFragmentManager = getDialpadFragmentManager();
840 if (dialpadFragmentManager == null) {
841 return;
842 }
843
calderwoodrad5883872017-12-12 15:29:12 -0800844 DialpadFragment dialpadFragment = getDialpadFragment();
linyuhc3968e62017-11-20 17:40:50 -0800845 if (dialpadFragment != null) {
846 FragmentTransaction transaction = dialpadFragmentManager.beginTransaction();
847 transaction.hide(dialpadFragment);
848 transaction.commitAllowingStateLoss();
849 dialpadFragmentManager.executePendingTransactions();
calderwoodrad5883872017-12-12 15:29:12 -0800850 dialpadFragment.setUserVisibleHint(false);
wangqi73ed6132018-05-21 15:57:36 -0700851 getInCallOrRttCallScreen().onInCallScreenDialpadVisibilityChange(false);
linyuhc3968e62017-11-20 17:40:50 -0800852 }
Eric Erfanianccca3152017-02-22 16:32:36 -0800853 }
854
855 public boolean isDialpadVisible() {
linyuh69a25062017-11-15 16:18:51 -0800856 DialpadFragment dialpadFragment = getDialpadFragment();
calderwoodraa584bcd2018-01-24 12:19:56 -0800857 return dialpadFragment != null
858 && dialpadFragment.isAdded()
859 && !dialpadFragment.isHidden()
860 && dialpadFragment.getView() != null
861 && dialpadFragment.getUserVisibleHint();
linyuh69a25062017-11-15 16:18:51 -0800862 }
863
linyuhc3968e62017-11-20 17:40:50 -0800864 /** Returns the {@link DialpadFragment} that's shown by this activity, or {@code null} */
linyuh69a25062017-11-15 16:18:51 -0800865 @Nullable
linyuhc3968e62017-11-20 17:40:50 -0800866 private DialpadFragment getDialpadFragment() {
linyuh69a25062017-11-15 16:18:51 -0800867 FragmentManager fragmentManager = getDialpadFragmentManager();
868 if (fragmentManager == null) {
869 return null;
870 }
linyuhc3968e62017-11-20 17:40:50 -0800871 return (DialpadFragment) fragmentManager.findFragmentByTag(Tags.DIALPAD_FRAGMENT);
Eric Erfanianccca3152017-02-22 16:32:36 -0800872 }
873
874 public void onForegroundCallChanged(DialerCall newForegroundCall) {
linyuh57b093b2017-11-17 14:32:32 -0800875 updateTaskDescription();
876
877 if (newForegroundCall == null || !didShowAnswerScreen) {
Eric Erfanianccca3152017-02-22 16:32:36 -0800878 LogUtil.v("InCallActivity.onForegroundCallChanged", "resetting background color");
linyuh57b093b2017-11-17 14:32:32 -0800879 updateWindowBackgroundColor(0 /* progress */);
Eric Erfanianccca3152017-02-22 16:32:36 -0800880 }
881 }
882
linyuhc3968e62017-11-20 17:40:50 -0800883 private void updateTaskDescription() {
linyuh57b093b2017-11-17 14:32:32 -0800884 int color =
885 getResources().getBoolean(R.bool.is_layout_landscape)
886 ? ResourcesCompat.getColor(
887 getResources(), R.color.statusbar_background_color, getTheme())
888 : InCallPresenter.getInstance().getThemeColorManager().getSecondaryColor();
889 setTaskDescription(
890 new TaskDescription(
891 getResources().getString(R.string.notification_ongoing_call), null /* icon */, color));
892 }
893
Eric Erfanianccca3152017-02-22 16:32:36 -0800894 public void updateWindowBackgroundColor(@FloatRange(from = -1f, to = 1.0f) float progress) {
895 ThemeColorManager themeColorManager = InCallPresenter.getInstance().getThemeColorManager();
896 @ColorInt int top;
897 @ColorInt int middle;
898 @ColorInt int bottom;
899 @ColorInt int gray = 0x66000000;
900
linyuh437ae952018-03-26 12:46:18 -0700901 if (isInMultiWindowMode()) {
Eric Erfanianccca3152017-02-22 16:32:36 -0800902 top = themeColorManager.getBackgroundColorSolid();
903 middle = themeColorManager.getBackgroundColorSolid();
904 bottom = themeColorManager.getBackgroundColorSolid();
905 } else {
906 top = themeColorManager.getBackgroundColorTop();
907 middle = themeColorManager.getBackgroundColorMiddle();
908 bottom = themeColorManager.getBackgroundColorBottom();
909 }
910
911 if (progress < 0) {
912 float correctedProgress = Math.abs(progress);
913 top = ColorUtils.blendARGB(top, gray, correctedProgress);
914 middle = ColorUtils.blendARGB(middle, gray, correctedProgress);
915 bottom = ColorUtils.blendARGB(bottom, gray, correctedProgress);
916 }
917
918 boolean backgroundDirty = false;
919 if (backgroundDrawable == null) {
920 backgroundDrawableColors = new int[] {top, middle, bottom};
921 backgroundDrawable = new GradientDrawable(Orientation.TOP_BOTTOM, backgroundDrawableColors);
922 backgroundDirty = true;
923 } else {
924 if (backgroundDrawableColors[0] != top) {
925 backgroundDrawableColors[0] = top;
926 backgroundDirty = true;
927 }
928 if (backgroundDrawableColors[1] != middle) {
929 backgroundDrawableColors[1] = middle;
930 backgroundDirty = true;
931 }
932 if (backgroundDrawableColors[2] != bottom) {
933 backgroundDrawableColors[2] = bottom;
934 backgroundDirty = true;
935 }
936 if (backgroundDirty) {
937 backgroundDrawable.setColors(backgroundDrawableColors);
938 }
939 }
940
941 if (backgroundDirty) {
942 getWindow().setBackgroundDrawable(backgroundDrawable);
943 }
944 }
945
946 public boolean isVisible() {
947 return isVisible;
948 }
949
950 public boolean getCallCardFragmentVisible() {
erfaniand05d8992018-03-20 19:42:26 -0700951 return didShowInCallScreen
952 || didShowVideoCallScreen
953 || didShowRttCallScreen
954 || didShowSpeakEasyScreen;
Eric Erfanianccca3152017-02-22 16:32:36 -0800955 }
956
957 public void dismissKeyguard(boolean dismiss) {
linyuh9c327da2017-11-14 12:33:48 -0800958 if (dismissKeyguard == dismiss) {
959 return;
960 }
961
962 dismissKeyguard = dismiss;
963 if (dismiss) {
964 getWindow().addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);
965 } else {
966 getWindow().clearFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);
967 }
Eric Erfanianccca3152017-02-22 16:32:36 -0800968 }
969
linyuhc3968e62017-11-20 17:40:50 -0800970 public void showDialogForPostCharWait(String callId, String chars) {
yuega489f512018-04-25 12:01:09 -0700971 PostCharDialogFragment fragment = new PostCharDialogFragment(callId, chars);
972 fragment.show(getSupportFragmentManager(), Tags.POST_CHAR_DIALOG_FRAGMENT);
Eric Erfanianccca3152017-02-22 16:32:36 -0800973 }
974
linyuh7b86f562017-11-16 11:24:09 -0800975 public void showDialogOrToastForDisconnectedCall(DisconnectMessage disconnectMessage) {
976 LogUtil.i(
977 "InCallActivity.showDialogOrToastForDisconnectedCall",
978 "disconnect cause: %s",
979 disconnectMessage);
980
981 if (disconnectMessage.dialog == null || isFinishing()) {
982 return;
983 }
984
985 dismissPendingDialogs();
986
987 // Show a toast if the app is in background when a dialog can't be visible.
988 if (!isVisible()) {
989 Toast.makeText(getApplicationContext(), disconnectMessage.toastMessage, Toast.LENGTH_LONG)
990 .show();
991 return;
992 }
993
994 // Show the dialog.
linyuhc3968e62017-11-20 17:40:50 -0800995 errorDialog = disconnectMessage.dialog;
linyuh7b86f562017-11-16 11:24:09 -0800996 InCallUiLock lock = InCallPresenter.getInstance().acquireInCallUiLock("showErrorDialog");
997 disconnectMessage.dialog.setOnDismissListener(
998 dialogInterface -> {
999 lock.release();
1000 onDialogDismissed();
1001 });
1002 disconnectMessage.dialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
1003 disconnectMessage.dialog.show();
1004 }
1005
1006 private void onDialogDismissed() {
linyuhc3968e62017-11-20 17:40:50 -08001007 errorDialog = null;
linyuh7b86f562017-11-16 11:24:09 -08001008 CallList.getInstance().onErrorDialogDismissed();
Eric Erfanianccca3152017-02-22 16:32:36 -08001009 }
1010
1011 public void dismissPendingDialogs() {
linyuhc3968e62017-11-20 17:40:50 -08001012 LogUtil.enterBlock("InCallActivity.dismissPendingDialogs");
linyuhf99f6302017-11-15 11:23:51 -08001013
1014 if (!isVisible) {
1015 // Defer the dismissing action as the activity is not visible and onSaveInstanceState may have
1016 // been called.
Eric Erfanianccca3152017-02-22 16:32:36 -08001017 LogUtil.i(
1018 "InCallActivity.dismissPendingDialogs", "defer actions since activity is not visible");
1019 needDismissPendingDialogs = true;
linyuhf99f6302017-11-15 11:23:51 -08001020 return;
Eric Erfanianccca3152017-02-22 16:32:36 -08001021 }
linyuhf99f6302017-11-15 11:23:51 -08001022
1023 // Dismiss the error dialog
linyuhf99f6302017-11-15 11:23:51 -08001024 if (errorDialog != null) {
1025 errorDialog.dismiss();
linyuhc3968e62017-11-20 17:40:50 -08001026 errorDialog = null;
linyuhf99f6302017-11-15 11:23:51 -08001027 }
1028
1029 // Dismiss the phone account selection dialog
linyuhf99f6302017-11-15 11:23:51 -08001030 if (selectPhoneAccountDialogFragment != null) {
1031 selectPhoneAccountDialogFragment.dismiss();
linyuhc3968e62017-11-20 17:40:50 -08001032 selectPhoneAccountDialogFragment = null;
linyuhf99f6302017-11-15 11:23:51 -08001033 }
1034
1035 // Dismiss the dialog for international call on WiFi
1036 InternationalCallOnWifiDialogFragment internationalCallOnWifiFragment =
1037 (InternationalCallOnWifiDialogFragment)
linyuhc3968e62017-11-20 17:40:50 -08001038 getSupportFragmentManager().findFragmentByTag(Tags.INTERNATIONAL_CALL_ON_WIFI);
linyuhf99f6302017-11-15 11:23:51 -08001039 if (internationalCallOnWifiFragment != null) {
1040 internationalCallOnWifiFragment.dismiss();
1041 }
1042
1043 // Dismiss the answer screen
1044 AnswerScreen answerScreen = getAnswerScreen();
1045 if (answerScreen != null) {
1046 answerScreen.dismissPendingDialogs();
1047 }
1048
1049 needDismissPendingDialogs = false;
Eric Erfanianccca3152017-02-22 16:32:36 -08001050 }
1051
linyuhc3968e62017-11-20 17:40:50 -08001052 private void enableInCallOrientationEventListener(boolean enable) {
linyuh69a25062017-11-15 16:18:51 -08001053 if (enable) {
1054 inCallOrientationEventListener.enable(true /* notifyDeviceOrientationChange */);
1055 } else {
1056 inCallOrientationEventListener.disable();
1057 }
Eric Erfanianccca3152017-02-22 16:32:36 -08001058 }
1059
1060 public void setExcludeFromRecents(boolean exclude) {
linyuhc3968e62017-11-20 17:40:50 -08001061 int taskId = getTaskId();
1062
1063 List<AppTask> tasks = getSystemService(ActivityManager.class).getAppTasks();
1064 for (AppTask task : tasks) {
1065 try {
1066 if (task.getTaskInfo().id == taskId) {
1067 task.setExcludeFromRecents(exclude);
1068 }
1069 } catch (RuntimeException e) {
1070 LogUtil.e("InCallActivity.setExcludeFromRecents", "RuntimeException:\n%s", e);
1071 }
1072 }
Eric Erfanianccca3152017-02-22 16:32:36 -08001073 }
1074
Eric Erfanianccca3152017-02-22 16:32:36 -08001075 @Nullable
1076 public FragmentManager getDialpadFragmentManager() {
wangqifd4c9f72018-03-08 18:21:50 -08001077 InCallScreen inCallScreen = getInCallOrRttCallScreen();
Eric Erfanianccca3152017-02-22 16:32:36 -08001078 if (inCallScreen != null) {
1079 return inCallScreen.getInCallScreenFragment().getChildFragmentManager();
1080 }
1081 return null;
1082 }
1083
1084 public int getDialpadContainerId() {
wangqifd4c9f72018-03-08 18:21:50 -08001085 return getInCallOrRttCallScreen().getAnswerAndDialpadContainerResourceId();
Eric Erfanianccca3152017-02-22 16:32:36 -08001086 }
1087
1088 @Override
1089 public AnswerScreenDelegate newAnswerScreenDelegate(AnswerScreen answerScreen) {
1090 DialerCall call = CallList.getInstance().getCallById(answerScreen.getCallId());
1091 if (call == null) {
1092 // This is a work around for a bug where we attempt to create a new delegate after the call
1093 // has already been removed. An example of when this can happen is:
1094 // 1. incoming video call in landscape mode
1095 // 2. remote party hangs up
1096 // 3. activity switches from landscape to portrait
1097 // At step #3 the answer fragment will try to create a new answer delegate but the call won't
1098 // exist. In this case we'll simply return a stub delegate that does nothing. This is ok
1099 // because this new state is transient and the activity will be destroyed soon.
1100 LogUtil.i("InCallActivity.onPrimaryCallStateChanged", "call doesn't exist, using stub");
1101 return new AnswerScreenPresenterStub();
1102 } else {
1103 return new AnswerScreenPresenter(
1104 this, answerScreen, CallList.getInstance().getCallById(answerScreen.getCallId()));
1105 }
1106 }
1107
1108 @Override
1109 public InCallScreenDelegate newInCallScreenDelegate() {
1110 return new CallCardPresenter(this);
1111 }
1112
1113 @Override
1114 public InCallButtonUiDelegate newInCallButtonUiDelegate() {
1115 return new CallButtonPresenter(this);
1116 }
1117
1118 @Override
Eric Erfanian90508232017-03-24 09:31:16 -07001119 public VideoCallScreenDelegate newVideoCallScreenDelegate(VideoCallScreen videoCallScreen) {
1120 DialerCall dialerCall = CallList.getInstance().getCallById(videoCallScreen.getCallId());
1121 if (dialerCall != null && dialerCall.getVideoTech().shouldUseSurfaceView()) {
1122 return dialerCall.getVideoTech().createVideoCallScreenDelegate(this, videoCallScreen);
1123 }
Eric Erfanianccca3152017-02-22 16:32:36 -08001124 return new VideoCallPresenter();
1125 }
1126
1127 public void onPrimaryCallStateChanged() {
Eric Erfanian2ca43182017-08-31 06:57:16 -07001128 Trace.beginSection("InCallActivity.onPrimaryCallStateChanged");
Eric Erfanianccca3152017-02-22 16:32:36 -08001129 showMainInCallFragment();
Eric Erfanian2ca43182017-08-31 06:57:16 -07001130 Trace.endSection();
Eric Erfanianccca3152017-02-22 16:32:36 -08001131 }
1132
linyuh7b86f562017-11-16 11:24:09 -08001133 public void showDialogOrToastForWifiHandoverFailure(DialerCall call) {
1134 if (call.showWifiHandoverAlertAsToast()) {
1135 Toast.makeText(this, R.string.video_call_lte_to_wifi_failed_message, Toast.LENGTH_SHORT)
1136 .show();
1137 return;
1138 }
1139
1140 dismissPendingDialogs();
1141
1142 AlertDialog.Builder builder =
1143 new AlertDialog.Builder(this).setTitle(R.string.video_call_lte_to_wifi_failed_title);
1144
1145 // This allows us to use the theme of the dialog instead of the activity
1146 View dialogCheckBoxView =
1147 View.inflate(builder.getContext(), R.layout.video_call_lte_to_wifi_failed, null /* root */);
1148 CheckBox wifiHandoverFailureCheckbox =
1149 (CheckBox) dialogCheckBoxView.findViewById(R.id.video_call_lte_to_wifi_failed_checkbox);
1150 wifiHandoverFailureCheckbox.setChecked(false);
1151
1152 InCallUiLock lock = InCallPresenter.getInstance().acquireInCallUiLock("WifiFailedDialog");
linyuhc3968e62017-11-20 17:40:50 -08001153 errorDialog =
linyuh7b86f562017-11-16 11:24:09 -08001154 builder
1155 .setView(dialogCheckBoxView)
1156 .setMessage(R.string.video_call_lte_to_wifi_failed_message)
1157 .setOnCancelListener(dialogInterface -> onDialogDismissed())
1158 .setPositiveButton(
1159 android.R.string.ok,
1160 (dialogInterface, id) -> {
1161 call.setDoNotShowDialogForHandoffToWifiFailure(
1162 wifiHandoverFailureCheckbox.isChecked());
1163 dialogInterface.cancel();
1164 onDialogDismissed();
1165 })
1166 .setOnDismissListener(dialogInterface -> lock.release())
1167 .create();
linyuh7b86f562017-11-16 11:24:09 -08001168 errorDialog.show();
Eric Erfanianccca3152017-02-22 16:32:36 -08001169 }
1170
linyuh7b86f562017-11-16 11:24:09 -08001171 public void showDialogForInternationalCallOnWifi(@NonNull DialerCall call) {
linyuh7b86f562017-11-16 11:24:09 -08001172 InternationalCallOnWifiDialogFragment fragment =
yuegb47528e2018-04-24 12:12:57 -07001173 InternationalCallOnWifiDialogFragment.newInstance(call.getId());
linyuhc3968e62017-11-20 17:40:50 -08001174 fragment.show(getSupportFragmentManager(), Tags.INTERNATIONAL_CALL_ON_WIFI);
Eric Erfanianc857f902017-05-15 14:05:33 -07001175 }
1176
wangqibc28ea72018-04-02 16:23:00 -07001177 public void showDialogForRttRequest(DialerCall call, int rttRequestId) {
1178 LogUtil.enterBlock("InCallActivity.showDialogForRttRequest");
wangqifb0cfff2018-06-05 11:51:01 -07001179 rttRequestDialogFragment = RttRequestDialogFragment.newInstance(call.getId(), rttRequestId);
1180 rttRequestDialogFragment.show(getSupportFragmentManager(), Tags.RTT_REQUEST_DIALOG);
wangqibc28ea72018-04-02 16:23:00 -07001181 }
1182
Eric Erfanianccca3152017-02-22 16:32:36 -08001183 public void setAllowOrientationChange(boolean allowOrientationChange) {
wangqi9982f0d2017-10-11 17:46:07 -07001184 if (this.allowOrientationChange == allowOrientationChange) {
1185 return;
1186 }
1187 this.allowOrientationChange = allowOrientationChange;
Eric Erfanianccca3152017-02-22 16:32:36 -08001188 if (!allowOrientationChange) {
1189 setRequestedOrientation(InCallOrientationEventListener.ACTIVITY_PREFERENCE_DISALLOW_ROTATION);
1190 } else {
1191 setRequestedOrientation(InCallOrientationEventListener.ACTIVITY_PREFERENCE_ALLOW_ROTATION);
1192 }
1193 enableInCallOrientationEventListener(allowOrientationChange);
1194 }
1195
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001196 public void hideMainInCallFragment() {
linyuhc3968e62017-11-20 17:40:50 -08001197 LogUtil.enterBlock("InCallActivity.hideMainInCallFragment");
1198 if (getCallCardFragmentVisible()) {
Eric Erfanianccca3152017-02-22 16:32:36 -08001199 FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
1200 hideInCallScreenFragment(transaction);
1201 hideVideoCallScreenFragment(transaction);
1202 transaction.commitAllowingStateLoss();
1203 getSupportFragmentManager().executePendingTransactions();
1204 }
1205 }
1206
1207 private void showMainInCallFragment() {
Eric Erfanian2ca43182017-08-31 06:57:16 -07001208 Trace.beginSection("InCallActivity.showMainInCallFragment");
Eric Erfanianccca3152017-02-22 16:32:36 -08001209 // If the activity's onStart method hasn't been called yet then defer doing any work.
1210 if (!isVisible) {
1211 LogUtil.i("InCallActivity.showMainInCallFragment", "not visible yet/anymore");
Eric Erfanian2ca43182017-08-31 06:57:16 -07001212 Trace.endSection();
Eric Erfanianccca3152017-02-22 16:32:36 -08001213 return;
1214 }
1215
1216 // Don't let this be reentrant.
1217 if (isInShowMainInCallFragment) {
1218 LogUtil.i("InCallActivity.showMainInCallFragment", "already in method, bailing");
Eric Erfanian2ca43182017-08-31 06:57:16 -07001219 Trace.endSection();
Eric Erfanianccca3152017-02-22 16:32:36 -08001220 return;
1221 }
1222
1223 isInShowMainInCallFragment = true;
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001224 ShouldShowUiResult shouldShowAnswerUi = getShouldShowAnswerUi();
1225 ShouldShowUiResult shouldShowVideoUi = getShouldShowVideoUi();
wangqi219b8702018-02-13 09:34:41 -08001226 ShouldShowUiResult shouldShowRttUi = getShouldShowRttUi();
erfaniand05d8992018-03-20 19:42:26 -07001227 ShouldShowUiResult shouldShowSpeakEasyUi = getShouldShowSpeakEasyUi();
Eric Erfanianccca3152017-02-22 16:32:36 -08001228 LogUtil.i(
1229 "InCallActivity.showMainInCallFragment",
uabdullah56a4cda2018-05-10 16:38:35 -07001230 "shouldShowAnswerUi: %b, shouldShowRttUi: %b, shouldShowVideoUi: %b, "
1231 + "shouldShowSpeakEasyUi: %b, didShowAnswerScreen: %b, didShowInCallScreen: %b, "
1232 + "didShowRttCallScreen: %b, didShowVideoCallScreen: %b, didShowSpeakEasyScreen: %b",
Eric Erfanianccca3152017-02-22 16:32:36 -08001233 shouldShowAnswerUi.shouldShow,
wangqi219b8702018-02-13 09:34:41 -08001234 shouldShowRttUi.shouldShow,
Eric Erfanian10b34a52017-05-04 08:23:17 -07001235 shouldShowVideoUi.shouldShow,
uabdullah56a4cda2018-05-10 16:38:35 -07001236 shouldShowSpeakEasyUi.shouldShow,
Eric Erfanianccca3152017-02-22 16:32:36 -08001237 didShowAnswerScreen,
1238 didShowInCallScreen,
wangqi219b8702018-02-13 09:34:41 -08001239 didShowRttCallScreen,
erfaniand05d8992018-03-20 19:42:26 -07001240 didShowVideoCallScreen,
1241 didShowSpeakEasyScreen);
Eric Erfanianccca3152017-02-22 16:32:36 -08001242 // Only video call ui allows orientation change.
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001243 setAllowOrientationChange(shouldShowVideoUi.shouldShow);
Eric Erfanianccca3152017-02-22 16:32:36 -08001244
1245 FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
wangqi219b8702018-02-13 09:34:41 -08001246 boolean didChange;
Eric Erfanianccca3152017-02-22 16:32:36 -08001247 if (shouldShowAnswerUi.shouldShow) {
wangqi219b8702018-02-13 09:34:41 -08001248 didChange = hideInCallScreenFragment(transaction);
1249 didChange |= hideVideoCallScreenFragment(transaction);
1250 didChange |= hideRttCallScreenFragment(transaction);
erfaniand05d8992018-03-20 19:42:26 -07001251 didChange |= hideSpeakEasyFragment(transaction);
wangqi219b8702018-02-13 09:34:41 -08001252 didChange |= showAnswerScreenFragment(transaction, shouldShowAnswerUi.call);
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001253 } else if (shouldShowVideoUi.shouldShow) {
wangqi219b8702018-02-13 09:34:41 -08001254 didChange = hideInCallScreenFragment(transaction);
1255 didChange |= showVideoCallScreenFragment(transaction, shouldShowVideoUi.call);
1256 didChange |= hideRttCallScreenFragment(transaction);
erfaniand05d8992018-03-20 19:42:26 -07001257 didChange |= hideSpeakEasyFragment(transaction);
wangqi219b8702018-02-13 09:34:41 -08001258 didChange |= hideAnswerScreenFragment(transaction);
1259 } else if (shouldShowRttUi.shouldShow) {
1260 didChange = hideInCallScreenFragment(transaction);
1261 didChange |= hideVideoCallScreenFragment(transaction);
1262 didChange |= hideAnswerScreenFragment(transaction);
erfaniand05d8992018-03-20 19:42:26 -07001263 didChange |= hideSpeakEasyFragment(transaction);
wangqi219b8702018-02-13 09:34:41 -08001264 didChange |= showRttCallScreenFragment(transaction, shouldShowRttUi.call);
erfaniand05d8992018-03-20 19:42:26 -07001265 } else if (shouldShowSpeakEasyUi.shouldShow) {
1266 didChange = hideInCallScreenFragment(transaction);
1267 didChange |= hideVideoCallScreenFragment(transaction);
1268 didChange |= hideAnswerScreenFragment(transaction);
1269 didChange |= hideRttCallScreenFragment(transaction);
1270 didChange |= showSpeakEasyFragment(transaction, shouldShowSpeakEasyUi.call);
Eric Erfanianccca3152017-02-22 16:32:36 -08001271 } else {
wangqi219b8702018-02-13 09:34:41 -08001272 didChange = showInCallScreenFragment(transaction);
1273 didChange |= hideVideoCallScreenFragment(transaction);
1274 didChange |= hideRttCallScreenFragment(transaction);
erfaniand05d8992018-03-20 19:42:26 -07001275 didChange |= hideSpeakEasyFragment(transaction);
wangqi219b8702018-02-13 09:34:41 -08001276 didChange |= hideAnswerScreenFragment(transaction);
Eric Erfanianccca3152017-02-22 16:32:36 -08001277 }
1278
wangqi219b8702018-02-13 09:34:41 -08001279 if (didChange) {
Eric Erfanian2ca43182017-08-31 06:57:16 -07001280 Trace.beginSection("InCallActivity.commitTransaction");
Eric Erfanianccca3152017-02-22 16:32:36 -08001281 transaction.commitNow();
Eric Erfanian2ca43182017-08-31 06:57:16 -07001282 Trace.endSection();
Eric Erfanianccca3152017-02-22 16:32:36 -08001283 Logger.get(this).logScreenView(ScreenEvent.Type.INCALL, this);
1284 }
1285 isInShowMainInCallFragment = false;
Eric Erfanian2ca43182017-08-31 06:57:16 -07001286 Trace.endSection();
Eric Erfanianccca3152017-02-22 16:32:36 -08001287 }
1288
erfaniand05d8992018-03-20 19:42:26 -07001289 private boolean showSpeakEasyFragment(FragmentTransaction transaction, DialerCall call) {
1290
erfaniand05d8992018-03-20 19:42:26 -07001291 if (didShowSpeakEasyScreen) {
erfanian612d13a2018-04-04 15:27:57 -07001292 if (lastShownSpeakEasyScreenUniqueCallid.equals(call.getUniqueCallId())) {
erfanian12243de2018-04-17 12:17:08 -07001293 LogUtil.i("InCallActivity.showSpeakEasyFragment", "found existing fragment");
erfanian612d13a2018-04-04 15:27:57 -07001294 return false;
1295 }
1296 hideSpeakEasyFragment(transaction);
erfanian12243de2018-04-17 12:17:08 -07001297 LogUtil.i("InCallActivity.showSpeakEasyFragment", "hid existing fragment");
erfaniand05d8992018-03-20 19:42:26 -07001298 }
1299
1300 Optional<Fragment> speakEasyFragment = speakEasyCallManager.getSpeakEasyFragment(call);
1301 if (speakEasyFragment.isPresent()) {
1302 transaction.add(R.id.main, speakEasyFragment.get(), Tags.SPEAK_EASY_SCREEN);
1303 didShowSpeakEasyScreen = true;
erfanian612d13a2018-04-04 15:27:57 -07001304 lastShownSpeakEasyScreenUniqueCallid = call.getUniqueCallId();
erfanian12243de2018-04-17 12:17:08 -07001305 LogUtil.i(
1306 "InCallActivity.showSpeakEasyFragment",
1307 "set fragment for call %s",
1308 lastShownSpeakEasyScreenUniqueCallid);
erfaniand05d8992018-03-20 19:42:26 -07001309 return true;
1310 }
1311 return false;
1312 }
1313
1314 private Fragment getSpeakEasyScreen() {
1315 return getSupportFragmentManager().findFragmentByTag(Tags.SPEAK_EASY_SCREEN);
1316 }
1317
1318 private boolean hideSpeakEasyFragment(FragmentTransaction transaction) {
1319 if (!didShowSpeakEasyScreen) {
1320 return false;
1321 }
1322
1323 Fragment speakEasyFragment = getSpeakEasyScreen();
1324
1325 if (speakEasyFragment != null) {
1326 transaction.remove(speakEasyFragment);
1327 didShowSpeakEasyScreen = false;
1328 return true;
1329 }
1330 return false;
1331 }
1332
erfanian12243de2018-04-17 12:17:08 -07001333 @VisibleForTesting
erfaniand05d8992018-03-20 19:42:26 -07001334 public void setSpeakEasyCallManager(SpeakEasyCallManager speakEasyCallManager) {
erfanian87dbb622018-04-04 15:43:00 -07001335 this.speakEasyCallManager = speakEasyCallManager;
erfaniand05d8992018-03-20 19:42:26 -07001336 }
1337
erfanian12243de2018-04-17 12:17:08 -07001338 @Nullable
erfaniand05d8992018-03-20 19:42:26 -07001339 public SpeakEasyCallManager getSpeakEasyCallManager() {
erfanian12243de2018-04-17 12:17:08 -07001340 if (this.speakEasyCallManager == null) {
1341 this.speakEasyCallManager = InCallPresenter.getInstance().getSpeakEasyCallManager();
1342 }
erfaniand05d8992018-03-20 19:42:26 -07001343 return speakEasyCallManager;
1344 }
1345
1346 private ShouldShowUiResult getShouldShowSpeakEasyUi() {
1347 SpeakEasyCallManager speakEasyCallManager = getSpeakEasyCallManager();
1348
1349 if (speakEasyCallManager == null) {
1350 return new ShouldShowUiResult(false, null);
1351 }
1352
erfanian3bb7cb62018-04-11 09:01:15 -07001353 DialerCall call =
1354 CallList.getInstance().getIncomingCall() != null
1355 ? CallList.getInstance().getIncomingCall()
1356 : CallList.getInstance().getActiveCall();
erfaniand05d8992018-03-20 19:42:26 -07001357
1358 if (call == null) {
1359 return new ShouldShowUiResult(false, call);
1360 }
1361
1362 if (!call.isSpeakEasyCall() || !call.isSpeakEasyEligible()) {
1363 return new ShouldShowUiResult(false, call);
1364 }
1365
1366 Optional<Fragment> speakEasyFragment = speakEasyCallManager.getSpeakEasyFragment(call);
1367
1368 if (!speakEasyFragment.isPresent()) {
1369 return new ShouldShowUiResult(false, call);
1370 }
1371 return new ShouldShowUiResult(true, call);
1372 }
1373
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001374 private ShouldShowUiResult getShouldShowAnswerUi() {
Eric Erfanianccca3152017-02-22 16:32:36 -08001375 DialerCall call = CallList.getInstance().getIncomingCall();
erfanian3bb7cb62018-04-11 09:01:15 -07001376 if (call != null && !call.isSpeakEasyCall()) {
Eric Erfanianccca3152017-02-22 16:32:36 -08001377 LogUtil.i("InCallActivity.getShouldShowAnswerUi", "found incoming call");
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001378 return new ShouldShowUiResult(true, call);
Eric Erfanianccca3152017-02-22 16:32:36 -08001379 }
1380
1381 call = CallList.getInstance().getVideoUpgradeRequestCall();
1382 if (call != null) {
1383 LogUtil.i("InCallActivity.getShouldShowAnswerUi", "found video upgrade request");
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001384 return new ShouldShowUiResult(true, call);
Eric Erfanianccca3152017-02-22 16:32:36 -08001385 }
1386
1387 // Check if we're showing the answer screen and the call is disconnected. If this condition is
1388 // true then we won't switch from the answer UI to the in call UI. This prevents flicker when
1389 // the user rejects an incoming call.
1390 call = CallList.getInstance().getFirstCall();
1391 if (call == null) {
1392 call = CallList.getInstance().getBackgroundCall();
1393 }
wangqibb94ca62018-04-27 14:34:04 -07001394 if (didShowAnswerScreen && (call == null || call.getState() == DialerCallState.DISCONNECTED)) {
Eric Erfanianccca3152017-02-22 16:32:36 -08001395 LogUtil.i("InCallActivity.getShouldShowAnswerUi", "found disconnecting incoming call");
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001396 return new ShouldShowUiResult(true, call);
Eric Erfanianccca3152017-02-22 16:32:36 -08001397 }
1398
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001399 return new ShouldShowUiResult(false, null);
Eric Erfanianccca3152017-02-22 16:32:36 -08001400 }
1401
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001402 private static ShouldShowUiResult getShouldShowVideoUi() {
Eric Erfanianccca3152017-02-22 16:32:36 -08001403 DialerCall call = CallList.getInstance().getFirstCall();
1404 if (call == null) {
1405 LogUtil.i("InCallActivity.getShouldShowVideoUi", "null call");
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001406 return new ShouldShowUiResult(false, null);
Eric Erfanianccca3152017-02-22 16:32:36 -08001407 }
1408
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001409 if (call.isVideoCall()) {
Eric Erfanianccca3152017-02-22 16:32:36 -08001410 LogUtil.i("InCallActivity.getShouldShowVideoUi", "found video call");
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001411 return new ShouldShowUiResult(true, call);
Eric Erfanianccca3152017-02-22 16:32:36 -08001412 }
1413
linyuh8fbecce2017-12-18 13:53:09 -08001414 if (call.hasSentVideoUpgradeRequest() || call.hasReceivedVideoUpgradeRequest()) {
Eric Erfanianccca3152017-02-22 16:32:36 -08001415 LogUtil.i("InCallActivity.getShouldShowVideoUi", "upgrading to video");
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001416 return new ShouldShowUiResult(true, call);
Eric Erfanianccca3152017-02-22 16:32:36 -08001417 }
1418
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001419 return new ShouldShowUiResult(false, null);
Eric Erfanianccca3152017-02-22 16:32:36 -08001420 }
1421
wangqi219b8702018-02-13 09:34:41 -08001422 private static ShouldShowUiResult getShouldShowRttUi() {
1423 DialerCall call = CallList.getInstance().getFirstCall();
1424 if (call == null) {
1425 LogUtil.i("InCallActivity.getShouldShowRttUi", "null call");
1426 return new ShouldShowUiResult(false, null);
1427 }
1428
wangqif6be6172018-03-30 15:57:56 -07001429 if (call.isActiveRttCall()) {
wangqi219b8702018-02-13 09:34:41 -08001430 LogUtil.i("InCallActivity.getShouldShowRttUi", "found rtt call");
1431 return new ShouldShowUiResult(true, call);
1432 }
1433
1434 if (call.hasSentRttUpgradeRequest()) {
1435 LogUtil.i("InCallActivity.getShouldShowRttUi", "upgrading to rtt");
1436 return new ShouldShowUiResult(true, call);
1437 }
1438
1439 return new ShouldShowUiResult(false, null);
1440 }
1441
Eric Erfanianccca3152017-02-22 16:32:36 -08001442 private boolean showAnswerScreenFragment(FragmentTransaction transaction, DialerCall call) {
1443 // When rejecting a call the active call can become null in which case we should continue
1444 // showing the answer screen.
1445 if (didShowAnswerScreen && call == null) {
1446 return false;
1447 }
1448
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001449 Assert.checkArgument(call != null, "didShowAnswerScreen was false but call was still null");
1450
1451 boolean isVideoUpgradeRequest = call.hasReceivedVideoUpgradeRequest();
Eric Erfanianccca3152017-02-22 16:32:36 -08001452
1453 // Check if we're already showing an answer screen for this call.
1454 if (didShowAnswerScreen) {
1455 AnswerScreen answerScreen = getAnswerScreen();
1456 if (answerScreen.getCallId().equals(call.getId())
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001457 && answerScreen.isVideoCall() == call.isVideoCall()
Eric Erfanian2ca43182017-08-31 06:57:16 -07001458 && answerScreen.isVideoUpgradeRequest() == isVideoUpgradeRequest
1459 && !answerScreen.isActionTimeout()) {
1460 LogUtil.d(
1461 "InCallActivity.showAnswerScreenFragment",
1462 "answer fragment exists for same call and has NOT been accepted/rejected/timed out");
Eric Erfanianccca3152017-02-22 16:32:36 -08001463 return false;
1464 }
Eric Erfanian2ca43182017-08-31 06:57:16 -07001465 if (answerScreen.isActionTimeout()) {
1466 LogUtil.i(
1467 "InCallActivity.showAnswerScreenFragment",
1468 "answer fragment exists but has been accepted/rejected and timed out");
1469 } else {
1470 LogUtil.i(
1471 "InCallActivity.showAnswerScreenFragment",
1472 "answer fragment exists but arguments do not match");
1473 }
Eric Erfanianccca3152017-02-22 16:32:36 -08001474 hideAnswerScreenFragment(transaction);
1475 }
1476
1477 // Show a new answer screen.
1478 AnswerScreen answerScreen =
Eric Erfanianfc37b022017-03-21 10:11:17 -07001479 AnswerBindings.createAnswerScreen(
1480 call.getId(),
wangqif6be6172018-03-30 15:57:56 -07001481 call.isActiveRttCall(),
Eric Erfanianfc37b022017-03-21 10:11:17 -07001482 call.isVideoCall(),
1483 isVideoUpgradeRequest,
Eric Erfanian90508232017-03-24 09:31:16 -07001484 call.getVideoTech().isSelfManagedCamera(),
1485 shouldAllowAnswerAndRelease(call),
erfaniand05d8992018-03-20 19:42:26 -07001486 CallList.getInstance().getBackgroundCall() != null,
erfanian89e3d1b2018-05-02 18:50:59 -07001487 getSpeakEasyCallManager().isAvailable(getApplicationContext())
1488 && call.isSpeakEasyEligible());
linyuhc3968e62017-11-20 17:40:50 -08001489 transaction.add(R.id.main, answerScreen.getAnswerScreenFragment(), Tags.ANSWER_SCREEN);
Eric Erfanianccca3152017-02-22 16:32:36 -08001490
1491 Logger.get(this).logScreenView(ScreenEvent.Type.INCOMING_CALL, this);
1492 didShowAnswerScreen = true;
1493 return true;
1494 }
1495
Eric Erfanian90508232017-03-24 09:31:16 -07001496 private boolean shouldAllowAnswerAndRelease(DialerCall call) {
1497 if (CallList.getInstance().getActiveCall() == null) {
1498 LogUtil.i("InCallActivity.shouldAllowAnswerAndRelease", "no active call");
1499 return false;
1500 }
1501 if (getSystemService(TelephonyManager.class).getPhoneType()
1502 == TelephonyManager.PHONE_TYPE_CDMA) {
1503 LogUtil.i("InCallActivity.shouldAllowAnswerAndRelease", "PHONE_TYPE_CDMA not supported");
1504 return false;
1505 }
1506 if (call.isVideoCall() || call.hasReceivedVideoUpgradeRequest()) {
1507 LogUtil.i("InCallActivity.shouldAllowAnswerAndRelease", "video call");
1508 return false;
1509 }
zachh190343a2018-05-31 17:30:46 -07001510 if (!ConfigProviderComponent.get(this)
1511 .getConfigProvider()
linyuhc3968e62017-11-20 17:40:50 -08001512 .getBoolean(ConfigNames.ANSWER_AND_RELEASE_ENABLED, true)) {
Eric Erfanian90508232017-03-24 09:31:16 -07001513 LogUtil.i("InCallActivity.shouldAllowAnswerAndRelease", "disabled by config");
1514 return false;
1515 }
1516
1517 return true;
1518 }
1519
Eric Erfanianccca3152017-02-22 16:32:36 -08001520 private boolean hideAnswerScreenFragment(FragmentTransaction transaction) {
1521 if (!didShowAnswerScreen) {
1522 return false;
1523 }
1524 AnswerScreen answerScreen = getAnswerScreen();
1525 if (answerScreen != null) {
1526 transaction.remove(answerScreen.getAnswerScreenFragment());
1527 }
1528
1529 didShowAnswerScreen = false;
1530 return true;
1531 }
1532
1533 private boolean showInCallScreenFragment(FragmentTransaction transaction) {
1534 if (didShowInCallScreen) {
1535 return false;
1536 }
Eric Erfanian2ca43182017-08-31 06:57:16 -07001537 InCallScreen inCallScreen = InCallBindings.createInCallScreen();
linyuhc3968e62017-11-20 17:40:50 -08001538 transaction.add(R.id.main, inCallScreen.getInCallScreenFragment(), Tags.IN_CALL_SCREEN);
Eric Erfanianccca3152017-02-22 16:32:36 -08001539 Logger.get(this).logScreenView(ScreenEvent.Type.INCALL, this);
1540 didShowInCallScreen = true;
1541 return true;
1542 }
1543
1544 private boolean hideInCallScreenFragment(FragmentTransaction transaction) {
1545 if (!didShowInCallScreen) {
1546 return false;
1547 }
1548 InCallScreen inCallScreen = getInCallScreen();
1549 if (inCallScreen != null) {
Eric Erfanian2ca43182017-08-31 06:57:16 -07001550 transaction.remove(inCallScreen.getInCallScreenFragment());
Eric Erfanianccca3152017-02-22 16:32:36 -08001551 }
1552 didShowInCallScreen = false;
1553 return true;
1554 }
1555
wangqi219b8702018-02-13 09:34:41 -08001556 private boolean showRttCallScreenFragment(FragmentTransaction transaction, DialerCall call) {
1557 if (didShowRttCallScreen) {
wangqi91958f82018-06-06 14:01:47 -07001558 if (getRttCallScreen().getCallId().equals(call.getId())) {
1559 return false;
wangqi219b8702018-02-13 09:34:41 -08001560 }
wangqi91958f82018-06-06 14:01:47 -07001561 LogUtil.i("InCallActivity.showRttCallScreenFragment", "RTT call id doesn't match");
1562 hideRttCallScreenFragment(transaction);
wangqi219b8702018-02-13 09:34:41 -08001563 }
1564 RttCallScreen rttCallScreen = RttBindings.createRttCallScreen(call.getId());
1565 transaction.add(R.id.main, rttCallScreen.getRttCallScreenFragment(), Tags.RTT_CALL_SCREEN);
1566 Logger.get(this).logScreenView(ScreenEvent.Type.INCALL, this);
1567 didShowRttCallScreen = true;
wangqifb0cfff2018-06-05 11:51:01 -07001568 // In some cases such as VZW, RTT request will be automatically accepted by modem. So the dialog
1569 // won't make any sense and should be dismissed if it's already switched to RTT.
1570 if (rttRequestDialogFragment != null) {
1571 LogUtil.i("InCallActivity.showRttCallScreenFragment", "dismiss RTT request dialog");
1572 rttRequestDialogFragment.dismiss();
1573 rttRequestDialogFragment = null;
1574 }
wangqi219b8702018-02-13 09:34:41 -08001575 return true;
1576 }
1577
1578 private boolean hideRttCallScreenFragment(FragmentTransaction transaction) {
1579 if (!didShowRttCallScreen) {
1580 return false;
1581 }
1582 RttCallScreen rttCallScreen = getRttCallScreen();
1583 if (rttCallScreen != null) {
1584 transaction.remove(rttCallScreen.getRttCallScreenFragment());
1585 }
1586 didShowRttCallScreen = false;
1587 return true;
1588 }
1589
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001590 private boolean showVideoCallScreenFragment(FragmentTransaction transaction, DialerCall call) {
Eric Erfanianccca3152017-02-22 16:32:36 -08001591 if (didShowVideoCallScreen) {
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001592 VideoCallScreen videoCallScreen = getVideoCallScreen();
1593 if (videoCallScreen.getCallId().equals(call.getId())) {
1594 return false;
1595 }
1596 LogUtil.i(
1597 "InCallActivity.showVideoCallScreenFragment",
1598 "video call fragment exists but arguments do not match");
1599 hideVideoCallScreenFragment(transaction);
Eric Erfanianccca3152017-02-22 16:32:36 -08001600 }
1601
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001602 LogUtil.i("InCallActivity.showVideoCallScreenFragment", "call: %s", call);
1603
Eric Erfanian90508232017-03-24 09:31:16 -07001604 VideoCallScreen videoCallScreen =
1605 VideoBindings.createVideoCallScreen(
1606 call.getId(), call.getVideoTech().shouldUseSurfaceView());
linyuhc3968e62017-11-20 17:40:50 -08001607 transaction.add(
1608 R.id.main, videoCallScreen.getVideoCallScreenFragment(), Tags.VIDEO_CALL_SCREEN);
Eric Erfanianccca3152017-02-22 16:32:36 -08001609
1610 Logger.get(this).logScreenView(ScreenEvent.Type.INCALL, this);
1611 didShowVideoCallScreen = true;
1612 return true;
1613 }
1614
1615 private boolean hideVideoCallScreenFragment(FragmentTransaction transaction) {
1616 if (!didShowVideoCallScreen) {
1617 return false;
1618 }
1619 VideoCallScreen videoCallScreen = getVideoCallScreen();
1620 if (videoCallScreen != null) {
1621 transaction.remove(videoCallScreen.getVideoCallScreenFragment());
1622 }
1623 didShowVideoCallScreen = false;
1624 return true;
1625 }
1626
linyuhc3968e62017-11-20 17:40:50 -08001627 private AnswerScreen getAnswerScreen() {
1628 return (AnswerScreen) getSupportFragmentManager().findFragmentByTag(Tags.ANSWER_SCREEN);
Eric Erfanianccca3152017-02-22 16:32:36 -08001629 }
1630
linyuhc3968e62017-11-20 17:40:50 -08001631 private InCallScreen getInCallScreen() {
1632 return (InCallScreen) getSupportFragmentManager().findFragmentByTag(Tags.IN_CALL_SCREEN);
Eric Erfanianccca3152017-02-22 16:32:36 -08001633 }
1634
linyuhc3968e62017-11-20 17:40:50 -08001635 private VideoCallScreen getVideoCallScreen() {
1636 return (VideoCallScreen) getSupportFragmentManager().findFragmentByTag(Tags.VIDEO_CALL_SCREEN);
Eric Erfanianccca3152017-02-22 16:32:36 -08001637 }
1638
wangqi219b8702018-02-13 09:34:41 -08001639 private RttCallScreen getRttCallScreen() {
1640 return (RttCallScreen) getSupportFragmentManager().findFragmentByTag(Tags.RTT_CALL_SCREEN);
1641 }
1642
wangqifd4c9f72018-03-08 18:21:50 -08001643 private InCallScreen getInCallOrRttCallScreen() {
1644 InCallScreen inCallScreen = null;
1645 if (didShowInCallScreen) {
1646 inCallScreen = getInCallScreen();
1647 }
1648 if (didShowRttCallScreen) {
1649 inCallScreen = getRttCallScreen();
1650 }
1651 return inCallScreen;
1652 }
1653
Eric Erfanianccca3152017-02-22 16:32:36 -08001654 @Override
1655 public void onPseudoScreenStateChanged(boolean isOn) {
1656 LogUtil.i("InCallActivity.onPseudoScreenStateChanged", "isOn: " + isOn);
1657 pseudoBlackScreenOverlay.setVisibility(isOn ? View.GONE : View.VISIBLE);
1658 }
1659
1660 /**
1661 * For some touch related issue, turning off the screen can be faked by drawing a black view over
1662 * the activity. All touch events started when the screen is "off" is rejected.
1663 *
1664 * @see PseudoScreenState
1665 */
1666 @Override
1667 public boolean dispatchTouchEvent(MotionEvent event) {
1668 // Reject any gesture that started when the screen is in the fake off state.
1669 if (touchDownWhenPseudoScreenOff) {
1670 if (event.getAction() == MotionEvent.ACTION_UP) {
1671 touchDownWhenPseudoScreenOff = false;
1672 }
1673 return true;
1674 }
1675 // Reject all touch event when the screen is in the fake off state.
1676 if (!InCallPresenter.getInstance().getPseudoScreenState().isOn()) {
1677 if (event.getAction() == MotionEvent.ACTION_DOWN) {
1678 touchDownWhenPseudoScreenOff = true;
1679 LogUtil.i("InCallActivity.dispatchTouchEvent", "touchDownWhenPseudoScreenOff");
1680 }
1681 return true;
1682 }
1683 return super.dispatchTouchEvent(event);
1684 }
1685
wangqi219b8702018-02-13 09:34:41 -08001686 @Override
1687 public RttCallScreenDelegate newRttCallScreenDelegate(RttCallScreen videoCallScreen) {
1688 return new RttCallPresenter();
1689 }
1690
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001691 private static class ShouldShowUiResult {
Eric Erfanianccca3152017-02-22 16:32:36 -08001692 public final boolean shouldShow;
1693 public final DialerCall call;
1694
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001695 ShouldShowUiResult(boolean shouldShow, DialerCall call) {
Eric Erfanianccca3152017-02-22 16:32:36 -08001696 this.shouldShow = shouldShow;
1697 this.call = call;
1698 }
1699 }
linyuhc3968e62017-11-20 17:40:50 -08001700
1701 private static final class IntentExtraNames {
1702 static final String FOR_FULL_SCREEN = "InCallActivity.for_full_screen_intent";
1703 static final String NEW_OUTGOING_CALL = "InCallActivity.new_outgoing_call";
1704 static final String SHOW_DIALPAD = "InCallActivity.show_dialpad";
1705 }
1706
1707 private static final class KeysForSavedInstance {
1708 static final String DIALPAD_TEXT = "InCallActivity.dialpad_text";
1709 static final String DID_SHOW_ANSWER_SCREEN = "did_show_answer_screen";
1710 static final String DID_SHOW_IN_CALL_SCREEN = "did_show_in_call_screen";
1711 static final String DID_SHOW_VIDEO_CALL_SCREEN = "did_show_video_call_screen";
wangqi153af2f2018-02-15 16:21:49 -08001712 static final String DID_SHOW_RTT_CALL_SCREEN = "did_show_rtt_call_screen";
erfaniand05d8992018-03-20 19:42:26 -07001713 static final String DID_SHOW_SPEAK_EASY_SCREEN = "did_show_speak_easy_screen";
linyuhc3968e62017-11-20 17:40:50 -08001714 }
1715
1716 /** Request codes for pending intents. */
1717 public static final class PendingIntentRequestCodes {
1718 static final int NON_FULL_SCREEN = 0;
1719 static final int FULL_SCREEN = 1;
1720 static final int BUBBLE = 2;
1721 }
1722
1723 private static final class Tags {
1724 static final String ANSWER_SCREEN = "tag_answer_screen";
1725 static final String DIALPAD_FRAGMENT = "tag_dialpad_fragment";
1726 static final String IN_CALL_SCREEN = "tag_in_call_screen";
1727 static final String INTERNATIONAL_CALL_ON_WIFI = "tag_international_call_on_wifi";
1728 static final String SELECT_ACCOUNT_FRAGMENT = "tag_select_account_fragment";
1729 static final String VIDEO_CALL_SCREEN = "tag_video_call_screen";
wangqi219b8702018-02-13 09:34:41 -08001730 static final String RTT_CALL_SCREEN = "tag_rtt_call_screen";
linyuhc3968e62017-11-20 17:40:50 -08001731 static final String POST_CHAR_DIALOG_FRAGMENT = "tag_post_char_dialog_fragment";
erfaniand05d8992018-03-20 19:42:26 -07001732 static final String SPEAK_EASY_SCREEN = "tag_speak_easy_screen";
wangqibc28ea72018-04-02 16:23:00 -07001733 static final String RTT_REQUEST_DIALOG = "tag_rtt_request_dialog";
linyuhc3968e62017-11-20 17:40:50 -08001734 }
1735
1736 private static final class ConfigNames {
1737 static final String ANSWER_AND_RELEASE_ENABLED = "answer_and_release_enabled";
1738 }
1739
linyuhc3968e62017-11-20 17:40:50 -08001740 private static final class SelectPhoneAccountListener
1741 extends SelectPhoneAccountDialogFragment.SelectPhoneAccountListener {
1742 private static final String TAG = SelectPhoneAccountListener.class.getCanonicalName();
1743
twyen73a74c32018-03-07 12:12:24 -08001744 private final Context appContext;
1745
1746 SelectPhoneAccountListener(Context appContext) {
1747 this.appContext = appContext;
1748 }
1749
linyuhc3968e62017-11-20 17:40:50 -08001750 @Override
1751 public void onPhoneAccountSelected(
1752 PhoneAccountHandle selectedAccountHandle, boolean setDefault, String callId) {
1753 DialerCall call = CallList.getInstance().getCallById(callId);
1754 LogUtil.i(TAG, "Phone account select with call:\n%s", call);
1755
1756 if (call != null) {
twyen73a74c32018-03-07 12:12:24 -08001757 call.phoneAccountSelected(selectedAccountHandle, false);
1758 if (call.getPreferredAccountRecorder() != null) {
1759 call.getPreferredAccountRecorder().record(appContext, selectedAccountHandle, setDefault);
1760 }
linyuhc3968e62017-11-20 17:40:50 -08001761 }
1762 }
1763
1764 @Override
1765 public void onDialogDismissed(String callId) {
1766 DialerCall call = CallList.getInstance().getCallById(callId);
1767 LogUtil.i(TAG, "Disconnecting call:\n%s" + call);
1768
1769 if (call != null) {
1770 call.disconnect();
1771 }
1772 }
1773 }
Eric Erfanianccca3152017-02-22 16:32:36 -08001774}