blob: 91f557bd5ff274ba72b0f27e35eb3b528efa8ba1 [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;
Eric Erfanian2ca43182017-08-31 06:57:16 -070064import com.android.dialer.configprovider.ConfigProviderBindings;
twyen73a74c32018-03-07 12:12:24 -080065import com.android.dialer.logging.DialerImpression.Type;
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;
72import com.android.dialer.preferredsim.suggestion.SuggestionProvider;
linyuhc3968e62017-11-20 17:40:50 -080073import com.android.dialer.util.ViewUtil;
Eric Erfanianccca3152017-02-22 16:32:36 -080074import com.android.incallui.answer.bindings.AnswerBindings;
75import com.android.incallui.answer.protocol.AnswerScreen;
76import com.android.incallui.answer.protocol.AnswerScreenDelegate;
77import com.android.incallui.answer.protocol.AnswerScreenDelegateFactory;
78import com.android.incallui.answerproximitysensor.PseudoScreenState;
linyuh57b093b2017-11-17 14:32:32 -080079import com.android.incallui.audiomode.AudioModeProvider;
Eric Erfanianccca3152017-02-22 16:32:36 -080080import com.android.incallui.call.CallList;
81import com.android.incallui.call.DialerCall;
82import com.android.incallui.call.DialerCall.State;
linyuh57b093b2017-11-17 14:32:32 -080083import com.android.incallui.call.TelecomAdapter;
Eric Erfanian2ca43182017-08-31 06:57:16 -070084import com.android.incallui.callpending.CallPendingActivity;
85import com.android.incallui.disconnectdialog.DisconnectMessage;
Eric Erfanianccca3152017-02-22 16:32:36 -080086import com.android.incallui.incall.bindings.InCallBindings;
87import com.android.incallui.incall.protocol.InCallButtonUiDelegate;
88import com.android.incallui.incall.protocol.InCallButtonUiDelegateFactory;
89import com.android.incallui.incall.protocol.InCallScreen;
90import com.android.incallui.incall.protocol.InCallScreenDelegate;
91import com.android.incallui.incall.protocol.InCallScreenDelegateFactory;
linyuh7b86f562017-11-16 11:24:09 -080092import com.android.incallui.incalluilock.InCallUiLock;
wangqi219b8702018-02-13 09:34:41 -080093import com.android.incallui.rtt.bindings.RttBindings;
94import com.android.incallui.rtt.protocol.RttCallScreen;
95import com.android.incallui.rtt.protocol.RttCallScreenDelegate;
96import com.android.incallui.rtt.protocol.RttCallScreenDelegateFactory;
erfaniand05d8992018-03-20 19:42:26 -070097import com.android.incallui.speakeasy.SpeakEasyCallManager;
linyuhf99f6302017-11-15 11:23:51 -080098import com.android.incallui.telecomeventui.InternationalCallOnWifiDialogFragment;
Eric Erfanianccca3152017-02-22 16:32:36 -080099import com.android.incallui.video.bindings.VideoBindings;
100import com.android.incallui.video.protocol.VideoCallScreen;
101import com.android.incallui.video.protocol.VideoCallScreenDelegate;
102import com.android.incallui.video.protocol.VideoCallScreenDelegateFactory;
linyuhc3968e62017-11-20 17:40:50 -0800103import com.google.common.base.Optional;
104import java.lang.annotation.Retention;
105import java.lang.annotation.RetentionPolicy;
106import java.util.ArrayList;
107import java.util.List;
Eric Erfanianccca3152017-02-22 16:32:36 -0800108
109/** Version of {@link InCallActivity} that shows the new UI */
110public class InCallActivity extends TransactionSafeFragmentActivity
111 implements AnswerScreenDelegateFactory,
112 InCallScreenDelegateFactory,
113 InCallButtonUiDelegateFactory,
114 VideoCallScreenDelegateFactory,
wangqi219b8702018-02-13 09:34:41 -0800115 RttCallScreenDelegateFactory,
Eric Erfanianccca3152017-02-22 16:32:36 -0800116 PseudoScreenState.StateChangedListener {
117
linyuhc3968e62017-11-20 17:40:50 -0800118 @Retention(RetentionPolicy.SOURCE)
119 @IntDef({
120 DIALPAD_REQUEST_NONE,
121 DIALPAD_REQUEST_SHOW,
122 DIALPAD_REQUEST_HIDE,
123 })
124 @interface DialpadRequestType {}
Eric Erfanian2ca43182017-08-31 06:57:16 -0700125
linyuhc3968e62017-11-20 17:40:50 -0800126 private static final int DIALPAD_REQUEST_NONE = 1;
127 private static final int DIALPAD_REQUEST_SHOW = 2;
128 private static final int DIALPAD_REQUEST_HIDE = 3;
linyuh57b093b2017-11-17 14:32:32 -0800129
linyuhc3968e62017-11-20 17:40:50 -0800130 private static Optional<Integer> audioRouteForTesting = Optional.absent();
linyuh57b093b2017-11-17 14:32:32 -0800131
linyuhc3968e62017-11-20 17:40:50 -0800132 private final InternationalCallOnWifiCallback internationalCallOnWifiCallback =
133 new InternationalCallOnWifiCallback();
twyen73a74c32018-03-07 12:12:24 -0800134
135 private SelectPhoneAccountListener selectPhoneAccountListener;
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;
145 private String showPostCharWaitDialogCallId;
146 private String showPostCharWaitDialogChars;
147 private boolean allowOrientationChange;
148 private boolean animateDialpadOnShow;
Eric Erfanianccca3152017-02-22 16:32:36 -0800149 private boolean didShowAnswerScreen;
150 private boolean didShowInCallScreen;
151 private boolean didShowVideoCallScreen;
wangqi219b8702018-02-13 09:34:41 -0800152 private boolean didShowRttCallScreen;
erfaniand05d8992018-03-20 19:42:26 -0700153 private boolean didShowSpeakEasyScreen;
erfanian612d13a2018-04-04 15:27:57 -0700154 private String lastShownSpeakEasyScreenUniqueCallid = "";
linyuh9c327da2017-11-14 12:33:48 -0800155 private boolean dismissKeyguard;
Eric Erfanianccca3152017-02-22 16:32:36 -0800156 private boolean isInShowMainInCallFragment;
linyuhc3968e62017-11-20 17:40:50 -0800157 private boolean isRecreating; // whether the activity is going to be recreated
158 private boolean isVisible;
Eric Erfanianccca3152017-02-22 16:32:36 -0800159 private boolean needDismissPendingDialogs;
linyuhc3968e62017-11-20 17:40:50 -0800160 private boolean showPostCharWaitDialogOnResume;
161 private boolean touchDownWhenPseudoScreenOff;
162 private int[] backgroundDrawableColors;
163 @DialpadRequestType private int showDialpadRequest = DIALPAD_REQUEST_NONE;
erfaniand05d8992018-03-20 19:42:26 -0700164 private SpeakEasyCallManager speakEasyCallManager;
Eric Erfanianccca3152017-02-22 16:32:36 -0800165
166 public static Intent getIntent(
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700167 Context context, boolean showDialpad, boolean newOutgoingCall, boolean isForFullScreen) {
Eric Erfanianccca3152017-02-22 16:32:36 -0800168 Intent intent = new Intent(Intent.ACTION_MAIN, null);
169 intent.setFlags(Intent.FLAG_ACTIVITY_NO_USER_ACTION | Intent.FLAG_ACTIVITY_NEW_TASK);
170 intent.setClass(context, InCallActivity.class);
linyuhc3968e62017-11-20 17:40:50 -0800171 if (showDialpad) {
172 intent.putExtra(IntentExtraNames.SHOW_DIALPAD, true);
173 }
174 intent.putExtra(IntentExtraNames.NEW_OUTGOING_CALL, newOutgoingCall);
175 intent.putExtra(IntentExtraNames.FOR_FULL_SCREEN, isForFullScreen);
Eric Erfanianccca3152017-02-22 16:32:36 -0800176 return intent;
177 }
178
179 @Override
180 protected void onResumeFragments() {
181 super.onResumeFragments();
182 if (needDismissPendingDialogs) {
183 dismissPendingDialogs();
184 }
185 }
186
187 @Override
linyuhc3968e62017-11-20 17:40:50 -0800188 protected void onCreate(Bundle bundle) {
Eric Erfanian2ca43182017-08-31 06:57:16 -0700189 Trace.beginSection("InCallActivity.onCreate");
linyuhc3968e62017-11-20 17:40:50 -0800190 super.onCreate(bundle);
Eric Erfanianccca3152017-02-22 16:32:36 -0800191
twyen73a74c32018-03-07 12:12:24 -0800192 selectPhoneAccountListener = new SelectPhoneAccountListener(getApplicationContext());
193
linyuhc3968e62017-11-20 17:40:50 -0800194 if (bundle != null) {
195 didShowAnswerScreen = bundle.getBoolean(KeysForSavedInstance.DID_SHOW_ANSWER_SCREEN);
196 didShowInCallScreen = bundle.getBoolean(KeysForSavedInstance.DID_SHOW_IN_CALL_SCREEN);
197 didShowVideoCallScreen = bundle.getBoolean(KeysForSavedInstance.DID_SHOW_VIDEO_CALL_SCREEN);
wangqi153af2f2018-02-15 16:21:49 -0800198 didShowRttCallScreen = bundle.getBoolean(KeysForSavedInstance.DID_SHOW_RTT_CALL_SCREEN);
Eric Erfanianccca3152017-02-22 16:32:36 -0800199 }
200
linyuhc3968e62017-11-20 17:40:50 -0800201 setWindowFlags();
202 setContentView(R.layout.incall_screen);
203 internalResolveIntent(getIntent());
204
205 boolean isLandscape =
206 getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE;
207 boolean isRtl = ViewUtil.isRtl();
208 if (isLandscape) {
209 dialpadSlideInAnimation =
210 AnimationUtils.loadAnimation(
211 this, isRtl ? R.anim.dialpad_slide_in_left : R.anim.dialpad_slide_in_right);
212 dialpadSlideOutAnimation =
213 AnimationUtils.loadAnimation(
214 this, isRtl ? R.anim.dialpad_slide_out_left : R.anim.dialpad_slide_out_right);
215 } else {
216 dialpadSlideInAnimation = AnimationUtils.loadAnimation(this, R.anim.dialpad_slide_in_bottom);
217 dialpadSlideOutAnimation =
218 AnimationUtils.loadAnimation(this, R.anim.dialpad_slide_out_bottom);
219 }
220 dialpadSlideInAnimation.setInterpolator(AnimUtils.EASE_IN);
221 dialpadSlideOutAnimation.setInterpolator(AnimUtils.EASE_OUT);
222 dialpadSlideOutAnimation.setAnimationListener(
223 new AnimationListenerAdapter() {
224 @Override
225 public void onAnimationEnd(Animation animation) {
226 hideDialpadFragment();
227 }
228 });
229
230 if (bundle != null && showDialpadRequest == DIALPAD_REQUEST_NONE) {
231 // If the dialpad was shown before, set related variables so that it can be shown and
232 // populated with the previous DTMF text during onResume().
233 if (bundle.containsKey(IntentExtraNames.SHOW_DIALPAD)) {
234 boolean showDialpad = bundle.getBoolean(IntentExtraNames.SHOW_DIALPAD);
235 showDialpadRequest = showDialpad ? DIALPAD_REQUEST_SHOW : DIALPAD_REQUEST_HIDE;
236 animateDialpadOnShow = false;
237 }
238 dtmfTextToPrepopulate = bundle.getString(KeysForSavedInstance.DIALPAD_TEXT);
239
240 SelectPhoneAccountDialogFragment selectPhoneAccountDialogFragment =
241 (SelectPhoneAccountDialogFragment)
242 getFragmentManager().findFragmentByTag(Tags.SELECT_ACCOUNT_FRAGMENT);
243 if (selectPhoneAccountDialogFragment != null) {
244 selectPhoneAccountDialogFragment.setListener(selectPhoneAccountListener);
245 }
246 }
247
248 InternationalCallOnWifiDialogFragment existingInternationalCallOnWifiDialogFragment =
249 (InternationalCallOnWifiDialogFragment)
250 getSupportFragmentManager().findFragmentByTag(Tags.INTERNATIONAL_CALL_ON_WIFI);
251 if (existingInternationalCallOnWifiDialogFragment != null) {
252 existingInternationalCallOnWifiDialogFragment.setCallback(internationalCallOnWifiCallback);
253 }
254
linyuh69a25062017-11-15 16:18:51 -0800255 inCallOrientationEventListener = new InCallOrientationEventListener(this);
Eric Erfanianccca3152017-02-22 16:32:36 -0800256
257 getWindow()
258 .getDecorView()
259 .setSystemUiVisibility(
260 View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
261
262 pseudoBlackScreenOverlay = findViewById(R.id.psuedo_black_screen_overlay);
Eric Erfanian2ca43182017-08-31 06:57:16 -0700263 sendBroadcast(CallPendingActivity.getFinishBroadcast());
264 Trace.endSection();
zachh7a96dc72018-02-20 22:16:03 -0800265 MetricsComponent.get(this)
266 .metrics()
267 .stopTimer(Metrics.ON_CALL_ADDED_TO_ON_INCALL_UI_SHOWN_INCOMING);
268 MetricsComponent.get(this)
269 .metrics()
270 .stopTimer(Metrics.ON_CALL_ADDED_TO_ON_INCALL_UI_SHOWN_OUTGOING);
Eric Erfanianccca3152017-02-22 16:32:36 -0800271 }
272
linyuhc3968e62017-11-20 17:40:50 -0800273 private void setWindowFlags() {
274 // Allow the activity to be shown when the screen is locked and filter out touch events that are
275 // "too fat".
276 int flags =
277 WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
278 | WindowManager.LayoutParams.FLAG_IGNORE_CHEEK_PRESSES;
279
linyuhf79d1cb2017-12-15 17:49:56 -0800280 // When the audio stream is not via Bluetooth, turn on the screen once the activity is shown.
281 // When the audio stream is via Bluetooth, turn on the screen only for an incoming call.
linyuhc3968e62017-11-20 17:40:50 -0800282 final int audioRoute = getAudioRoute();
linyuhf79d1cb2017-12-15 17:49:56 -0800283 if (audioRoute != CallAudioState.ROUTE_BLUETOOTH
284 || CallList.getInstance().getIncomingCall() != null) {
linyuhc3968e62017-11-20 17:40:50 -0800285 flags |= WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON;
286 }
287
288 getWindow().addFlags(flags);
289 }
290
291 private static int getAudioRoute() {
292 if (audioRouteForTesting.isPresent()) {
293 return audioRouteForTesting.get();
294 }
295
296 return AudioModeProvider.getInstance().getAudioState().getRoute();
297 }
298
299 @VisibleForTesting(otherwise = VisibleForTesting.NONE)
300 public static void setAudioRouteForTesting(int audioRoute) {
301 audioRouteForTesting = Optional.of(audioRoute);
302 }
303
304 private void internalResolveIntent(Intent intent) {
305 if (!intent.getAction().equals(Intent.ACTION_MAIN)) {
306 return;
307 }
308
309 if (intent.hasExtra(IntentExtraNames.SHOW_DIALPAD)) {
310 // IntentExtraNames.SHOW_DIALPAD can be used to specify whether the DTMF dialpad should be
311 // initially visible. If the extra is absent, leave the dialpad in its previous state.
312 boolean showDialpad = intent.getBooleanExtra(IntentExtraNames.SHOW_DIALPAD, false);
313 relaunchedFromDialer(showDialpad);
314 }
315
316 DialerCall outgoingCall = CallList.getInstance().getOutgoingCall();
317 if (outgoingCall == null) {
318 outgoingCall = CallList.getInstance().getPendingOutgoingCall();
319 }
320 if (intent.getBooleanExtra(IntentExtraNames.NEW_OUTGOING_CALL, false)) {
321 intent.removeExtra(IntentExtraNames.NEW_OUTGOING_CALL);
322
323 // InCallActivity is responsible for disconnecting a new outgoing call if there is no way of
324 // making it (i.e. no valid call capable accounts).
linyuh122fb0b2018-03-26 13:35:32 -0700325 if (InCallPresenter.isCallWithNoValidAccounts(outgoingCall)) {
linyuhc3968e62017-11-20 17:40:50 -0800326 LogUtil.i(
327 "InCallActivity.internalResolveIntent", "Call with no valid accounts, disconnecting");
328 outgoingCall.disconnect();
329 }
330
331 dismissKeyguard(true);
332 }
333
334 if (showPhoneAccountSelectionDialog()) {
335 hideMainInCallFragment();
336 }
337 }
338
339 /**
340 * When relaunching from the dialer app, {@code showDialpad} indicates whether the dialpad should
341 * be shown on launch.
342 *
343 * @param showDialpad {@code true} to indicate the dialpad should be shown on launch, and {@code
344 * false} to indicate no change should be made to the dialpad visibility.
345 */
346 private void relaunchedFromDialer(boolean showDialpad) {
347 showDialpadRequest = showDialpad ? DIALPAD_REQUEST_SHOW : DIALPAD_REQUEST_NONE;
348 animateDialpadOnShow = true;
349
350 if (showDialpadRequest == DIALPAD_REQUEST_SHOW) {
351 // If there's only one line in use, AND it's on hold, then we're sure the user
352 // wants to use the dialpad toward the exact line, so un-hold the holding line.
353 DialerCall call = CallList.getInstance().getActiveOrBackgroundCall();
354 if (call != null && call.getState() == State.ONHOLD) {
355 call.unhold();
356 }
357 }
358 }
359
360 /**
361 * Show a phone account selection dialog if there is a call waiting for phone account selection.
362 *
363 * @return true if the dialog was shown.
364 */
365 private boolean showPhoneAccountSelectionDialog() {
366 DialerCall waitingForAccountCall = CallList.getInstance().getWaitingForAccountCall();
367 if (waitingForAccountCall == null) {
368 return false;
369 }
370
twyen73a74c32018-03-07 12:12:24 -0800371 DialerExecutorComponent.get(this)
372 .dialerExecutorFactory()
373 .createNonUiTaskBuilder(new PreferredAccountWorker(waitingForAccountCall.getNumber()))
374 .onSuccess(
375 (result -> {
376 if (result.getPhoneAccountHandle().isPresent()) {
377 Logger.get(this).logImpression(Type.DUAL_SIM_SELECTION_PREFERRED_USED);
378 selectPhoneAccountListener.onPhoneAccountSelected(
379 result.getPhoneAccountHandle().get(), false, waitingForAccountCall.getId());
380 return;
381 }
382 if (result.getSuggestion().isPresent()) {
383 LogUtil.i(
384 "CallingAccountSelector.processPreferredAccount",
385 "SIM suggested: " + result.getSuggestion().get().reason);
386 if (result.getSuggestion().get().shouldAutoSelect) {
387 Logger.get(this).logImpression(Type.DUAL_SIM_SELECTION_SUGGESTION_AUTO_SELECTED);
388 LogUtil.i(
389 "CallingAccountSelector.processPreferredAccount", "Auto selected suggestion");
390 selectPhoneAccountListener.onPhoneAccountSelected(
391 result.getSuggestion().get().phoneAccountHandle,
392 false,
393 waitingForAccountCall.getId());
394 return;
395 }
396 }
397 Bundle extras = waitingForAccountCall.getIntentExtras();
398 List<PhoneAccountHandle> phoneAccountHandles =
399 extras == null
400 ? new ArrayList<>()
401 : extras.getParcelableArrayList(Call.AVAILABLE_PHONE_ACCOUNTS);
linyuhc3968e62017-11-20 17:40:50 -0800402
twyen73a74c32018-03-07 12:12:24 -0800403 waitingForAccountCall.setPreferredAccountRecorder(
404 new PreferredAccountRecorder(
405 waitingForAccountCall.getNumber(),
406 result.getSuggestion().orNull(),
407 result.getDataId().orNull()));
408 selectPhoneAccountDialogFragment =
409 SelectPhoneAccountDialogFragment.newInstance(
410 R.string.select_phone_account_for_calls,
411 result.getDataId().isPresent() /* canSetDefault */,
412 R.string.select_phone_account_for_calls_remember /* setDefaultResId */,
413 phoneAccountHandles,
414 selectPhoneAccountListener,
415 waitingForAccountCall.getId(),
416 SuggestionProvider.buildHint(
417 this, phoneAccountHandles, result.getSuggestion().orNull() /* hints */));
418 selectPhoneAccountDialogFragment.show(
419 getFragmentManager(), Tags.SELECT_ACCOUNT_FRAGMENT);
420 }))
421 .build()
422 .executeParallel(this);
423
linyuhc3968e62017-11-20 17:40:50 -0800424 return true;
425 }
426
Eric Erfanianccca3152017-02-22 16:32:36 -0800427 @Override
428 protected void onSaveInstanceState(Bundle out) {
linyuh57b093b2017-11-17 14:32:32 -0800429 LogUtil.enterBlock("InCallActivity.onSaveInstanceState");
430
431 // TODO: DialpadFragment should handle this as part of its own state
linyuhc3968e62017-11-20 17:40:50 -0800432 out.putBoolean(IntentExtraNames.SHOW_DIALPAD, isDialpadVisible());
linyuh57b093b2017-11-17 14:32:32 -0800433 DialpadFragment dialpadFragment = getDialpadFragment();
434 if (dialpadFragment != null) {
linyuhc3968e62017-11-20 17:40:50 -0800435 out.putString(KeysForSavedInstance.DIALPAD_TEXT, dialpadFragment.getDtmfText());
linyuh57b093b2017-11-17 14:32:32 -0800436 }
437
linyuhc3968e62017-11-20 17:40:50 -0800438 out.putBoolean(KeysForSavedInstance.DID_SHOW_ANSWER_SCREEN, didShowAnswerScreen);
439 out.putBoolean(KeysForSavedInstance.DID_SHOW_IN_CALL_SCREEN, didShowInCallScreen);
440 out.putBoolean(KeysForSavedInstance.DID_SHOW_VIDEO_CALL_SCREEN, didShowVideoCallScreen);
wangqi153af2f2018-02-15 16:21:49 -0800441 out.putBoolean(KeysForSavedInstance.DID_SHOW_RTT_CALL_SCREEN, didShowRttCallScreen);
erfaniand05d8992018-03-20 19:42:26 -0700442 out.putBoolean(KeysForSavedInstance.DID_SHOW_SPEAK_EASY_SCREEN, didShowSpeakEasyScreen);
linyuh57b093b2017-11-17 14:32:32 -0800443
Eric Erfanianccca3152017-02-22 16:32:36 -0800444 super.onSaveInstanceState(out);
445 isVisible = false;
446 }
447
448 @Override
449 protected void onStart() {
Eric Erfanian2ca43182017-08-31 06:57:16 -0700450 Trace.beginSection("InCallActivity.onStart");
Eric Erfanianccca3152017-02-22 16:32:36 -0800451 super.onStart();
linyuh57b093b2017-11-17 14:32:32 -0800452
Eric Erfanianccca3152017-02-22 16:32:36 -0800453 isVisible = true;
454 showMainInCallFragment();
linyuh57b093b2017-11-17 14:32:32 -0800455
456 InCallPresenter.getInstance().setActivity(this);
457 enableInCallOrientationEventListener(
458 getRequestedOrientation()
459 == InCallOrientationEventListener.ACTIVITY_PREFERENCE_ALLOW_ROTATION);
460 InCallPresenter.getInstance().onActivityStarted();
461
yueg10f6e822018-01-17 15:32:18 -0800462 if (!isRecreating) {
463 InCallPresenter.getInstance().onUiShowing(true);
464 }
465
linyuh437ae952018-03-26 12:46:18 -0700466 if (isInMultiWindowMode() && !getResources().getBoolean(R.bool.incall_dialpad_allowed)) {
Eric Erfanianccca3152017-02-22 16:32:36 -0800467 // Hide the dialpad because there may not be enough room
468 showDialpadFragment(false, false);
469 }
linyuh57b093b2017-11-17 14:32:32 -0800470
Eric Erfanian2ca43182017-08-31 06:57:16 -0700471 Trace.endSection();
Eric Erfanianccca3152017-02-22 16:32:36 -0800472 }
473
474 @Override
475 protected void onResume() {
Eric Erfanian2ca43182017-08-31 06:57:16 -0700476 Trace.beginSection("InCallActivity.onResume");
Eric Erfanianccca3152017-02-22 16:32:36 -0800477 super.onResume();
linyuhc3968e62017-11-20 17:40:50 -0800478
479 if (!InCallPresenter.getInstance().isReadyForTearDown()) {
480 updateTaskDescription();
linyuhc3968e62017-11-20 17:40:50 -0800481 }
482
483 // If there is a pending request to show or hide the dialpad, handle that now.
484 if (showDialpadRequest != DIALPAD_REQUEST_NONE) {
485 if (showDialpadRequest == DIALPAD_REQUEST_SHOW) {
486 // Exit fullscreen so that the user has access to the dialpad hide/show button.
487 // This is important when showing the dialpad from within dialer.
488 InCallPresenter.getInstance().setFullScreen(false /* isFullScreen */, true /* force */);
489
490 showDialpadFragment(true /* show */, animateDialpadOnShow /* animate */);
491 animateDialpadOnShow = false;
492
493 DialpadFragment dialpadFragment = getDialpadFragment();
494 if (dialpadFragment != null) {
495 dialpadFragment.setDtmfText(dtmfTextToPrepopulate);
496 dtmfTextToPrepopulate = null;
497 }
498 } else {
499 LogUtil.i("InCallActivity.onResume", "Force-hide the dialpad");
500 if (getDialpadFragment() != null) {
501 showDialpadFragment(false /* show */, false /* animate */);
502 }
503 }
504 showDialpadRequest = DIALPAD_REQUEST_NONE;
505 }
506 updateNavigationBar(isDialpadVisible());
507
508 if (showPostCharWaitDialogOnResume) {
509 showDialogForPostCharWait(showPostCharWaitDialogCallId, showPostCharWaitDialogChars);
510 }
511
512 CallList.getInstance()
513 .onInCallUiShown(getIntent().getBooleanExtra(IntentExtraNames.FOR_FULL_SCREEN, false));
514
Eric Erfanianccca3152017-02-22 16:32:36 -0800515 PseudoScreenState pseudoScreenState = InCallPresenter.getInstance().getPseudoScreenState();
516 pseudoScreenState.addListener(this);
517 onPseudoScreenStateChanged(pseudoScreenState.isOn());
Eric Erfanian2ca43182017-08-31 06:57:16 -0700518 Trace.endSection();
weijiaxu650e7cc2017-10-31 12:38:54 -0700519 // add 1 sec delay to get memory snapshot so that dialer wont react slowly on resume.
520 ThreadUtil.postDelayedOnUiThread(
weijiaxuc950a9b2017-11-06 16:39:04 -0800521 () ->
zachh7a96dc72018-02-20 22:16:03 -0800522 MetricsComponent.get(this)
523 .metrics()
524 .recordMemory(Metrics.INCALL_ACTIVITY_ON_RESUME_MEMORY_EVENT_NAME),
weijiaxu650e7cc2017-10-31 12:38:54 -0700525 1000);
Eric Erfanianccca3152017-02-22 16:32:36 -0800526 }
527
Eric Erfanianccca3152017-02-22 16:32:36 -0800528 @Override
529 protected void onPause() {
Eric Erfanian2ca43182017-08-31 06:57:16 -0700530 Trace.beginSection("InCallActivity.onPause");
Eric Erfanianccca3152017-02-22 16:32:36 -0800531 super.onPause();
linyuh57b093b2017-11-17 14:32:32 -0800532
533 DialpadFragment dialpadFragment = getDialpadFragment();
534 if (dialpadFragment != null) {
535 dialpadFragment.onDialerKeyUp(null);
536 }
537
Eric Erfanianccca3152017-02-22 16:32:36 -0800538 InCallPresenter.getInstance().getPseudoScreenState().removeListener(this);
Eric Erfanian2ca43182017-08-31 06:57:16 -0700539 Trace.endSection();
Eric Erfanianccca3152017-02-22 16:32:36 -0800540 }
541
542 @Override
543 protected void onStop() {
Eric Erfanian2ca43182017-08-31 06:57:16 -0700544 Trace.beginSection("InCallActivity.onStop");
wangqi4d705e52017-09-28 12:23:35 -0700545 isVisible = false;
Eric Erfanianccca3152017-02-22 16:32:36 -0800546 super.onStop();
linyuh57b093b2017-11-17 14:32:32 -0800547
548 // Disconnects the call waiting for a phone account when the activity is hidden (e.g., after the
549 // user presses the home button).
550 // Without this the pending call will get stuck on phone account selection and new calls can't
551 // be created.
552 // Skip this when the screen is locked since the activity may complete its current life cycle
553 // and restart.
linyuhc3968e62017-11-20 17:40:50 -0800554 if (!isRecreating && !getSystemService(KeyguardManager.class).isKeyguardLocked()) {
linyuh57b093b2017-11-17 14:32:32 -0800555 DialerCall waitingForAccountCall = CallList.getInstance().getWaitingForAccountCall();
556 if (waitingForAccountCall != null) {
557 waitingForAccountCall.disconnect();
558 }
559 }
560
561 enableInCallOrientationEventListener(false);
562 InCallPresenter.getInstance().updateIsChangingConfigurations();
563 InCallPresenter.getInstance().onActivityStopped();
linyuhc3968e62017-11-20 17:40:50 -0800564 if (!isRecreating) {
yueg10f6e822018-01-17 15:32:18 -0800565 InCallPresenter.getInstance().onUiShowing(false);
wangqie6060522018-04-05 11:47:15 -0700566 }
567 if (errorDialog != null) {
568 errorDialog.dismiss();
linyuh57b093b2017-11-17 14:32:32 -0800569 }
570
yueg10f6e822018-01-17 15:32:18 -0800571 if (isFinishing()) {
572 InCallPresenter.getInstance().unsetActivity(this);
573 }
574
Eric Erfanian2ca43182017-08-31 06:57:16 -0700575 Trace.endSection();
Eric Erfanianccca3152017-02-22 16:32:36 -0800576 }
577
578 @Override
579 protected void onDestroy() {
Eric Erfanian2ca43182017-08-31 06:57:16 -0700580 Trace.beginSection("InCallActivity.onDestroy");
Eric Erfanianccca3152017-02-22 16:32:36 -0800581 super.onDestroy();
linyuh57b093b2017-11-17 14:32:32 -0800582
583 InCallPresenter.getInstance().unsetActivity(this);
584 InCallPresenter.getInstance().updateIsChangingConfigurations();
Eric Erfanian2ca43182017-08-31 06:57:16 -0700585 Trace.endSection();
Eric Erfanianccca3152017-02-22 16:32:36 -0800586 }
587
588 @Override
589 public void finish() {
590 if (shouldCloseActivityOnFinish()) {
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700591 // When user select incall ui from recents after the call is disconnected, it tries to launch
592 // a new InCallActivity but InCallPresenter is already teared down at this point, which causes
593 // crash.
594 // By calling finishAndRemoveTask() instead of finish() the task associated with
595 // InCallActivity is cleared completely. So system won't try to create a new InCallActivity in
596 // this case.
597 //
598 // Calling finish won't clear the task and normally when an activity finishes it shouldn't
599 // clear the task since there could be parent activity in the same task that's still alive.
600 // But InCallActivity is special since it's singleInstance which means it's root activity and
601 // only instance of activity in the task. So it should be safe to also remove task when
602 // finishing.
603 // It's also necessary in the sense of it's excluded from recents. So whenever the activity
604 // finishes, the task should also be removed since it doesn't make sense to go back to it in
605 // anyway anymore.
606 super.finishAndRemoveTask();
Eric Erfanianccca3152017-02-22 16:32:36 -0800607 }
608 }
609
610 private boolean shouldCloseActivityOnFinish() {
linyuhc3968e62017-11-20 17:40:50 -0800611 if (!isVisible) {
Eric Erfanianccca3152017-02-22 16:32:36 -0800612 LogUtil.i(
613 "InCallActivity.shouldCloseActivityOnFinish",
614 "allowing activity to be closed because it's not visible");
615 return true;
616 }
617
twyen8efb4952017-10-06 16:35:54 -0700618 if (InCallPresenter.getInstance().isInCallUiLocked()) {
Eric Erfanianccca3152017-02-22 16:32:36 -0800619 LogUtil.i(
620 "InCallActivity.shouldCloseActivityOnFinish",
twyen8efb4952017-10-06 16:35:54 -0700621 "in call ui is locked, not closing activity");
Eric Erfanianccca3152017-02-22 16:32:36 -0800622 return false;
623 }
624
625 LogUtil.i(
626 "InCallActivity.shouldCloseActivityOnFinish",
twyen8efb4952017-10-06 16:35:54 -0700627 "activity is visible and has no locks, allowing activity to close");
Eric Erfanianccca3152017-02-22 16:32:36 -0800628 return true;
629 }
630
631 @Override
632 protected void onNewIntent(Intent intent) {
linyuhc3968e62017-11-20 17:40:50 -0800633 LogUtil.enterBlock("InCallActivity.onNewIntent");
Eric Erfanianccca3152017-02-22 16:32:36 -0800634
635 // If the screen is off, we need to make sure it gets turned on for incoming calls.
636 // This normally works just fine thanks to FLAG_TURN_SCREEN_ON but that only works
637 // when the activity is first created. Therefore, to ensure the screen is turned on
638 // for the call waiting case, we recreate() the current activity. There should be no jank from
639 // this since the screen is already off and will remain so until our new activity is up.
linyuhc3968e62017-11-20 17:40:50 -0800640 if (!isVisible) {
641 onNewIntent(intent, true /* isRecreating */);
Eric Erfanianccca3152017-02-22 16:32:36 -0800642 LogUtil.i("InCallActivity.onNewIntent", "Restarting InCallActivity to force screen on.");
643 recreate();
Eric Erfanian10b34a52017-05-04 08:23:17 -0700644 } else {
linyuhc3968e62017-11-20 17:40:50 -0800645 onNewIntent(intent, false /* isRecreating */);
646 }
647 }
648
yuega3305352018-01-09 11:02:47 -0800649 @VisibleForTesting
650 void onNewIntent(Intent intent, boolean isRecreating) {
linyuhc3968e62017-11-20 17:40:50 -0800651 this.isRecreating = isRecreating;
652
653 // We're being re-launched with a new Intent. Since it's possible for a single InCallActivity
654 // instance to persist indefinitely (even if we finish() ourselves), this sequence can
655 // happen any time the InCallActivity needs to be displayed.
656
657 // Stash away the new intent so that we can get it in the future by calling getIntent().
658 // Otherwise getIntent() will return the original Intent from when we first got created.
659 setIntent(intent);
660
661 // Activities are always paused before receiving a new intent, so we can count on our onResume()
662 // method being called next.
663
664 // Just like in onCreate(), handle the intent.
665 // Skip if InCallActivity is going to be recreated since this will be called in onCreate().
666 if (!isRecreating) {
667 internalResolveIntent(intent);
Eric Erfanianccca3152017-02-22 16:32:36 -0800668 }
669 }
670
671 @Override
672 public void onBackPressed() {
linyuh57b093b2017-11-17 14:32:32 -0800673 LogUtil.enterBlock("InCallActivity.onBackPressed");
674
linyuhc3968e62017-11-20 17:40:50 -0800675 if (!isVisible) {
linyuh57b093b2017-11-17 14:32:32 -0800676 return;
Eric Erfanianccca3152017-02-22 16:32:36 -0800677 }
linyuh57b093b2017-11-17 14:32:32 -0800678
679 if (!getCallCardFragmentVisible()) {
680 return;
681 }
682
683 DialpadFragment dialpadFragment = getDialpadFragment();
684 if (dialpadFragment != null && dialpadFragment.isVisible()) {
685 showDialpadFragment(false /* show */, true /* animate */);
686 return;
687 }
688
689 if (CallList.getInstance().getIncomingCall() != null) {
690 LogUtil.i(
691 "InCallActivity.onBackPressed",
692 "Ignore the press of the back key when an incoming call is ringing");
693 return;
694 }
695
696 // Nothing special to do. Fall back to the default behavior.
697 super.onBackPressed();
Eric Erfanianccca3152017-02-22 16:32:36 -0800698 }
699
700 @Override
701 public boolean onOptionsItemSelected(MenuItem item) {
702 LogUtil.i("InCallActivity.onOptionsItemSelected", "item: " + item);
703 if (item.getItemId() == android.R.id.home) {
704 onBackPressed();
705 return true;
706 }
707 return super.onOptionsItemSelected(item);
708 }
709
710 @Override
711 public boolean onKeyUp(int keyCode, KeyEvent event) {
linyuh57b093b2017-11-17 14:32:32 -0800712 DialpadFragment dialpadFragment = getDialpadFragment();
713 if (dialpadFragment != null
714 && dialpadFragment.isVisible()
715 && dialpadFragment.onDialerKeyUp(event)) {
716 return true;
717 }
718
719 if (keyCode == KeyEvent.KEYCODE_CALL) {
720 // Always consume KEYCODE_CALL to ensure the PhoneWindow won't do anything with it.
721 return true;
722 }
723
724 return super.onKeyUp(keyCode, event);
Eric Erfanianccca3152017-02-22 16:32:36 -0800725 }
726
727 @Override
728 public boolean onKeyDown(int keyCode, KeyEvent event) {
linyuh57b093b2017-11-17 14:32:32 -0800729 switch (keyCode) {
730 case KeyEvent.KEYCODE_CALL:
731 if (!InCallPresenter.getInstance().handleCallKey()) {
732 LogUtil.e(
733 "InCallActivity.onKeyDown",
734 "InCallPresenter should always handle KEYCODE_CALL in onKeyDown");
735 }
736 // Always consume KEYCODE_CALL to ensure the PhoneWindow won't do anything with it.
737 return true;
738
739 // Note that KEYCODE_ENDCALL isn't handled here as the standard system-wide handling of it
740 // is exactly what's needed, namely
741 // (1) "hang up" if there's an active call, or
742 // (2) "don't answer" if there's an incoming call.
743 // (See PhoneWindowManager for implementation details.)
744
745 case KeyEvent.KEYCODE_CAMERA:
746 // Consume KEYCODE_CAMERA since it's easy to accidentally press the camera button.
747 return true;
748
749 case KeyEvent.KEYCODE_VOLUME_UP:
750 case KeyEvent.KEYCODE_VOLUME_DOWN:
751 case KeyEvent.KEYCODE_VOLUME_MUTE:
752 // Ringer silencing handled by PhoneWindowManager.
753 break;
754
755 case KeyEvent.KEYCODE_MUTE:
756 TelecomAdapter.getInstance()
757 .mute(!AudioModeProvider.getInstance().getAudioState().isMuted());
758 return true;
759
760 case KeyEvent.KEYCODE_SLASH:
761 // When verbose logging is enabled, dump the view for debugging/testing purposes.
762 if (LogUtil.isVerboseEnabled()) {
763 View decorView = getWindow().getDecorView();
764 LogUtil.v("InCallActivity.onKeyDown", "View dump:\n%s", decorView);
765 return true;
766 }
767 break;
768
769 case KeyEvent.KEYCODE_EQUALS:
770 break;
771
772 default: // fall out
773 }
774
775 // Pass other key events to DialpadFragment's "onDialerKeyDown" method in case the user types
776 // in DTMF (Dual-tone multi-frequency signaling) code.
777 DialpadFragment dialpadFragment = getDialpadFragment();
778 if (dialpadFragment != null
779 && dialpadFragment.isVisible()
780 && dialpadFragment.onDialerKeyDown(event)) {
781 return true;
782 }
783
784 return super.onKeyDown(keyCode, event);
Eric Erfanianccca3152017-02-22 16:32:36 -0800785 }
786
787 public boolean isInCallScreenAnimating() {
788 return false;
789 }
790
791 public void showConferenceFragment(boolean show) {
792 if (show) {
793 startActivity(new Intent(this, ManageConferenceActivity.class));
794 }
795 }
796
linyuhc3968e62017-11-20 17:40:50 -0800797 public void showDialpadFragment(boolean show, boolean animate) {
798 if (show == isDialpadVisible()) {
799 return;
Eric Erfanianccca3152017-02-22 16:32:36 -0800800 }
linyuhc3968e62017-11-20 17:40:50 -0800801
802 FragmentManager dialpadFragmentManager = getDialpadFragmentManager();
803 if (dialpadFragmentManager == null) {
804 LogUtil.i("InCallActivity.showDialpadFragment", "Unable to obtain a FragmentManager");
805 return;
806 }
807
808 if (!animate) {
809 if (show) {
810 showDialpadFragment();
811 } else {
812 hideDialpadFragment();
813 }
814 } else {
815 if (show) {
816 showDialpadFragment();
817 getDialpadFragment().animateShowDialpad();
818 }
819 getDialpadFragment()
820 .getView()
821 .startAnimation(show ? dialpadSlideInAnimation : dialpadSlideOutAnimation);
822 }
823
824 ProximitySensor sensor = InCallPresenter.getInstance().getProximitySensor();
825 if (sensor != null) {
826 sensor.onDialpadVisible(show);
827 }
828 showDialpadRequest = DIALPAD_REQUEST_NONE;
829
830 // Note: onInCallScreenDialpadVisibilityChange is called here to ensure that the dialpad FAB
831 // repositions itself.
wangqifd4c9f72018-03-08 18:21:50 -0800832 getInCallOrRttCallScreen().onInCallScreenDialpadVisibilityChange(show);
linyuhc3968e62017-11-20 17:40:50 -0800833 }
834
835 private void showDialpadFragment() {
836 FragmentManager dialpadFragmentManager = getDialpadFragmentManager();
837 if (dialpadFragmentManager == null) {
838 return;
839 }
840
841 FragmentTransaction transaction = dialpadFragmentManager.beginTransaction();
842 DialpadFragment dialpadFragment = getDialpadFragment();
843 if (dialpadFragment == null) {
wangqifd4c9f72018-03-08 18:21:50 -0800844 dialpadFragment = new DialpadFragment();
845 transaction.add(getDialpadContainerId(), dialpadFragment, Tags.DIALPAD_FRAGMENT);
linyuhc3968e62017-11-20 17:40:50 -0800846 } else {
847 transaction.show(dialpadFragment);
calderwoodrad5883872017-12-12 15:29:12 -0800848 dialpadFragment.setUserVisibleHint(true);
linyuhc3968e62017-11-20 17:40:50 -0800849 }
wangqifd4c9f72018-03-08 18:21:50 -0800850 // RTT call screen doesn't show end call button inside dialpad, thus the space reserved for end
851 // call button should be removed.
852 dialpadFragment.setShouldShowEndCallSpace(didShowInCallScreen);
linyuhc3968e62017-11-20 17:40:50 -0800853 transaction.commitAllowingStateLoss();
854 dialpadFragmentManager.executePendingTransactions();
855
856 Logger.get(this).logScreenView(ScreenEvent.Type.INCALL_DIALPAD, this);
857 updateNavigationBar(true /* isDialpadVisible */);
858 }
859
860 private void hideDialpadFragment() {
861 FragmentManager dialpadFragmentManager = getDialpadFragmentManager();
862 if (dialpadFragmentManager == null) {
863 return;
864 }
865
calderwoodrad5883872017-12-12 15:29:12 -0800866 DialpadFragment dialpadFragment = getDialpadFragment();
linyuhc3968e62017-11-20 17:40:50 -0800867 if (dialpadFragment != null) {
868 FragmentTransaction transaction = dialpadFragmentManager.beginTransaction();
869 transaction.hide(dialpadFragment);
870 transaction.commitAllowingStateLoss();
871 dialpadFragmentManager.executePendingTransactions();
calderwoodrad5883872017-12-12 15:29:12 -0800872 dialpadFragment.setUserVisibleHint(false);
linyuhc3968e62017-11-20 17:40:50 -0800873 }
874 updateNavigationBar(false /* isDialpadVisible */);
Eric Erfanianccca3152017-02-22 16:32:36 -0800875 }
876
877 public boolean isDialpadVisible() {
linyuh69a25062017-11-15 16:18:51 -0800878 DialpadFragment dialpadFragment = getDialpadFragment();
calderwoodraa584bcd2018-01-24 12:19:56 -0800879 return dialpadFragment != null
880 && dialpadFragment.isAdded()
881 && !dialpadFragment.isHidden()
882 && dialpadFragment.getView() != null
883 && dialpadFragment.getUserVisibleHint();
linyuh69a25062017-11-15 16:18:51 -0800884 }
885
linyuhc3968e62017-11-20 17:40:50 -0800886 /** Returns the {@link DialpadFragment} that's shown by this activity, or {@code null} */
linyuh69a25062017-11-15 16:18:51 -0800887 @Nullable
linyuhc3968e62017-11-20 17:40:50 -0800888 private DialpadFragment getDialpadFragment() {
linyuh69a25062017-11-15 16:18:51 -0800889 FragmentManager fragmentManager = getDialpadFragmentManager();
890 if (fragmentManager == null) {
891 return null;
892 }
linyuhc3968e62017-11-20 17:40:50 -0800893 return (DialpadFragment) fragmentManager.findFragmentByTag(Tags.DIALPAD_FRAGMENT);
Eric Erfanianccca3152017-02-22 16:32:36 -0800894 }
895
896 public void onForegroundCallChanged(DialerCall newForegroundCall) {
linyuh57b093b2017-11-17 14:32:32 -0800897 updateTaskDescription();
898
899 if (newForegroundCall == null || !didShowAnswerScreen) {
Eric Erfanianccca3152017-02-22 16:32:36 -0800900 LogUtil.v("InCallActivity.onForegroundCallChanged", "resetting background color");
linyuh57b093b2017-11-17 14:32:32 -0800901 updateWindowBackgroundColor(0 /* progress */);
Eric Erfanianccca3152017-02-22 16:32:36 -0800902 }
903 }
904
linyuhc3968e62017-11-20 17:40:50 -0800905 private void updateTaskDescription() {
linyuh57b093b2017-11-17 14:32:32 -0800906 int color =
907 getResources().getBoolean(R.bool.is_layout_landscape)
908 ? ResourcesCompat.getColor(
909 getResources(), R.color.statusbar_background_color, getTheme())
910 : InCallPresenter.getInstance().getThemeColorManager().getSecondaryColor();
911 setTaskDescription(
912 new TaskDescription(
913 getResources().getString(R.string.notification_ongoing_call), null /* icon */, color));
914 }
915
Eric Erfanianccca3152017-02-22 16:32:36 -0800916 public void updateWindowBackgroundColor(@FloatRange(from = -1f, to = 1.0f) float progress) {
917 ThemeColorManager themeColorManager = InCallPresenter.getInstance().getThemeColorManager();
918 @ColorInt int top;
919 @ColorInt int middle;
920 @ColorInt int bottom;
921 @ColorInt int gray = 0x66000000;
922
linyuh437ae952018-03-26 12:46:18 -0700923 if (isInMultiWindowMode()) {
Eric Erfanianccca3152017-02-22 16:32:36 -0800924 top = themeColorManager.getBackgroundColorSolid();
925 middle = themeColorManager.getBackgroundColorSolid();
926 bottom = themeColorManager.getBackgroundColorSolid();
927 } else {
928 top = themeColorManager.getBackgroundColorTop();
929 middle = themeColorManager.getBackgroundColorMiddle();
930 bottom = themeColorManager.getBackgroundColorBottom();
931 }
932
933 if (progress < 0) {
934 float correctedProgress = Math.abs(progress);
935 top = ColorUtils.blendARGB(top, gray, correctedProgress);
936 middle = ColorUtils.blendARGB(middle, gray, correctedProgress);
937 bottom = ColorUtils.blendARGB(bottom, gray, correctedProgress);
938 }
939
940 boolean backgroundDirty = false;
941 if (backgroundDrawable == null) {
942 backgroundDrawableColors = new int[] {top, middle, bottom};
943 backgroundDrawable = new GradientDrawable(Orientation.TOP_BOTTOM, backgroundDrawableColors);
944 backgroundDirty = true;
945 } else {
946 if (backgroundDrawableColors[0] != top) {
947 backgroundDrawableColors[0] = top;
948 backgroundDirty = true;
949 }
950 if (backgroundDrawableColors[1] != middle) {
951 backgroundDrawableColors[1] = middle;
952 backgroundDirty = true;
953 }
954 if (backgroundDrawableColors[2] != bottom) {
955 backgroundDrawableColors[2] = bottom;
956 backgroundDirty = true;
957 }
958 if (backgroundDirty) {
959 backgroundDrawable.setColors(backgroundDrawableColors);
960 }
961 }
962
963 if (backgroundDirty) {
964 getWindow().setBackgroundDrawable(backgroundDrawable);
965 }
966 }
967
968 public boolean isVisible() {
969 return isVisible;
970 }
971
972 public boolean getCallCardFragmentVisible() {
erfaniand05d8992018-03-20 19:42:26 -0700973 return didShowInCallScreen
974 || didShowVideoCallScreen
975 || didShowRttCallScreen
976 || didShowSpeakEasyScreen;
Eric Erfanianccca3152017-02-22 16:32:36 -0800977 }
978
979 public void dismissKeyguard(boolean dismiss) {
linyuh9c327da2017-11-14 12:33:48 -0800980 if (dismissKeyguard == dismiss) {
981 return;
982 }
983
984 dismissKeyguard = dismiss;
985 if (dismiss) {
986 getWindow().addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);
987 } else {
988 getWindow().clearFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);
989 }
Eric Erfanianccca3152017-02-22 16:32:36 -0800990 }
991
linyuhc3968e62017-11-20 17:40:50 -0800992 public void showDialogForPostCharWait(String callId, String chars) {
993 if (isVisible) {
994 PostCharDialogFragment fragment = new PostCharDialogFragment(callId, chars);
995 fragment.show(getSupportFragmentManager(), Tags.POST_CHAR_DIALOG_FRAGMENT);
996
997 showPostCharWaitDialogOnResume = false;
998 showPostCharWaitDialogCallId = null;
999 showPostCharWaitDialogChars = null;
1000 } else {
1001 showPostCharWaitDialogOnResume = true;
1002 showPostCharWaitDialogCallId = callId;
1003 showPostCharWaitDialogChars = chars;
1004 }
Eric Erfanianccca3152017-02-22 16:32:36 -08001005 }
1006
linyuh7b86f562017-11-16 11:24:09 -08001007 public void showDialogOrToastForDisconnectedCall(DisconnectMessage disconnectMessage) {
1008 LogUtil.i(
1009 "InCallActivity.showDialogOrToastForDisconnectedCall",
1010 "disconnect cause: %s",
1011 disconnectMessage);
1012
1013 if (disconnectMessage.dialog == null || isFinishing()) {
1014 return;
1015 }
1016
1017 dismissPendingDialogs();
1018
1019 // Show a toast if the app is in background when a dialog can't be visible.
1020 if (!isVisible()) {
1021 Toast.makeText(getApplicationContext(), disconnectMessage.toastMessage, Toast.LENGTH_LONG)
1022 .show();
1023 return;
1024 }
1025
1026 // Show the dialog.
linyuhc3968e62017-11-20 17:40:50 -08001027 errorDialog = disconnectMessage.dialog;
linyuh7b86f562017-11-16 11:24:09 -08001028 InCallUiLock lock = InCallPresenter.getInstance().acquireInCallUiLock("showErrorDialog");
1029 disconnectMessage.dialog.setOnDismissListener(
1030 dialogInterface -> {
1031 lock.release();
1032 onDialogDismissed();
1033 });
1034 disconnectMessage.dialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
1035 disconnectMessage.dialog.show();
1036 }
1037
1038 private void onDialogDismissed() {
linyuhc3968e62017-11-20 17:40:50 -08001039 errorDialog = null;
linyuh7b86f562017-11-16 11:24:09 -08001040 CallList.getInstance().onErrorDialogDismissed();
Eric Erfanianccca3152017-02-22 16:32:36 -08001041 }
1042
1043 public void dismissPendingDialogs() {
linyuhc3968e62017-11-20 17:40:50 -08001044 LogUtil.enterBlock("InCallActivity.dismissPendingDialogs");
linyuhf99f6302017-11-15 11:23:51 -08001045
1046 if (!isVisible) {
1047 // Defer the dismissing action as the activity is not visible and onSaveInstanceState may have
1048 // been called.
Eric Erfanianccca3152017-02-22 16:32:36 -08001049 LogUtil.i(
1050 "InCallActivity.dismissPendingDialogs", "defer actions since activity is not visible");
1051 needDismissPendingDialogs = true;
linyuhf99f6302017-11-15 11:23:51 -08001052 return;
Eric Erfanianccca3152017-02-22 16:32:36 -08001053 }
linyuhf99f6302017-11-15 11:23:51 -08001054
1055 // Dismiss the error dialog
linyuhf99f6302017-11-15 11:23:51 -08001056 if (errorDialog != null) {
1057 errorDialog.dismiss();
linyuhc3968e62017-11-20 17:40:50 -08001058 errorDialog = null;
linyuhf99f6302017-11-15 11:23:51 -08001059 }
1060
1061 // Dismiss the phone account selection dialog
linyuhf99f6302017-11-15 11:23:51 -08001062 if (selectPhoneAccountDialogFragment != null) {
1063 selectPhoneAccountDialogFragment.dismiss();
linyuhc3968e62017-11-20 17:40:50 -08001064 selectPhoneAccountDialogFragment = null;
linyuhf99f6302017-11-15 11:23:51 -08001065 }
1066
1067 // Dismiss the dialog for international call on WiFi
1068 InternationalCallOnWifiDialogFragment internationalCallOnWifiFragment =
1069 (InternationalCallOnWifiDialogFragment)
linyuhc3968e62017-11-20 17:40:50 -08001070 getSupportFragmentManager().findFragmentByTag(Tags.INTERNATIONAL_CALL_ON_WIFI);
linyuhf99f6302017-11-15 11:23:51 -08001071 if (internationalCallOnWifiFragment != null) {
1072 internationalCallOnWifiFragment.dismiss();
1073 }
1074
1075 // Dismiss the answer screen
1076 AnswerScreen answerScreen = getAnswerScreen();
1077 if (answerScreen != null) {
1078 answerScreen.dismissPendingDialogs();
1079 }
1080
1081 needDismissPendingDialogs = false;
Eric Erfanianccca3152017-02-22 16:32:36 -08001082 }
1083
linyuhc3968e62017-11-20 17:40:50 -08001084 private void enableInCallOrientationEventListener(boolean enable) {
linyuh69a25062017-11-15 16:18:51 -08001085 if (enable) {
1086 inCallOrientationEventListener.enable(true /* notifyDeviceOrientationChange */);
1087 } else {
1088 inCallOrientationEventListener.disable();
1089 }
Eric Erfanianccca3152017-02-22 16:32:36 -08001090 }
1091
1092 public void setExcludeFromRecents(boolean exclude) {
linyuhc3968e62017-11-20 17:40:50 -08001093 int taskId = getTaskId();
1094
1095 List<AppTask> tasks = getSystemService(ActivityManager.class).getAppTasks();
1096 for (AppTask task : tasks) {
1097 try {
1098 if (task.getTaskInfo().id == taskId) {
1099 task.setExcludeFromRecents(exclude);
1100 }
1101 } catch (RuntimeException e) {
1102 LogUtil.e("InCallActivity.setExcludeFromRecents", "RuntimeException:\n%s", e);
1103 }
1104 }
Eric Erfanianccca3152017-02-22 16:32:36 -08001105 }
1106
Eric Erfanianccca3152017-02-22 16:32:36 -08001107 @Nullable
1108 public FragmentManager getDialpadFragmentManager() {
wangqifd4c9f72018-03-08 18:21:50 -08001109 InCallScreen inCallScreen = getInCallOrRttCallScreen();
Eric Erfanianccca3152017-02-22 16:32:36 -08001110 if (inCallScreen != null) {
1111 return inCallScreen.getInCallScreenFragment().getChildFragmentManager();
1112 }
1113 return null;
1114 }
1115
1116 public int getDialpadContainerId() {
wangqifd4c9f72018-03-08 18:21:50 -08001117 return getInCallOrRttCallScreen().getAnswerAndDialpadContainerResourceId();
Eric Erfanianccca3152017-02-22 16:32:36 -08001118 }
1119
1120 @Override
1121 public AnswerScreenDelegate newAnswerScreenDelegate(AnswerScreen answerScreen) {
1122 DialerCall call = CallList.getInstance().getCallById(answerScreen.getCallId());
1123 if (call == null) {
1124 // This is a work around for a bug where we attempt to create a new delegate after the call
1125 // has already been removed. An example of when this can happen is:
1126 // 1. incoming video call in landscape mode
1127 // 2. remote party hangs up
1128 // 3. activity switches from landscape to portrait
1129 // At step #3 the answer fragment will try to create a new answer delegate but the call won't
1130 // exist. In this case we'll simply return a stub delegate that does nothing. This is ok
1131 // because this new state is transient and the activity will be destroyed soon.
1132 LogUtil.i("InCallActivity.onPrimaryCallStateChanged", "call doesn't exist, using stub");
1133 return new AnswerScreenPresenterStub();
1134 } else {
1135 return new AnswerScreenPresenter(
1136 this, answerScreen, CallList.getInstance().getCallById(answerScreen.getCallId()));
1137 }
1138 }
1139
1140 @Override
1141 public InCallScreenDelegate newInCallScreenDelegate() {
1142 return new CallCardPresenter(this);
1143 }
1144
1145 @Override
1146 public InCallButtonUiDelegate newInCallButtonUiDelegate() {
1147 return new CallButtonPresenter(this);
1148 }
1149
1150 @Override
Eric Erfanian90508232017-03-24 09:31:16 -07001151 public VideoCallScreenDelegate newVideoCallScreenDelegate(VideoCallScreen videoCallScreen) {
1152 DialerCall dialerCall = CallList.getInstance().getCallById(videoCallScreen.getCallId());
1153 if (dialerCall != null && dialerCall.getVideoTech().shouldUseSurfaceView()) {
1154 return dialerCall.getVideoTech().createVideoCallScreenDelegate(this, videoCallScreen);
1155 }
Eric Erfanianccca3152017-02-22 16:32:36 -08001156 return new VideoCallPresenter();
1157 }
1158
1159 public void onPrimaryCallStateChanged() {
Eric Erfanian2ca43182017-08-31 06:57:16 -07001160 Trace.beginSection("InCallActivity.onPrimaryCallStateChanged");
Eric Erfanianccca3152017-02-22 16:32:36 -08001161 showMainInCallFragment();
Eric Erfanian2ca43182017-08-31 06:57:16 -07001162 Trace.endSection();
Eric Erfanianccca3152017-02-22 16:32:36 -08001163 }
1164
linyuh7b86f562017-11-16 11:24:09 -08001165 public void showDialogOrToastForWifiHandoverFailure(DialerCall call) {
1166 if (call.showWifiHandoverAlertAsToast()) {
1167 Toast.makeText(this, R.string.video_call_lte_to_wifi_failed_message, Toast.LENGTH_SHORT)
1168 .show();
1169 return;
1170 }
1171
1172 dismissPendingDialogs();
1173
1174 AlertDialog.Builder builder =
1175 new AlertDialog.Builder(this).setTitle(R.string.video_call_lte_to_wifi_failed_title);
1176
1177 // This allows us to use the theme of the dialog instead of the activity
1178 View dialogCheckBoxView =
1179 View.inflate(builder.getContext(), R.layout.video_call_lte_to_wifi_failed, null /* root */);
1180 CheckBox wifiHandoverFailureCheckbox =
1181 (CheckBox) dialogCheckBoxView.findViewById(R.id.video_call_lte_to_wifi_failed_checkbox);
1182 wifiHandoverFailureCheckbox.setChecked(false);
1183
1184 InCallUiLock lock = InCallPresenter.getInstance().acquireInCallUiLock("WifiFailedDialog");
linyuhc3968e62017-11-20 17:40:50 -08001185 errorDialog =
linyuh7b86f562017-11-16 11:24:09 -08001186 builder
1187 .setView(dialogCheckBoxView)
1188 .setMessage(R.string.video_call_lte_to_wifi_failed_message)
1189 .setOnCancelListener(dialogInterface -> onDialogDismissed())
1190 .setPositiveButton(
1191 android.R.string.ok,
1192 (dialogInterface, id) -> {
1193 call.setDoNotShowDialogForHandoffToWifiFailure(
1194 wifiHandoverFailureCheckbox.isChecked());
1195 dialogInterface.cancel();
1196 onDialogDismissed();
1197 })
1198 .setOnDismissListener(dialogInterface -> lock.release())
1199 .create();
linyuh7b86f562017-11-16 11:24:09 -08001200 errorDialog.show();
Eric Erfanianccca3152017-02-22 16:32:36 -08001201 }
1202
linyuh7b86f562017-11-16 11:24:09 -08001203 public void showDialogForInternationalCallOnWifi(@NonNull DialerCall call) {
1204 if (!InternationalCallOnWifiDialogFragment.shouldShow(this)) {
1205 LogUtil.i(
1206 "InCallActivity.showDialogForInternationalCallOnWifi",
1207 "InternationalCallOnWifiDialogFragment.shouldShow returned false");
1208 return;
1209 }
1210
1211 InternationalCallOnWifiDialogFragment fragment =
1212 InternationalCallOnWifiDialogFragment.newInstance(
linyuhc3968e62017-11-20 17:40:50 -08001213 call.getId(), internationalCallOnWifiCallback);
1214 fragment.show(getSupportFragmentManager(), Tags.INTERNATIONAL_CALL_ON_WIFI);
Eric Erfanianc857f902017-05-15 14:05:33 -07001215 }
1216
wangqibc28ea72018-04-02 16:23:00 -07001217 public void showDialogForRttRequest(DialerCall call, int rttRequestId) {
1218 LogUtil.enterBlock("InCallActivity.showDialogForRttRequest");
1219 DialogFragment fragment = RttRequestDialogFragment.newInstance(call.getId(), rttRequestId);
1220 fragment.show(getSupportFragmentManager(), Tags.RTT_REQUEST_DIALOG);
1221 }
1222
Eric Erfanian938468d2017-10-24 14:05:52 -07001223 @Override
1224 public void onMultiWindowModeChanged(boolean isInMultiWindowMode) {
1225 super.onMultiWindowModeChanged(isInMultiWindowMode);
linyuh57b093b2017-11-17 14:32:32 -08001226 updateNavigationBar(isDialpadVisible());
1227 }
1228
linyuhc3968e62017-11-20 17:40:50 -08001229 private void updateNavigationBar(boolean isDialpadVisible) {
linyuh437ae952018-03-26 12:46:18 -07001230 if (isInMultiWindowMode()) {
linyuh57b093b2017-11-17 14:32:32 -08001231 return;
1232 }
1233
1234 View navigationBarBackground = getWindow().findViewById(R.id.navigation_bar_background);
1235 if (navigationBarBackground != null) {
1236 navigationBarBackground.setVisibility(isDialpadVisible ? View.VISIBLE : View.GONE);
Eric Erfanian938468d2017-10-24 14:05:52 -07001237 }
1238 }
1239
Eric Erfanianccca3152017-02-22 16:32:36 -08001240 public void setAllowOrientationChange(boolean allowOrientationChange) {
wangqi9982f0d2017-10-11 17:46:07 -07001241 if (this.allowOrientationChange == allowOrientationChange) {
1242 return;
1243 }
1244 this.allowOrientationChange = allowOrientationChange;
Eric Erfanianccca3152017-02-22 16:32:36 -08001245 if (!allowOrientationChange) {
1246 setRequestedOrientation(InCallOrientationEventListener.ACTIVITY_PREFERENCE_DISALLOW_ROTATION);
1247 } else {
1248 setRequestedOrientation(InCallOrientationEventListener.ACTIVITY_PREFERENCE_ALLOW_ROTATION);
1249 }
1250 enableInCallOrientationEventListener(allowOrientationChange);
1251 }
1252
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001253 public void hideMainInCallFragment() {
linyuhc3968e62017-11-20 17:40:50 -08001254 LogUtil.enterBlock("InCallActivity.hideMainInCallFragment");
1255 if (getCallCardFragmentVisible()) {
Eric Erfanianccca3152017-02-22 16:32:36 -08001256 FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
1257 hideInCallScreenFragment(transaction);
1258 hideVideoCallScreenFragment(transaction);
1259 transaction.commitAllowingStateLoss();
1260 getSupportFragmentManager().executePendingTransactions();
1261 }
1262 }
1263
1264 private void showMainInCallFragment() {
Eric Erfanian2ca43182017-08-31 06:57:16 -07001265 Trace.beginSection("InCallActivity.showMainInCallFragment");
Eric Erfanianccca3152017-02-22 16:32:36 -08001266 // If the activity's onStart method hasn't been called yet then defer doing any work.
1267 if (!isVisible) {
1268 LogUtil.i("InCallActivity.showMainInCallFragment", "not visible yet/anymore");
Eric Erfanian2ca43182017-08-31 06:57:16 -07001269 Trace.endSection();
Eric Erfanianccca3152017-02-22 16:32:36 -08001270 return;
1271 }
1272
1273 // Don't let this be reentrant.
1274 if (isInShowMainInCallFragment) {
1275 LogUtil.i("InCallActivity.showMainInCallFragment", "already in method, bailing");
Eric Erfanian2ca43182017-08-31 06:57:16 -07001276 Trace.endSection();
Eric Erfanianccca3152017-02-22 16:32:36 -08001277 return;
1278 }
1279
1280 isInShowMainInCallFragment = true;
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001281 ShouldShowUiResult shouldShowAnswerUi = getShouldShowAnswerUi();
1282 ShouldShowUiResult shouldShowVideoUi = getShouldShowVideoUi();
wangqi219b8702018-02-13 09:34:41 -08001283 ShouldShowUiResult shouldShowRttUi = getShouldShowRttUi();
erfaniand05d8992018-03-20 19:42:26 -07001284 ShouldShowUiResult shouldShowSpeakEasyUi = getShouldShowSpeakEasyUi();
Eric Erfanianccca3152017-02-22 16:32:36 -08001285 LogUtil.i(
1286 "InCallActivity.showMainInCallFragment",
wangqi219b8702018-02-13 09:34:41 -08001287 "shouldShowAnswerUi: %b, shouldShowRttUi: %b, shouldShowVideoUi: %b "
1288 + "didShowAnswerScreen: %b, didShowInCallScreen: %b, didShowRttCallScreen: %b, "
erfaniand05d8992018-03-20 19:42:26 -07001289 + "didShowVideoCallScreen: %b"
1290 + "didShowSpeakEasyScreen: %b",
Eric Erfanianccca3152017-02-22 16:32:36 -08001291 shouldShowAnswerUi.shouldShow,
wangqi219b8702018-02-13 09:34:41 -08001292 shouldShowRttUi.shouldShow,
Eric Erfanian10b34a52017-05-04 08:23:17 -07001293 shouldShowVideoUi.shouldShow,
Eric Erfanianccca3152017-02-22 16:32:36 -08001294 didShowAnswerScreen,
1295 didShowInCallScreen,
wangqi219b8702018-02-13 09:34:41 -08001296 didShowRttCallScreen,
erfaniand05d8992018-03-20 19:42:26 -07001297 didShowVideoCallScreen,
1298 didShowSpeakEasyScreen);
Eric Erfanianccca3152017-02-22 16:32:36 -08001299 // Only video call ui allows orientation change.
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001300 setAllowOrientationChange(shouldShowVideoUi.shouldShow);
Eric Erfanianccca3152017-02-22 16:32:36 -08001301
1302 FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
wangqi219b8702018-02-13 09:34:41 -08001303 boolean didChange;
Eric Erfanianccca3152017-02-22 16:32:36 -08001304 if (shouldShowAnswerUi.shouldShow) {
wangqi219b8702018-02-13 09:34:41 -08001305 didChange = hideInCallScreenFragment(transaction);
1306 didChange |= hideVideoCallScreenFragment(transaction);
1307 didChange |= hideRttCallScreenFragment(transaction);
erfaniand05d8992018-03-20 19:42:26 -07001308 didChange |= hideSpeakEasyFragment(transaction);
wangqi219b8702018-02-13 09:34:41 -08001309 didChange |= showAnswerScreenFragment(transaction, shouldShowAnswerUi.call);
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001310 } else if (shouldShowVideoUi.shouldShow) {
wangqi219b8702018-02-13 09:34:41 -08001311 didChange = hideInCallScreenFragment(transaction);
1312 didChange |= showVideoCallScreenFragment(transaction, shouldShowVideoUi.call);
1313 didChange |= hideRttCallScreenFragment(transaction);
erfaniand05d8992018-03-20 19:42:26 -07001314 didChange |= hideSpeakEasyFragment(transaction);
wangqi219b8702018-02-13 09:34:41 -08001315 didChange |= hideAnswerScreenFragment(transaction);
1316 } else if (shouldShowRttUi.shouldShow) {
1317 didChange = hideInCallScreenFragment(transaction);
1318 didChange |= hideVideoCallScreenFragment(transaction);
1319 didChange |= hideAnswerScreenFragment(transaction);
erfaniand05d8992018-03-20 19:42:26 -07001320 didChange |= hideSpeakEasyFragment(transaction);
wangqi219b8702018-02-13 09:34:41 -08001321 didChange |= showRttCallScreenFragment(transaction, shouldShowRttUi.call);
erfaniand05d8992018-03-20 19:42:26 -07001322 } else if (shouldShowSpeakEasyUi.shouldShow) {
1323 didChange = hideInCallScreenFragment(transaction);
1324 didChange |= hideVideoCallScreenFragment(transaction);
1325 didChange |= hideAnswerScreenFragment(transaction);
1326 didChange |= hideRttCallScreenFragment(transaction);
1327 didChange |= showSpeakEasyFragment(transaction, shouldShowSpeakEasyUi.call);
Eric Erfanianccca3152017-02-22 16:32:36 -08001328 } else {
wangqi219b8702018-02-13 09:34:41 -08001329 didChange = showInCallScreenFragment(transaction);
1330 didChange |= hideVideoCallScreenFragment(transaction);
1331 didChange |= hideRttCallScreenFragment(transaction);
erfaniand05d8992018-03-20 19:42:26 -07001332 didChange |= hideSpeakEasyFragment(transaction);
wangqi219b8702018-02-13 09:34:41 -08001333 didChange |= hideAnswerScreenFragment(transaction);
Eric Erfanianccca3152017-02-22 16:32:36 -08001334 }
1335
wangqi219b8702018-02-13 09:34:41 -08001336 if (didChange) {
Eric Erfanian2ca43182017-08-31 06:57:16 -07001337 Trace.beginSection("InCallActivity.commitTransaction");
Eric Erfanianccca3152017-02-22 16:32:36 -08001338 transaction.commitNow();
Eric Erfanian2ca43182017-08-31 06:57:16 -07001339 Trace.endSection();
Eric Erfanianccca3152017-02-22 16:32:36 -08001340 Logger.get(this).logScreenView(ScreenEvent.Type.INCALL, this);
1341 }
1342 isInShowMainInCallFragment = false;
Eric Erfanian2ca43182017-08-31 06:57:16 -07001343 Trace.endSection();
Eric Erfanianccca3152017-02-22 16:32:36 -08001344 }
1345
erfaniand05d8992018-03-20 19:42:26 -07001346 private boolean showSpeakEasyFragment(FragmentTransaction transaction, DialerCall call) {
1347
erfaniand05d8992018-03-20 19:42:26 -07001348 if (didShowSpeakEasyScreen) {
erfanian612d13a2018-04-04 15:27:57 -07001349 if (lastShownSpeakEasyScreenUniqueCallid.equals(call.getUniqueCallId())) {
erfanian12243de2018-04-17 12:17:08 -07001350 LogUtil.i("InCallActivity.showSpeakEasyFragment", "found existing fragment");
erfanian612d13a2018-04-04 15:27:57 -07001351 return false;
1352 }
1353 hideSpeakEasyFragment(transaction);
erfanian12243de2018-04-17 12:17:08 -07001354 LogUtil.i("InCallActivity.showSpeakEasyFragment", "hid existing fragment");
erfaniand05d8992018-03-20 19:42:26 -07001355 }
1356
1357 Optional<Fragment> speakEasyFragment = speakEasyCallManager.getSpeakEasyFragment(call);
1358 if (speakEasyFragment.isPresent()) {
1359 transaction.add(R.id.main, speakEasyFragment.get(), Tags.SPEAK_EASY_SCREEN);
1360 didShowSpeakEasyScreen = true;
erfanian612d13a2018-04-04 15:27:57 -07001361 lastShownSpeakEasyScreenUniqueCallid = call.getUniqueCallId();
erfanian12243de2018-04-17 12:17:08 -07001362 LogUtil.i(
1363 "InCallActivity.showSpeakEasyFragment",
1364 "set fragment for call %s",
1365 lastShownSpeakEasyScreenUniqueCallid);
erfaniand05d8992018-03-20 19:42:26 -07001366 return true;
1367 }
1368 return false;
1369 }
1370
1371 private Fragment getSpeakEasyScreen() {
1372 return getSupportFragmentManager().findFragmentByTag(Tags.SPEAK_EASY_SCREEN);
1373 }
1374
1375 private boolean hideSpeakEasyFragment(FragmentTransaction transaction) {
1376 if (!didShowSpeakEasyScreen) {
1377 return false;
1378 }
1379
1380 Fragment speakEasyFragment = getSpeakEasyScreen();
1381
1382 if (speakEasyFragment != null) {
1383 transaction.remove(speakEasyFragment);
1384 didShowSpeakEasyScreen = false;
1385 return true;
1386 }
1387 return false;
1388 }
1389
erfanian12243de2018-04-17 12:17:08 -07001390 @VisibleForTesting
erfaniand05d8992018-03-20 19:42:26 -07001391 public void setSpeakEasyCallManager(SpeakEasyCallManager speakEasyCallManager) {
erfanian87dbb622018-04-04 15:43:00 -07001392 this.speakEasyCallManager = speakEasyCallManager;
erfaniand05d8992018-03-20 19:42:26 -07001393 }
1394
erfanian12243de2018-04-17 12:17:08 -07001395 @Nullable
erfaniand05d8992018-03-20 19:42:26 -07001396 public SpeakEasyCallManager getSpeakEasyCallManager() {
erfanian12243de2018-04-17 12:17:08 -07001397 if (this.speakEasyCallManager == null) {
1398 this.speakEasyCallManager = InCallPresenter.getInstance().getSpeakEasyCallManager();
1399 }
erfaniand05d8992018-03-20 19:42:26 -07001400 return speakEasyCallManager;
1401 }
1402
1403 private ShouldShowUiResult getShouldShowSpeakEasyUi() {
1404 SpeakEasyCallManager speakEasyCallManager = getSpeakEasyCallManager();
1405
1406 if (speakEasyCallManager == null) {
1407 return new ShouldShowUiResult(false, null);
1408 }
1409
erfanian3bb7cb62018-04-11 09:01:15 -07001410 DialerCall call =
1411 CallList.getInstance().getIncomingCall() != null
1412 ? CallList.getInstance().getIncomingCall()
1413 : CallList.getInstance().getActiveCall();
erfaniand05d8992018-03-20 19:42:26 -07001414
1415 if (call == null) {
1416 return new ShouldShowUiResult(false, call);
1417 }
1418
1419 if (!call.isSpeakEasyCall() || !call.isSpeakEasyEligible()) {
1420 return new ShouldShowUiResult(false, call);
1421 }
1422
1423 Optional<Fragment> speakEasyFragment = speakEasyCallManager.getSpeakEasyFragment(call);
1424
1425 if (!speakEasyFragment.isPresent()) {
1426 return new ShouldShowUiResult(false, call);
1427 }
1428 return new ShouldShowUiResult(true, call);
1429 }
1430
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001431 private ShouldShowUiResult getShouldShowAnswerUi() {
Eric Erfanianccca3152017-02-22 16:32:36 -08001432 DialerCall call = CallList.getInstance().getIncomingCall();
erfanian3bb7cb62018-04-11 09:01:15 -07001433 if (call != null && !call.isSpeakEasyCall()) {
Eric Erfanianccca3152017-02-22 16:32:36 -08001434 LogUtil.i("InCallActivity.getShouldShowAnswerUi", "found incoming call");
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001435 return new ShouldShowUiResult(true, call);
Eric Erfanianccca3152017-02-22 16:32:36 -08001436 }
1437
1438 call = CallList.getInstance().getVideoUpgradeRequestCall();
1439 if (call != null) {
1440 LogUtil.i("InCallActivity.getShouldShowAnswerUi", "found video upgrade request");
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001441 return new ShouldShowUiResult(true, call);
Eric Erfanianccca3152017-02-22 16:32:36 -08001442 }
1443
1444 // Check if we're showing the answer screen and the call is disconnected. If this condition is
1445 // true then we won't switch from the answer UI to the in call UI. This prevents flicker when
1446 // the user rejects an incoming call.
1447 call = CallList.getInstance().getFirstCall();
1448 if (call == null) {
1449 call = CallList.getInstance().getBackgroundCall();
1450 }
1451 if (didShowAnswerScreen && (call == null || call.getState() == State.DISCONNECTED)) {
1452 LogUtil.i("InCallActivity.getShouldShowAnswerUi", "found disconnecting incoming call");
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001453 return new ShouldShowUiResult(true, call);
Eric Erfanianccca3152017-02-22 16:32:36 -08001454 }
1455
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001456 return new ShouldShowUiResult(false, null);
Eric Erfanianccca3152017-02-22 16:32:36 -08001457 }
1458
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001459 private static ShouldShowUiResult getShouldShowVideoUi() {
Eric Erfanianccca3152017-02-22 16:32:36 -08001460 DialerCall call = CallList.getInstance().getFirstCall();
1461 if (call == null) {
1462 LogUtil.i("InCallActivity.getShouldShowVideoUi", "null call");
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001463 return new ShouldShowUiResult(false, null);
Eric Erfanianccca3152017-02-22 16:32:36 -08001464 }
1465
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001466 if (call.isVideoCall()) {
Eric Erfanianccca3152017-02-22 16:32:36 -08001467 LogUtil.i("InCallActivity.getShouldShowVideoUi", "found video call");
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001468 return new ShouldShowUiResult(true, call);
Eric Erfanianccca3152017-02-22 16:32:36 -08001469 }
1470
linyuh8fbecce2017-12-18 13:53:09 -08001471 if (call.hasSentVideoUpgradeRequest() || call.hasReceivedVideoUpgradeRequest()) {
Eric Erfanianccca3152017-02-22 16:32:36 -08001472 LogUtil.i("InCallActivity.getShouldShowVideoUi", "upgrading to video");
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001473 return new ShouldShowUiResult(true, call);
Eric Erfanianccca3152017-02-22 16:32:36 -08001474 }
1475
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001476 return new ShouldShowUiResult(false, null);
Eric Erfanianccca3152017-02-22 16:32:36 -08001477 }
1478
wangqi219b8702018-02-13 09:34:41 -08001479 private static ShouldShowUiResult getShouldShowRttUi() {
1480 DialerCall call = CallList.getInstance().getFirstCall();
1481 if (call == null) {
1482 LogUtil.i("InCallActivity.getShouldShowRttUi", "null call");
1483 return new ShouldShowUiResult(false, null);
1484 }
1485
wangqif6be6172018-03-30 15:57:56 -07001486 if (call.isActiveRttCall()) {
wangqi219b8702018-02-13 09:34:41 -08001487 LogUtil.i("InCallActivity.getShouldShowRttUi", "found rtt call");
1488 return new ShouldShowUiResult(true, call);
1489 }
1490
1491 if (call.hasSentRttUpgradeRequest()) {
1492 LogUtil.i("InCallActivity.getShouldShowRttUi", "upgrading to rtt");
1493 return new ShouldShowUiResult(true, call);
1494 }
1495
1496 return new ShouldShowUiResult(false, null);
1497 }
1498
Eric Erfanianccca3152017-02-22 16:32:36 -08001499 private boolean showAnswerScreenFragment(FragmentTransaction transaction, DialerCall call) {
1500 // When rejecting a call the active call can become null in which case we should continue
1501 // showing the answer screen.
1502 if (didShowAnswerScreen && call == null) {
1503 return false;
1504 }
1505
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001506 Assert.checkArgument(call != null, "didShowAnswerScreen was false but call was still null");
1507
1508 boolean isVideoUpgradeRequest = call.hasReceivedVideoUpgradeRequest();
Eric Erfanianccca3152017-02-22 16:32:36 -08001509
1510 // Check if we're already showing an answer screen for this call.
1511 if (didShowAnswerScreen) {
1512 AnswerScreen answerScreen = getAnswerScreen();
1513 if (answerScreen.getCallId().equals(call.getId())
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001514 && answerScreen.isVideoCall() == call.isVideoCall()
Eric Erfanian2ca43182017-08-31 06:57:16 -07001515 && answerScreen.isVideoUpgradeRequest() == isVideoUpgradeRequest
1516 && !answerScreen.isActionTimeout()) {
1517 LogUtil.d(
1518 "InCallActivity.showAnswerScreenFragment",
1519 "answer fragment exists for same call and has NOT been accepted/rejected/timed out");
Eric Erfanianccca3152017-02-22 16:32:36 -08001520 return false;
1521 }
Eric Erfanian2ca43182017-08-31 06:57:16 -07001522 if (answerScreen.isActionTimeout()) {
1523 LogUtil.i(
1524 "InCallActivity.showAnswerScreenFragment",
1525 "answer fragment exists but has been accepted/rejected and timed out");
1526 } else {
1527 LogUtil.i(
1528 "InCallActivity.showAnswerScreenFragment",
1529 "answer fragment exists but arguments do not match");
1530 }
Eric Erfanianccca3152017-02-22 16:32:36 -08001531 hideAnswerScreenFragment(transaction);
1532 }
1533
1534 // Show a new answer screen.
1535 AnswerScreen answerScreen =
Eric Erfanianfc37b022017-03-21 10:11:17 -07001536 AnswerBindings.createAnswerScreen(
1537 call.getId(),
wangqif6be6172018-03-30 15:57:56 -07001538 call.isActiveRttCall(),
Eric Erfanianfc37b022017-03-21 10:11:17 -07001539 call.isVideoCall(),
1540 isVideoUpgradeRequest,
Eric Erfanian90508232017-03-24 09:31:16 -07001541 call.getVideoTech().isSelfManagedCamera(),
1542 shouldAllowAnswerAndRelease(call),
erfaniand05d8992018-03-20 19:42:26 -07001543 CallList.getInstance().getBackgroundCall() != null,
1544 call.isSpeakEasyEligible());
linyuhc3968e62017-11-20 17:40:50 -08001545 transaction.add(R.id.main, answerScreen.getAnswerScreenFragment(), Tags.ANSWER_SCREEN);
Eric Erfanianccca3152017-02-22 16:32:36 -08001546
1547 Logger.get(this).logScreenView(ScreenEvent.Type.INCOMING_CALL, this);
1548 didShowAnswerScreen = true;
1549 return true;
1550 }
1551
Eric Erfanian90508232017-03-24 09:31:16 -07001552 private boolean shouldAllowAnswerAndRelease(DialerCall call) {
1553 if (CallList.getInstance().getActiveCall() == null) {
1554 LogUtil.i("InCallActivity.shouldAllowAnswerAndRelease", "no active call");
1555 return false;
1556 }
1557 if (getSystemService(TelephonyManager.class).getPhoneType()
1558 == TelephonyManager.PHONE_TYPE_CDMA) {
1559 LogUtil.i("InCallActivity.shouldAllowAnswerAndRelease", "PHONE_TYPE_CDMA not supported");
1560 return false;
1561 }
1562 if (call.isVideoCall() || call.hasReceivedVideoUpgradeRequest()) {
1563 LogUtil.i("InCallActivity.shouldAllowAnswerAndRelease", "video call");
1564 return false;
1565 }
linyuhc3968e62017-11-20 17:40:50 -08001566 if (!ConfigProviderBindings.get(this)
1567 .getBoolean(ConfigNames.ANSWER_AND_RELEASE_ENABLED, true)) {
Eric Erfanian90508232017-03-24 09:31:16 -07001568 LogUtil.i("InCallActivity.shouldAllowAnswerAndRelease", "disabled by config");
1569 return false;
1570 }
1571
1572 return true;
1573 }
1574
Eric Erfanianccca3152017-02-22 16:32:36 -08001575 private boolean hideAnswerScreenFragment(FragmentTransaction transaction) {
1576 if (!didShowAnswerScreen) {
1577 return false;
1578 }
1579 AnswerScreen answerScreen = getAnswerScreen();
1580 if (answerScreen != null) {
1581 transaction.remove(answerScreen.getAnswerScreenFragment());
1582 }
1583
1584 didShowAnswerScreen = false;
1585 return true;
1586 }
1587
1588 private boolean showInCallScreenFragment(FragmentTransaction transaction) {
1589 if (didShowInCallScreen) {
1590 return false;
1591 }
Eric Erfanian2ca43182017-08-31 06:57:16 -07001592 InCallScreen inCallScreen = InCallBindings.createInCallScreen();
linyuhc3968e62017-11-20 17:40:50 -08001593 transaction.add(R.id.main, inCallScreen.getInCallScreenFragment(), Tags.IN_CALL_SCREEN);
Eric Erfanianccca3152017-02-22 16:32:36 -08001594 Logger.get(this).logScreenView(ScreenEvent.Type.INCALL, this);
1595 didShowInCallScreen = true;
1596 return true;
1597 }
1598
1599 private boolean hideInCallScreenFragment(FragmentTransaction transaction) {
1600 if (!didShowInCallScreen) {
1601 return false;
1602 }
1603 InCallScreen inCallScreen = getInCallScreen();
1604 if (inCallScreen != null) {
Eric Erfanian2ca43182017-08-31 06:57:16 -07001605 transaction.remove(inCallScreen.getInCallScreenFragment());
Eric Erfanianccca3152017-02-22 16:32:36 -08001606 }
1607 didShowInCallScreen = false;
1608 return true;
1609 }
1610
wangqi219b8702018-02-13 09:34:41 -08001611 private boolean showRttCallScreenFragment(FragmentTransaction transaction, DialerCall call) {
1612 if (didShowRttCallScreen) {
1613 // This shouldn't happen since only one RTT call is allow at same time.
1614 if (!getRttCallScreen().getCallId().equals(call.getId())) {
1615 LogUtil.e("InCallActivity.showRttCallScreenFragment", "RTT call id doesn't match");
1616 }
1617 return false;
1618 }
1619 RttCallScreen rttCallScreen = RttBindings.createRttCallScreen(call.getId());
1620 transaction.add(R.id.main, rttCallScreen.getRttCallScreenFragment(), Tags.RTT_CALL_SCREEN);
1621 Logger.get(this).logScreenView(ScreenEvent.Type.INCALL, this);
1622 didShowRttCallScreen = true;
1623 return true;
1624 }
1625
1626 private boolean hideRttCallScreenFragment(FragmentTransaction transaction) {
1627 if (!didShowRttCallScreen) {
1628 return false;
1629 }
1630 RttCallScreen rttCallScreen = getRttCallScreen();
1631 if (rttCallScreen != null) {
1632 transaction.remove(rttCallScreen.getRttCallScreenFragment());
1633 }
1634 didShowRttCallScreen = false;
1635 return true;
1636 }
1637
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001638 private boolean showVideoCallScreenFragment(FragmentTransaction transaction, DialerCall call) {
Eric Erfanianccca3152017-02-22 16:32:36 -08001639 if (didShowVideoCallScreen) {
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001640 VideoCallScreen videoCallScreen = getVideoCallScreen();
1641 if (videoCallScreen.getCallId().equals(call.getId())) {
1642 return false;
1643 }
1644 LogUtil.i(
1645 "InCallActivity.showVideoCallScreenFragment",
1646 "video call fragment exists but arguments do not match");
1647 hideVideoCallScreenFragment(transaction);
Eric Erfanianccca3152017-02-22 16:32:36 -08001648 }
1649
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001650 LogUtil.i("InCallActivity.showVideoCallScreenFragment", "call: %s", call);
1651
Eric Erfanian90508232017-03-24 09:31:16 -07001652 VideoCallScreen videoCallScreen =
1653 VideoBindings.createVideoCallScreen(
1654 call.getId(), call.getVideoTech().shouldUseSurfaceView());
linyuhc3968e62017-11-20 17:40:50 -08001655 transaction.add(
1656 R.id.main, videoCallScreen.getVideoCallScreenFragment(), Tags.VIDEO_CALL_SCREEN);
Eric Erfanianccca3152017-02-22 16:32:36 -08001657
1658 Logger.get(this).logScreenView(ScreenEvent.Type.INCALL, this);
1659 didShowVideoCallScreen = true;
1660 return true;
1661 }
1662
1663 private boolean hideVideoCallScreenFragment(FragmentTransaction transaction) {
1664 if (!didShowVideoCallScreen) {
1665 return false;
1666 }
1667 VideoCallScreen videoCallScreen = getVideoCallScreen();
1668 if (videoCallScreen != null) {
1669 transaction.remove(videoCallScreen.getVideoCallScreenFragment());
1670 }
1671 didShowVideoCallScreen = false;
1672 return true;
1673 }
1674
linyuhc3968e62017-11-20 17:40:50 -08001675 private AnswerScreen getAnswerScreen() {
1676 return (AnswerScreen) getSupportFragmentManager().findFragmentByTag(Tags.ANSWER_SCREEN);
Eric Erfanianccca3152017-02-22 16:32:36 -08001677 }
1678
linyuhc3968e62017-11-20 17:40:50 -08001679 private InCallScreen getInCallScreen() {
1680 return (InCallScreen) getSupportFragmentManager().findFragmentByTag(Tags.IN_CALL_SCREEN);
Eric Erfanianccca3152017-02-22 16:32:36 -08001681 }
1682
linyuhc3968e62017-11-20 17:40:50 -08001683 private VideoCallScreen getVideoCallScreen() {
1684 return (VideoCallScreen) getSupportFragmentManager().findFragmentByTag(Tags.VIDEO_CALL_SCREEN);
Eric Erfanianccca3152017-02-22 16:32:36 -08001685 }
1686
wangqi219b8702018-02-13 09:34:41 -08001687 private RttCallScreen getRttCallScreen() {
1688 return (RttCallScreen) getSupportFragmentManager().findFragmentByTag(Tags.RTT_CALL_SCREEN);
1689 }
1690
wangqifd4c9f72018-03-08 18:21:50 -08001691 private InCallScreen getInCallOrRttCallScreen() {
1692 InCallScreen inCallScreen = null;
1693 if (didShowInCallScreen) {
1694 inCallScreen = getInCallScreen();
1695 }
1696 if (didShowRttCallScreen) {
1697 inCallScreen = getRttCallScreen();
1698 }
1699 return inCallScreen;
1700 }
1701
Eric Erfanianccca3152017-02-22 16:32:36 -08001702 @Override
1703 public void onPseudoScreenStateChanged(boolean isOn) {
1704 LogUtil.i("InCallActivity.onPseudoScreenStateChanged", "isOn: " + isOn);
1705 pseudoBlackScreenOverlay.setVisibility(isOn ? View.GONE : View.VISIBLE);
1706 }
1707
1708 /**
1709 * For some touch related issue, turning off the screen can be faked by drawing a black view over
1710 * the activity. All touch events started when the screen is "off" is rejected.
1711 *
1712 * @see PseudoScreenState
1713 */
1714 @Override
1715 public boolean dispatchTouchEvent(MotionEvent event) {
1716 // Reject any gesture that started when the screen is in the fake off state.
1717 if (touchDownWhenPseudoScreenOff) {
1718 if (event.getAction() == MotionEvent.ACTION_UP) {
1719 touchDownWhenPseudoScreenOff = false;
1720 }
1721 return true;
1722 }
1723 // Reject all touch event when the screen is in the fake off state.
1724 if (!InCallPresenter.getInstance().getPseudoScreenState().isOn()) {
1725 if (event.getAction() == MotionEvent.ACTION_DOWN) {
1726 touchDownWhenPseudoScreenOff = true;
1727 LogUtil.i("InCallActivity.dispatchTouchEvent", "touchDownWhenPseudoScreenOff");
1728 }
1729 return true;
1730 }
1731 return super.dispatchTouchEvent(event);
1732 }
1733
wangqi219b8702018-02-13 09:34:41 -08001734 @Override
1735 public RttCallScreenDelegate newRttCallScreenDelegate(RttCallScreen videoCallScreen) {
1736 return new RttCallPresenter();
1737 }
1738
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001739 private static class ShouldShowUiResult {
Eric Erfanianccca3152017-02-22 16:32:36 -08001740 public final boolean shouldShow;
1741 public final DialerCall call;
1742
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001743 ShouldShowUiResult(boolean shouldShow, DialerCall call) {
Eric Erfanianccca3152017-02-22 16:32:36 -08001744 this.shouldShow = shouldShow;
1745 this.call = call;
1746 }
1747 }
linyuhc3968e62017-11-20 17:40:50 -08001748
1749 private static final class IntentExtraNames {
1750 static final String FOR_FULL_SCREEN = "InCallActivity.for_full_screen_intent";
1751 static final String NEW_OUTGOING_CALL = "InCallActivity.new_outgoing_call";
1752 static final String SHOW_DIALPAD = "InCallActivity.show_dialpad";
1753 }
1754
1755 private static final class KeysForSavedInstance {
1756 static final String DIALPAD_TEXT = "InCallActivity.dialpad_text";
1757 static final String DID_SHOW_ANSWER_SCREEN = "did_show_answer_screen";
1758 static final String DID_SHOW_IN_CALL_SCREEN = "did_show_in_call_screen";
1759 static final String DID_SHOW_VIDEO_CALL_SCREEN = "did_show_video_call_screen";
wangqi153af2f2018-02-15 16:21:49 -08001760 static final String DID_SHOW_RTT_CALL_SCREEN = "did_show_rtt_call_screen";
erfaniand05d8992018-03-20 19:42:26 -07001761 static final String DID_SHOW_SPEAK_EASY_SCREEN = "did_show_speak_easy_screen";
linyuhc3968e62017-11-20 17:40:50 -08001762 }
1763
1764 /** Request codes for pending intents. */
1765 public static final class PendingIntentRequestCodes {
1766 static final int NON_FULL_SCREEN = 0;
1767 static final int FULL_SCREEN = 1;
1768 static final int BUBBLE = 2;
1769 }
1770
1771 private static final class Tags {
1772 static final String ANSWER_SCREEN = "tag_answer_screen";
1773 static final String DIALPAD_FRAGMENT = "tag_dialpad_fragment";
1774 static final String IN_CALL_SCREEN = "tag_in_call_screen";
1775 static final String INTERNATIONAL_CALL_ON_WIFI = "tag_international_call_on_wifi";
1776 static final String SELECT_ACCOUNT_FRAGMENT = "tag_select_account_fragment";
1777 static final String VIDEO_CALL_SCREEN = "tag_video_call_screen";
wangqi219b8702018-02-13 09:34:41 -08001778 static final String RTT_CALL_SCREEN = "tag_rtt_call_screen";
linyuhc3968e62017-11-20 17:40:50 -08001779 static final String POST_CHAR_DIALOG_FRAGMENT = "tag_post_char_dialog_fragment";
erfaniand05d8992018-03-20 19:42:26 -07001780 static final String SPEAK_EASY_SCREEN = "tag_speak_easy_screen";
wangqibc28ea72018-04-02 16:23:00 -07001781 static final String RTT_REQUEST_DIALOG = "tag_rtt_request_dialog";
linyuhc3968e62017-11-20 17:40:50 -08001782 }
1783
1784 private static final class ConfigNames {
1785 static final String ANSWER_AND_RELEASE_ENABLED = "answer_and_release_enabled";
1786 }
1787
1788 private static final class InternationalCallOnWifiCallback
1789 implements InternationalCallOnWifiDialogFragment.Callback {
1790 private static final String TAG = InternationalCallOnWifiCallback.class.getCanonicalName();
1791
1792 @Override
1793 public void continueCall(@NonNull String callId) {
1794 LogUtil.i(TAG, "Continuing call with ID: %s", callId);
1795 }
1796
1797 @Override
1798 public void cancelCall(@NonNull String callId) {
1799 DialerCall call = CallList.getInstance().getCallById(callId);
1800 if (call == null) {
1801 LogUtil.i(TAG, "Call destroyed before the dialog is closed");
1802 return;
1803 }
1804
1805 LogUtil.i(TAG, "Disconnecting international call on WiFi");
1806 call.disconnect();
1807 }
1808 }
1809
1810 private static final class SelectPhoneAccountListener
1811 extends SelectPhoneAccountDialogFragment.SelectPhoneAccountListener {
1812 private static final String TAG = SelectPhoneAccountListener.class.getCanonicalName();
1813
twyen73a74c32018-03-07 12:12:24 -08001814 private final Context appContext;
1815
1816 SelectPhoneAccountListener(Context appContext) {
1817 this.appContext = appContext;
1818 }
1819
linyuhc3968e62017-11-20 17:40:50 -08001820 @Override
1821 public void onPhoneAccountSelected(
1822 PhoneAccountHandle selectedAccountHandle, boolean setDefault, String callId) {
1823 DialerCall call = CallList.getInstance().getCallById(callId);
1824 LogUtil.i(TAG, "Phone account select with call:\n%s", call);
1825
1826 if (call != null) {
twyen73a74c32018-03-07 12:12:24 -08001827 call.phoneAccountSelected(selectedAccountHandle, false);
1828 if (call.getPreferredAccountRecorder() != null) {
1829 call.getPreferredAccountRecorder().record(appContext, selectedAccountHandle, setDefault);
1830 }
linyuhc3968e62017-11-20 17:40:50 -08001831 }
1832 }
1833
1834 @Override
1835 public void onDialogDismissed(String callId) {
1836 DialerCall call = CallList.getInstance().getCallById(callId);
1837 LogUtil.i(TAG, "Disconnecting call:\n%s" + call);
1838
1839 if (call != null) {
1840 call.disconnect();
1841 }
1842 }
1843 }
Eric Erfanianccca3152017-02-22 16:32:36 -08001844}