blob: 86799bfe4ec4bcda8f0121a1ef33fe3834e8048c [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
twyen73a74c32018-03-07 12:12:24 -0800132 private SelectPhoneAccountListener selectPhoneAccountListener;
Eric Erfanianccca3152017-02-22 16:32:36 -0800133
linyuhc3968e62017-11-20 17:40:50 -0800134 private Animation dialpadSlideInAnimation;
135 private Animation dialpadSlideOutAnimation;
136 private Dialog errorDialog;
137 private GradientDrawable backgroundDrawable;
linyuh69a25062017-11-15 16:18:51 -0800138 private InCallOrientationEventListener inCallOrientationEventListener;
linyuhc3968e62017-11-20 17:40:50 -0800139 private View pseudoBlackScreenOverlay;
140 private SelectPhoneAccountDialogFragment selectPhoneAccountDialogFragment;
141 private String dtmfTextToPrepopulate;
142 private String showPostCharWaitDialogCallId;
143 private String showPostCharWaitDialogChars;
144 private boolean allowOrientationChange;
145 private boolean animateDialpadOnShow;
Eric Erfanianccca3152017-02-22 16:32:36 -0800146 private boolean didShowAnswerScreen;
147 private boolean didShowInCallScreen;
148 private boolean didShowVideoCallScreen;
wangqi219b8702018-02-13 09:34:41 -0800149 private boolean didShowRttCallScreen;
erfaniand05d8992018-03-20 19:42:26 -0700150 private boolean didShowSpeakEasyScreen;
erfanian612d13a2018-04-04 15:27:57 -0700151 private String lastShownSpeakEasyScreenUniqueCallid = "";
linyuh9c327da2017-11-14 12:33:48 -0800152 private boolean dismissKeyguard;
Eric Erfanianccca3152017-02-22 16:32:36 -0800153 private boolean isInShowMainInCallFragment;
linyuhc3968e62017-11-20 17:40:50 -0800154 private boolean isRecreating; // whether the activity is going to be recreated
155 private boolean isVisible;
Eric Erfanianccca3152017-02-22 16:32:36 -0800156 private boolean needDismissPendingDialogs;
linyuhc3968e62017-11-20 17:40:50 -0800157 private boolean showPostCharWaitDialogOnResume;
158 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;
Eric Erfanianccca3152017-02-22 16:32:36 -0800162
163 public static Intent getIntent(
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700164 Context context, boolean showDialpad, boolean newOutgoingCall, boolean isForFullScreen) {
Eric Erfanianccca3152017-02-22 16:32:36 -0800165 Intent intent = new Intent(Intent.ACTION_MAIN, null);
166 intent.setFlags(Intent.FLAG_ACTIVITY_NO_USER_ACTION | Intent.FLAG_ACTIVITY_NEW_TASK);
167 intent.setClass(context, InCallActivity.class);
linyuhc3968e62017-11-20 17:40:50 -0800168 if (showDialpad) {
169 intent.putExtra(IntentExtraNames.SHOW_DIALPAD, true);
170 }
171 intent.putExtra(IntentExtraNames.NEW_OUTGOING_CALL, newOutgoingCall);
172 intent.putExtra(IntentExtraNames.FOR_FULL_SCREEN, isForFullScreen);
Eric Erfanianccca3152017-02-22 16:32:36 -0800173 return intent;
174 }
175
176 @Override
177 protected void onResumeFragments() {
178 super.onResumeFragments();
179 if (needDismissPendingDialogs) {
180 dismissPendingDialogs();
181 }
182 }
183
184 @Override
linyuhc3968e62017-11-20 17:40:50 -0800185 protected void onCreate(Bundle bundle) {
Eric Erfanian2ca43182017-08-31 06:57:16 -0700186 Trace.beginSection("InCallActivity.onCreate");
linyuhc3968e62017-11-20 17:40:50 -0800187 super.onCreate(bundle);
Eric Erfanianccca3152017-02-22 16:32:36 -0800188
twyen73a74c32018-03-07 12:12:24 -0800189 selectPhoneAccountListener = new SelectPhoneAccountListener(getApplicationContext());
190
linyuhc3968e62017-11-20 17:40:50 -0800191 if (bundle != null) {
192 didShowAnswerScreen = bundle.getBoolean(KeysForSavedInstance.DID_SHOW_ANSWER_SCREEN);
193 didShowInCallScreen = bundle.getBoolean(KeysForSavedInstance.DID_SHOW_IN_CALL_SCREEN);
194 didShowVideoCallScreen = bundle.getBoolean(KeysForSavedInstance.DID_SHOW_VIDEO_CALL_SCREEN);
wangqi153af2f2018-02-15 16:21:49 -0800195 didShowRttCallScreen = bundle.getBoolean(KeysForSavedInstance.DID_SHOW_RTT_CALL_SCREEN);
Eric Erfanianccca3152017-02-22 16:32:36 -0800196 }
197
linyuhc3968e62017-11-20 17:40:50 -0800198 setWindowFlags();
199 setContentView(R.layout.incall_screen);
200 internalResolveIntent(getIntent());
201
202 boolean isLandscape =
203 getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE;
204 boolean isRtl = ViewUtil.isRtl();
205 if (isLandscape) {
206 dialpadSlideInAnimation =
207 AnimationUtils.loadAnimation(
208 this, isRtl ? R.anim.dialpad_slide_in_left : R.anim.dialpad_slide_in_right);
209 dialpadSlideOutAnimation =
210 AnimationUtils.loadAnimation(
211 this, isRtl ? R.anim.dialpad_slide_out_left : R.anim.dialpad_slide_out_right);
212 } else {
213 dialpadSlideInAnimation = AnimationUtils.loadAnimation(this, R.anim.dialpad_slide_in_bottom);
214 dialpadSlideOutAnimation =
215 AnimationUtils.loadAnimation(this, R.anim.dialpad_slide_out_bottom);
216 }
217 dialpadSlideInAnimation.setInterpolator(AnimUtils.EASE_IN);
218 dialpadSlideOutAnimation.setInterpolator(AnimUtils.EASE_OUT);
219 dialpadSlideOutAnimation.setAnimationListener(
220 new AnimationListenerAdapter() {
221 @Override
222 public void onAnimationEnd(Animation animation) {
223 hideDialpadFragment();
224 }
225 });
226
227 if (bundle != null && showDialpadRequest == DIALPAD_REQUEST_NONE) {
228 // If the dialpad was shown before, set related variables so that it can be shown and
229 // populated with the previous DTMF text during onResume().
230 if (bundle.containsKey(IntentExtraNames.SHOW_DIALPAD)) {
231 boolean showDialpad = bundle.getBoolean(IntentExtraNames.SHOW_DIALPAD);
232 showDialpadRequest = showDialpad ? DIALPAD_REQUEST_SHOW : DIALPAD_REQUEST_HIDE;
233 animateDialpadOnShow = false;
234 }
235 dtmfTextToPrepopulate = bundle.getString(KeysForSavedInstance.DIALPAD_TEXT);
236
237 SelectPhoneAccountDialogFragment selectPhoneAccountDialogFragment =
238 (SelectPhoneAccountDialogFragment)
239 getFragmentManager().findFragmentByTag(Tags.SELECT_ACCOUNT_FRAGMENT);
240 if (selectPhoneAccountDialogFragment != null) {
241 selectPhoneAccountDialogFragment.setListener(selectPhoneAccountListener);
242 }
243 }
244
linyuh69a25062017-11-15 16:18:51 -0800245 inCallOrientationEventListener = new InCallOrientationEventListener(this);
Eric Erfanianccca3152017-02-22 16:32:36 -0800246
247 getWindow()
248 .getDecorView()
249 .setSystemUiVisibility(
250 View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
251
252 pseudoBlackScreenOverlay = findViewById(R.id.psuedo_black_screen_overlay);
Eric Erfanian2ca43182017-08-31 06:57:16 -0700253 sendBroadcast(CallPendingActivity.getFinishBroadcast());
254 Trace.endSection();
zachh7a96dc72018-02-20 22:16:03 -0800255 MetricsComponent.get(this)
256 .metrics()
257 .stopTimer(Metrics.ON_CALL_ADDED_TO_ON_INCALL_UI_SHOWN_INCOMING);
258 MetricsComponent.get(this)
259 .metrics()
260 .stopTimer(Metrics.ON_CALL_ADDED_TO_ON_INCALL_UI_SHOWN_OUTGOING);
Eric Erfanianccca3152017-02-22 16:32:36 -0800261 }
262
linyuhc3968e62017-11-20 17:40:50 -0800263 private void setWindowFlags() {
264 // Allow the activity to be shown when the screen is locked and filter out touch events that are
265 // "too fat".
266 int flags =
267 WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
268 | WindowManager.LayoutParams.FLAG_IGNORE_CHEEK_PRESSES;
269
linyuhf79d1cb2017-12-15 17:49:56 -0800270 // When the audio stream is not via Bluetooth, turn on the screen once the activity is shown.
271 // When the audio stream is via Bluetooth, turn on the screen only for an incoming call.
linyuhc3968e62017-11-20 17:40:50 -0800272 final int audioRoute = getAudioRoute();
linyuhf79d1cb2017-12-15 17:49:56 -0800273 if (audioRoute != CallAudioState.ROUTE_BLUETOOTH
274 || CallList.getInstance().getIncomingCall() != null) {
linyuhc3968e62017-11-20 17:40:50 -0800275 flags |= WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON;
276 }
277
278 getWindow().addFlags(flags);
279 }
280
281 private static int getAudioRoute() {
282 if (audioRouteForTesting.isPresent()) {
283 return audioRouteForTesting.get();
284 }
285
286 return AudioModeProvider.getInstance().getAudioState().getRoute();
287 }
288
289 @VisibleForTesting(otherwise = VisibleForTesting.NONE)
290 public static void setAudioRouteForTesting(int audioRoute) {
291 audioRouteForTesting = Optional.of(audioRoute);
292 }
293
294 private void internalResolveIntent(Intent intent) {
295 if (!intent.getAction().equals(Intent.ACTION_MAIN)) {
296 return;
297 }
298
299 if (intent.hasExtra(IntentExtraNames.SHOW_DIALPAD)) {
300 // IntentExtraNames.SHOW_DIALPAD can be used to specify whether the DTMF dialpad should be
301 // initially visible. If the extra is absent, leave the dialpad in its previous state.
302 boolean showDialpad = intent.getBooleanExtra(IntentExtraNames.SHOW_DIALPAD, false);
303 relaunchedFromDialer(showDialpad);
304 }
305
306 DialerCall outgoingCall = CallList.getInstance().getOutgoingCall();
307 if (outgoingCall == null) {
308 outgoingCall = CallList.getInstance().getPendingOutgoingCall();
309 }
310 if (intent.getBooleanExtra(IntentExtraNames.NEW_OUTGOING_CALL, false)) {
311 intent.removeExtra(IntentExtraNames.NEW_OUTGOING_CALL);
312
313 // InCallActivity is responsible for disconnecting a new outgoing call if there is no way of
314 // making it (i.e. no valid call capable accounts).
linyuh122fb0b2018-03-26 13:35:32 -0700315 if (InCallPresenter.isCallWithNoValidAccounts(outgoingCall)) {
linyuhc3968e62017-11-20 17:40:50 -0800316 LogUtil.i(
317 "InCallActivity.internalResolveIntent", "Call with no valid accounts, disconnecting");
318 outgoingCall.disconnect();
319 }
320
321 dismissKeyguard(true);
322 }
323
324 if (showPhoneAccountSelectionDialog()) {
325 hideMainInCallFragment();
326 }
327 }
328
329 /**
330 * When relaunching from the dialer app, {@code showDialpad} indicates whether the dialpad should
331 * be shown on launch.
332 *
333 * @param showDialpad {@code true} to indicate the dialpad should be shown on launch, and {@code
334 * false} to indicate no change should be made to the dialpad visibility.
335 */
336 private void relaunchedFromDialer(boolean showDialpad) {
337 showDialpadRequest = showDialpad ? DIALPAD_REQUEST_SHOW : DIALPAD_REQUEST_NONE;
338 animateDialpadOnShow = true;
339
340 if (showDialpadRequest == DIALPAD_REQUEST_SHOW) {
341 // If there's only one line in use, AND it's on hold, then we're sure the user
342 // wants to use the dialpad toward the exact line, so un-hold the holding line.
343 DialerCall call = CallList.getInstance().getActiveOrBackgroundCall();
344 if (call != null && call.getState() == State.ONHOLD) {
345 call.unhold();
346 }
347 }
348 }
349
350 /**
351 * Show a phone account selection dialog if there is a call waiting for phone account selection.
352 *
353 * @return true if the dialog was shown.
354 */
355 private boolean showPhoneAccountSelectionDialog() {
356 DialerCall waitingForAccountCall = CallList.getInstance().getWaitingForAccountCall();
357 if (waitingForAccountCall == null) {
358 return false;
359 }
360
twyen73a74c32018-03-07 12:12:24 -0800361 DialerExecutorComponent.get(this)
362 .dialerExecutorFactory()
363 .createNonUiTaskBuilder(new PreferredAccountWorker(waitingForAccountCall.getNumber()))
364 .onSuccess(
365 (result -> {
366 if (result.getPhoneAccountHandle().isPresent()) {
367 Logger.get(this).logImpression(Type.DUAL_SIM_SELECTION_PREFERRED_USED);
368 selectPhoneAccountListener.onPhoneAccountSelected(
369 result.getPhoneAccountHandle().get(), false, waitingForAccountCall.getId());
370 return;
371 }
372 if (result.getSuggestion().isPresent()) {
373 LogUtil.i(
374 "CallingAccountSelector.processPreferredAccount",
375 "SIM suggested: " + result.getSuggestion().get().reason);
376 if (result.getSuggestion().get().shouldAutoSelect) {
377 Logger.get(this).logImpression(Type.DUAL_SIM_SELECTION_SUGGESTION_AUTO_SELECTED);
378 LogUtil.i(
379 "CallingAccountSelector.processPreferredAccount", "Auto selected suggestion");
380 selectPhoneAccountListener.onPhoneAccountSelected(
381 result.getSuggestion().get().phoneAccountHandle,
382 false,
383 waitingForAccountCall.getId());
384 return;
385 }
386 }
387 Bundle extras = waitingForAccountCall.getIntentExtras();
388 List<PhoneAccountHandle> phoneAccountHandles =
389 extras == null
390 ? new ArrayList<>()
391 : extras.getParcelableArrayList(Call.AVAILABLE_PHONE_ACCOUNTS);
linyuhc3968e62017-11-20 17:40:50 -0800392
twyen73a74c32018-03-07 12:12:24 -0800393 waitingForAccountCall.setPreferredAccountRecorder(
394 new PreferredAccountRecorder(
395 waitingForAccountCall.getNumber(),
396 result.getSuggestion().orNull(),
397 result.getDataId().orNull()));
398 selectPhoneAccountDialogFragment =
399 SelectPhoneAccountDialogFragment.newInstance(
400 R.string.select_phone_account_for_calls,
401 result.getDataId().isPresent() /* canSetDefault */,
402 R.string.select_phone_account_for_calls_remember /* setDefaultResId */,
403 phoneAccountHandles,
404 selectPhoneAccountListener,
405 waitingForAccountCall.getId(),
406 SuggestionProvider.buildHint(
407 this, phoneAccountHandles, result.getSuggestion().orNull() /* hints */));
408 selectPhoneAccountDialogFragment.show(
409 getFragmentManager(), Tags.SELECT_ACCOUNT_FRAGMENT);
410 }))
411 .build()
412 .executeParallel(this);
413
linyuhc3968e62017-11-20 17:40:50 -0800414 return true;
415 }
416
Eric Erfanianccca3152017-02-22 16:32:36 -0800417 @Override
418 protected void onSaveInstanceState(Bundle out) {
linyuh57b093b2017-11-17 14:32:32 -0800419 LogUtil.enterBlock("InCallActivity.onSaveInstanceState");
420
421 // TODO: DialpadFragment should handle this as part of its own state
linyuhc3968e62017-11-20 17:40:50 -0800422 out.putBoolean(IntentExtraNames.SHOW_DIALPAD, isDialpadVisible());
linyuh57b093b2017-11-17 14:32:32 -0800423 DialpadFragment dialpadFragment = getDialpadFragment();
424 if (dialpadFragment != null) {
linyuhc3968e62017-11-20 17:40:50 -0800425 out.putString(KeysForSavedInstance.DIALPAD_TEXT, dialpadFragment.getDtmfText());
linyuh57b093b2017-11-17 14:32:32 -0800426 }
427
linyuhc3968e62017-11-20 17:40:50 -0800428 out.putBoolean(KeysForSavedInstance.DID_SHOW_ANSWER_SCREEN, didShowAnswerScreen);
429 out.putBoolean(KeysForSavedInstance.DID_SHOW_IN_CALL_SCREEN, didShowInCallScreen);
430 out.putBoolean(KeysForSavedInstance.DID_SHOW_VIDEO_CALL_SCREEN, didShowVideoCallScreen);
wangqi153af2f2018-02-15 16:21:49 -0800431 out.putBoolean(KeysForSavedInstance.DID_SHOW_RTT_CALL_SCREEN, didShowRttCallScreen);
erfaniand05d8992018-03-20 19:42:26 -0700432 out.putBoolean(KeysForSavedInstance.DID_SHOW_SPEAK_EASY_SCREEN, didShowSpeakEasyScreen);
linyuh57b093b2017-11-17 14:32:32 -0800433
Eric Erfanianccca3152017-02-22 16:32:36 -0800434 super.onSaveInstanceState(out);
435 isVisible = false;
436 }
437
438 @Override
439 protected void onStart() {
Eric Erfanian2ca43182017-08-31 06:57:16 -0700440 Trace.beginSection("InCallActivity.onStart");
Eric Erfanianccca3152017-02-22 16:32:36 -0800441 super.onStart();
linyuh57b093b2017-11-17 14:32:32 -0800442
Eric Erfanianccca3152017-02-22 16:32:36 -0800443 isVisible = true;
444 showMainInCallFragment();
linyuh57b093b2017-11-17 14:32:32 -0800445
446 InCallPresenter.getInstance().setActivity(this);
447 enableInCallOrientationEventListener(
448 getRequestedOrientation()
449 == InCallOrientationEventListener.ACTIVITY_PREFERENCE_ALLOW_ROTATION);
450 InCallPresenter.getInstance().onActivityStarted();
451
yueg10f6e822018-01-17 15:32:18 -0800452 if (!isRecreating) {
453 InCallPresenter.getInstance().onUiShowing(true);
454 }
455
linyuh437ae952018-03-26 12:46:18 -0700456 if (isInMultiWindowMode() && !getResources().getBoolean(R.bool.incall_dialpad_allowed)) {
Eric Erfanianccca3152017-02-22 16:32:36 -0800457 // Hide the dialpad because there may not be enough room
458 showDialpadFragment(false, false);
459 }
linyuh57b093b2017-11-17 14:32:32 -0800460
Eric Erfanian2ca43182017-08-31 06:57:16 -0700461 Trace.endSection();
Eric Erfanianccca3152017-02-22 16:32:36 -0800462 }
463
464 @Override
465 protected void onResume() {
Eric Erfanian2ca43182017-08-31 06:57:16 -0700466 Trace.beginSection("InCallActivity.onResume");
Eric Erfanianccca3152017-02-22 16:32:36 -0800467 super.onResume();
linyuhc3968e62017-11-20 17:40:50 -0800468
469 if (!InCallPresenter.getInstance().isReadyForTearDown()) {
470 updateTaskDescription();
linyuhc3968e62017-11-20 17:40:50 -0800471 }
472
473 // If there is a pending request to show or hide the dialpad, handle that now.
474 if (showDialpadRequest != DIALPAD_REQUEST_NONE) {
475 if (showDialpadRequest == DIALPAD_REQUEST_SHOW) {
476 // Exit fullscreen so that the user has access to the dialpad hide/show button.
477 // This is important when showing the dialpad from within dialer.
478 InCallPresenter.getInstance().setFullScreen(false /* isFullScreen */, true /* force */);
479
480 showDialpadFragment(true /* show */, animateDialpadOnShow /* animate */);
481 animateDialpadOnShow = false;
482
483 DialpadFragment dialpadFragment = getDialpadFragment();
484 if (dialpadFragment != null) {
485 dialpadFragment.setDtmfText(dtmfTextToPrepopulate);
486 dtmfTextToPrepopulate = null;
487 }
488 } else {
489 LogUtil.i("InCallActivity.onResume", "Force-hide the dialpad");
490 if (getDialpadFragment() != null) {
491 showDialpadFragment(false /* show */, false /* animate */);
492 }
493 }
494 showDialpadRequest = DIALPAD_REQUEST_NONE;
495 }
496 updateNavigationBar(isDialpadVisible());
497
498 if (showPostCharWaitDialogOnResume) {
499 showDialogForPostCharWait(showPostCharWaitDialogCallId, showPostCharWaitDialogChars);
500 }
501
502 CallList.getInstance()
503 .onInCallUiShown(getIntent().getBooleanExtra(IntentExtraNames.FOR_FULL_SCREEN, false));
504
Eric Erfanianccca3152017-02-22 16:32:36 -0800505 PseudoScreenState pseudoScreenState = InCallPresenter.getInstance().getPseudoScreenState();
506 pseudoScreenState.addListener(this);
507 onPseudoScreenStateChanged(pseudoScreenState.isOn());
Eric Erfanian2ca43182017-08-31 06:57:16 -0700508 Trace.endSection();
weijiaxu650e7cc2017-10-31 12:38:54 -0700509 // add 1 sec delay to get memory snapshot so that dialer wont react slowly on resume.
510 ThreadUtil.postDelayedOnUiThread(
weijiaxuc950a9b2017-11-06 16:39:04 -0800511 () ->
zachh7a96dc72018-02-20 22:16:03 -0800512 MetricsComponent.get(this)
513 .metrics()
514 .recordMemory(Metrics.INCALL_ACTIVITY_ON_RESUME_MEMORY_EVENT_NAME),
weijiaxu650e7cc2017-10-31 12:38:54 -0700515 1000);
Eric Erfanianccca3152017-02-22 16:32:36 -0800516 }
517
Eric Erfanianccca3152017-02-22 16:32:36 -0800518 @Override
519 protected void onPause() {
Eric Erfanian2ca43182017-08-31 06:57:16 -0700520 Trace.beginSection("InCallActivity.onPause");
Eric Erfanianccca3152017-02-22 16:32:36 -0800521 super.onPause();
linyuh57b093b2017-11-17 14:32:32 -0800522
523 DialpadFragment dialpadFragment = getDialpadFragment();
524 if (dialpadFragment != null) {
525 dialpadFragment.onDialerKeyUp(null);
526 }
527
Eric Erfanianccca3152017-02-22 16:32:36 -0800528 InCallPresenter.getInstance().getPseudoScreenState().removeListener(this);
Eric Erfanian2ca43182017-08-31 06:57:16 -0700529 Trace.endSection();
Eric Erfanianccca3152017-02-22 16:32:36 -0800530 }
531
532 @Override
533 protected void onStop() {
Eric Erfanian2ca43182017-08-31 06:57:16 -0700534 Trace.beginSection("InCallActivity.onStop");
wangqi4d705e52017-09-28 12:23:35 -0700535 isVisible = false;
Eric Erfanianccca3152017-02-22 16:32:36 -0800536 super.onStop();
linyuh57b093b2017-11-17 14:32:32 -0800537
538 // Disconnects the call waiting for a phone account when the activity is hidden (e.g., after the
539 // user presses the home button).
540 // Without this the pending call will get stuck on phone account selection and new calls can't
541 // be created.
542 // Skip this when the screen is locked since the activity may complete its current life cycle
543 // and restart.
linyuhc3968e62017-11-20 17:40:50 -0800544 if (!isRecreating && !getSystemService(KeyguardManager.class).isKeyguardLocked()) {
linyuh57b093b2017-11-17 14:32:32 -0800545 DialerCall waitingForAccountCall = CallList.getInstance().getWaitingForAccountCall();
546 if (waitingForAccountCall != null) {
547 waitingForAccountCall.disconnect();
548 }
549 }
550
551 enableInCallOrientationEventListener(false);
552 InCallPresenter.getInstance().updateIsChangingConfigurations();
553 InCallPresenter.getInstance().onActivityStopped();
linyuhc3968e62017-11-20 17:40:50 -0800554 if (!isRecreating) {
yueg10f6e822018-01-17 15:32:18 -0800555 InCallPresenter.getInstance().onUiShowing(false);
wangqie6060522018-04-05 11:47:15 -0700556 }
557 if (errorDialog != null) {
558 errorDialog.dismiss();
linyuh57b093b2017-11-17 14:32:32 -0800559 }
560
yueg10f6e822018-01-17 15:32:18 -0800561 if (isFinishing()) {
562 InCallPresenter.getInstance().unsetActivity(this);
563 }
564
Eric Erfanian2ca43182017-08-31 06:57:16 -0700565 Trace.endSection();
Eric Erfanianccca3152017-02-22 16:32:36 -0800566 }
567
568 @Override
569 protected void onDestroy() {
Eric Erfanian2ca43182017-08-31 06:57:16 -0700570 Trace.beginSection("InCallActivity.onDestroy");
Eric Erfanianccca3152017-02-22 16:32:36 -0800571 super.onDestroy();
linyuh57b093b2017-11-17 14:32:32 -0800572
573 InCallPresenter.getInstance().unsetActivity(this);
574 InCallPresenter.getInstance().updateIsChangingConfigurations();
Eric Erfanian2ca43182017-08-31 06:57:16 -0700575 Trace.endSection();
Eric Erfanianccca3152017-02-22 16:32:36 -0800576 }
577
578 @Override
579 public void finish() {
580 if (shouldCloseActivityOnFinish()) {
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700581 // When user select incall ui from recents after the call is disconnected, it tries to launch
582 // a new InCallActivity but InCallPresenter is already teared down at this point, which causes
583 // crash.
584 // By calling finishAndRemoveTask() instead of finish() the task associated with
585 // InCallActivity is cleared completely. So system won't try to create a new InCallActivity in
586 // this case.
587 //
588 // Calling finish won't clear the task and normally when an activity finishes it shouldn't
589 // clear the task since there could be parent activity in the same task that's still alive.
590 // But InCallActivity is special since it's singleInstance which means it's root activity and
591 // only instance of activity in the task. So it should be safe to also remove task when
592 // finishing.
593 // It's also necessary in the sense of it's excluded from recents. So whenever the activity
594 // finishes, the task should also be removed since it doesn't make sense to go back to it in
595 // anyway anymore.
596 super.finishAndRemoveTask();
Eric Erfanianccca3152017-02-22 16:32:36 -0800597 }
598 }
599
600 private boolean shouldCloseActivityOnFinish() {
linyuhc3968e62017-11-20 17:40:50 -0800601 if (!isVisible) {
Eric Erfanianccca3152017-02-22 16:32:36 -0800602 LogUtil.i(
603 "InCallActivity.shouldCloseActivityOnFinish",
604 "allowing activity to be closed because it's not visible");
605 return true;
606 }
607
twyen8efb4952017-10-06 16:35:54 -0700608 if (InCallPresenter.getInstance().isInCallUiLocked()) {
Eric Erfanianccca3152017-02-22 16:32:36 -0800609 LogUtil.i(
610 "InCallActivity.shouldCloseActivityOnFinish",
twyen8efb4952017-10-06 16:35:54 -0700611 "in call ui is locked, not closing activity");
Eric Erfanianccca3152017-02-22 16:32:36 -0800612 return false;
613 }
614
615 LogUtil.i(
616 "InCallActivity.shouldCloseActivityOnFinish",
twyen8efb4952017-10-06 16:35:54 -0700617 "activity is visible and has no locks, allowing activity to close");
Eric Erfanianccca3152017-02-22 16:32:36 -0800618 return true;
619 }
620
621 @Override
622 protected void onNewIntent(Intent intent) {
linyuhc3968e62017-11-20 17:40:50 -0800623 LogUtil.enterBlock("InCallActivity.onNewIntent");
Eric Erfanianccca3152017-02-22 16:32:36 -0800624
625 // If the screen is off, we need to make sure it gets turned on for incoming calls.
626 // This normally works just fine thanks to FLAG_TURN_SCREEN_ON but that only works
627 // when the activity is first created. Therefore, to ensure the screen is turned on
628 // for the call waiting case, we recreate() the current activity. There should be no jank from
629 // this since the screen is already off and will remain so until our new activity is up.
linyuhc3968e62017-11-20 17:40:50 -0800630 if (!isVisible) {
631 onNewIntent(intent, true /* isRecreating */);
Eric Erfanianccca3152017-02-22 16:32:36 -0800632 LogUtil.i("InCallActivity.onNewIntent", "Restarting InCallActivity to force screen on.");
633 recreate();
Eric Erfanian10b34a52017-05-04 08:23:17 -0700634 } else {
linyuhc3968e62017-11-20 17:40:50 -0800635 onNewIntent(intent, false /* isRecreating */);
636 }
637 }
638
yuega3305352018-01-09 11:02:47 -0800639 @VisibleForTesting
640 void onNewIntent(Intent intent, boolean isRecreating) {
linyuhc3968e62017-11-20 17:40:50 -0800641 this.isRecreating = isRecreating;
642
643 // We're being re-launched with a new Intent. Since it's possible for a single InCallActivity
644 // instance to persist indefinitely (even if we finish() ourselves), this sequence can
645 // happen any time the InCallActivity needs to be displayed.
646
647 // Stash away the new intent so that we can get it in the future by calling getIntent().
648 // Otherwise getIntent() will return the original Intent from when we first got created.
649 setIntent(intent);
650
651 // Activities are always paused before receiving a new intent, so we can count on our onResume()
652 // method being called next.
653
654 // Just like in onCreate(), handle the intent.
655 // Skip if InCallActivity is going to be recreated since this will be called in onCreate().
656 if (!isRecreating) {
657 internalResolveIntent(intent);
Eric Erfanianccca3152017-02-22 16:32:36 -0800658 }
659 }
660
661 @Override
662 public void onBackPressed() {
linyuh57b093b2017-11-17 14:32:32 -0800663 LogUtil.enterBlock("InCallActivity.onBackPressed");
664
linyuhc3968e62017-11-20 17:40:50 -0800665 if (!isVisible) {
linyuh57b093b2017-11-17 14:32:32 -0800666 return;
Eric Erfanianccca3152017-02-22 16:32:36 -0800667 }
linyuh57b093b2017-11-17 14:32:32 -0800668
669 if (!getCallCardFragmentVisible()) {
670 return;
671 }
672
673 DialpadFragment dialpadFragment = getDialpadFragment();
674 if (dialpadFragment != null && dialpadFragment.isVisible()) {
675 showDialpadFragment(false /* show */, true /* animate */);
676 return;
677 }
678
679 if (CallList.getInstance().getIncomingCall() != null) {
680 LogUtil.i(
681 "InCallActivity.onBackPressed",
682 "Ignore the press of the back key when an incoming call is ringing");
683 return;
684 }
685
686 // Nothing special to do. Fall back to the default behavior.
687 super.onBackPressed();
Eric Erfanianccca3152017-02-22 16:32:36 -0800688 }
689
690 @Override
691 public boolean onOptionsItemSelected(MenuItem item) {
692 LogUtil.i("InCallActivity.onOptionsItemSelected", "item: " + item);
693 if (item.getItemId() == android.R.id.home) {
694 onBackPressed();
695 return true;
696 }
697 return super.onOptionsItemSelected(item);
698 }
699
700 @Override
701 public boolean onKeyUp(int keyCode, KeyEvent event) {
linyuh57b093b2017-11-17 14:32:32 -0800702 DialpadFragment dialpadFragment = getDialpadFragment();
703 if (dialpadFragment != null
704 && dialpadFragment.isVisible()
705 && dialpadFragment.onDialerKeyUp(event)) {
706 return true;
707 }
708
709 if (keyCode == KeyEvent.KEYCODE_CALL) {
710 // Always consume KEYCODE_CALL to ensure the PhoneWindow won't do anything with it.
711 return true;
712 }
713
714 return super.onKeyUp(keyCode, event);
Eric Erfanianccca3152017-02-22 16:32:36 -0800715 }
716
717 @Override
718 public boolean onKeyDown(int keyCode, KeyEvent event) {
linyuh57b093b2017-11-17 14:32:32 -0800719 switch (keyCode) {
720 case KeyEvent.KEYCODE_CALL:
721 if (!InCallPresenter.getInstance().handleCallKey()) {
722 LogUtil.e(
723 "InCallActivity.onKeyDown",
724 "InCallPresenter should always handle KEYCODE_CALL in onKeyDown");
725 }
726 // Always consume KEYCODE_CALL to ensure the PhoneWindow won't do anything with it.
727 return true;
728
729 // Note that KEYCODE_ENDCALL isn't handled here as the standard system-wide handling of it
730 // is exactly what's needed, namely
731 // (1) "hang up" if there's an active call, or
732 // (2) "don't answer" if there's an incoming call.
733 // (See PhoneWindowManager for implementation details.)
734
735 case KeyEvent.KEYCODE_CAMERA:
736 // Consume KEYCODE_CAMERA since it's easy to accidentally press the camera button.
737 return true;
738
739 case KeyEvent.KEYCODE_VOLUME_UP:
740 case KeyEvent.KEYCODE_VOLUME_DOWN:
741 case KeyEvent.KEYCODE_VOLUME_MUTE:
742 // Ringer silencing handled by PhoneWindowManager.
743 break;
744
745 case KeyEvent.KEYCODE_MUTE:
746 TelecomAdapter.getInstance()
747 .mute(!AudioModeProvider.getInstance().getAudioState().isMuted());
748 return true;
749
750 case KeyEvent.KEYCODE_SLASH:
751 // When verbose logging is enabled, dump the view for debugging/testing purposes.
752 if (LogUtil.isVerboseEnabled()) {
753 View decorView = getWindow().getDecorView();
754 LogUtil.v("InCallActivity.onKeyDown", "View dump:\n%s", decorView);
755 return true;
756 }
757 break;
758
759 case KeyEvent.KEYCODE_EQUALS:
760 break;
761
762 default: // fall out
763 }
764
765 // Pass other key events to DialpadFragment's "onDialerKeyDown" method in case the user types
766 // in DTMF (Dual-tone multi-frequency signaling) code.
767 DialpadFragment dialpadFragment = getDialpadFragment();
768 if (dialpadFragment != null
769 && dialpadFragment.isVisible()
770 && dialpadFragment.onDialerKeyDown(event)) {
771 return true;
772 }
773
774 return super.onKeyDown(keyCode, event);
Eric Erfanianccca3152017-02-22 16:32:36 -0800775 }
776
777 public boolean isInCallScreenAnimating() {
778 return false;
779 }
780
781 public void showConferenceFragment(boolean show) {
782 if (show) {
783 startActivity(new Intent(this, ManageConferenceActivity.class));
784 }
785 }
786
linyuhc3968e62017-11-20 17:40:50 -0800787 public void showDialpadFragment(boolean show, boolean animate) {
788 if (show == isDialpadVisible()) {
789 return;
Eric Erfanianccca3152017-02-22 16:32:36 -0800790 }
linyuhc3968e62017-11-20 17:40:50 -0800791
792 FragmentManager dialpadFragmentManager = getDialpadFragmentManager();
793 if (dialpadFragmentManager == null) {
794 LogUtil.i("InCallActivity.showDialpadFragment", "Unable to obtain a FragmentManager");
795 return;
796 }
797
798 if (!animate) {
799 if (show) {
800 showDialpadFragment();
801 } else {
802 hideDialpadFragment();
803 }
804 } else {
805 if (show) {
806 showDialpadFragment();
807 getDialpadFragment().animateShowDialpad();
808 }
809 getDialpadFragment()
810 .getView()
811 .startAnimation(show ? dialpadSlideInAnimation : dialpadSlideOutAnimation);
812 }
813
814 ProximitySensor sensor = InCallPresenter.getInstance().getProximitySensor();
815 if (sensor != null) {
816 sensor.onDialpadVisible(show);
817 }
818 showDialpadRequest = DIALPAD_REQUEST_NONE;
819
820 // Note: onInCallScreenDialpadVisibilityChange is called here to ensure that the dialpad FAB
821 // repositions itself.
wangqifd4c9f72018-03-08 18:21:50 -0800822 getInCallOrRttCallScreen().onInCallScreenDialpadVisibilityChange(show);
linyuhc3968e62017-11-20 17:40:50 -0800823 }
824
825 private void showDialpadFragment() {
826 FragmentManager dialpadFragmentManager = getDialpadFragmentManager();
827 if (dialpadFragmentManager == null) {
828 return;
829 }
830
831 FragmentTransaction transaction = dialpadFragmentManager.beginTransaction();
832 DialpadFragment dialpadFragment = getDialpadFragment();
833 if (dialpadFragment == null) {
wangqifd4c9f72018-03-08 18:21:50 -0800834 dialpadFragment = new DialpadFragment();
835 transaction.add(getDialpadContainerId(), dialpadFragment, Tags.DIALPAD_FRAGMENT);
linyuhc3968e62017-11-20 17:40:50 -0800836 } else {
837 transaction.show(dialpadFragment);
calderwoodrad5883872017-12-12 15:29:12 -0800838 dialpadFragment.setUserVisibleHint(true);
linyuhc3968e62017-11-20 17:40:50 -0800839 }
wangqifd4c9f72018-03-08 18:21:50 -0800840 // RTT call screen doesn't show end call button inside dialpad, thus the space reserved for end
841 // call button should be removed.
842 dialpadFragment.setShouldShowEndCallSpace(didShowInCallScreen);
linyuhc3968e62017-11-20 17:40:50 -0800843 transaction.commitAllowingStateLoss();
844 dialpadFragmentManager.executePendingTransactions();
845
846 Logger.get(this).logScreenView(ScreenEvent.Type.INCALL_DIALPAD, this);
847 updateNavigationBar(true /* isDialpadVisible */);
848 }
849
850 private void hideDialpadFragment() {
851 FragmentManager dialpadFragmentManager = getDialpadFragmentManager();
852 if (dialpadFragmentManager == null) {
853 return;
854 }
855
calderwoodrad5883872017-12-12 15:29:12 -0800856 DialpadFragment dialpadFragment = getDialpadFragment();
linyuhc3968e62017-11-20 17:40:50 -0800857 if (dialpadFragment != null) {
858 FragmentTransaction transaction = dialpadFragmentManager.beginTransaction();
859 transaction.hide(dialpadFragment);
860 transaction.commitAllowingStateLoss();
861 dialpadFragmentManager.executePendingTransactions();
calderwoodrad5883872017-12-12 15:29:12 -0800862 dialpadFragment.setUserVisibleHint(false);
linyuhc3968e62017-11-20 17:40:50 -0800863 }
864 updateNavigationBar(false /* isDialpadVisible */);
Eric Erfanianccca3152017-02-22 16:32:36 -0800865 }
866
867 public boolean isDialpadVisible() {
linyuh69a25062017-11-15 16:18:51 -0800868 DialpadFragment dialpadFragment = getDialpadFragment();
calderwoodraa584bcd2018-01-24 12:19:56 -0800869 return dialpadFragment != null
870 && dialpadFragment.isAdded()
871 && !dialpadFragment.isHidden()
872 && dialpadFragment.getView() != null
873 && dialpadFragment.getUserVisibleHint();
linyuh69a25062017-11-15 16:18:51 -0800874 }
875
linyuhc3968e62017-11-20 17:40:50 -0800876 /** Returns the {@link DialpadFragment} that's shown by this activity, or {@code null} */
linyuh69a25062017-11-15 16:18:51 -0800877 @Nullable
linyuhc3968e62017-11-20 17:40:50 -0800878 private DialpadFragment getDialpadFragment() {
linyuh69a25062017-11-15 16:18:51 -0800879 FragmentManager fragmentManager = getDialpadFragmentManager();
880 if (fragmentManager == null) {
881 return null;
882 }
linyuhc3968e62017-11-20 17:40:50 -0800883 return (DialpadFragment) fragmentManager.findFragmentByTag(Tags.DIALPAD_FRAGMENT);
Eric Erfanianccca3152017-02-22 16:32:36 -0800884 }
885
886 public void onForegroundCallChanged(DialerCall newForegroundCall) {
linyuh57b093b2017-11-17 14:32:32 -0800887 updateTaskDescription();
888
889 if (newForegroundCall == null || !didShowAnswerScreen) {
Eric Erfanianccca3152017-02-22 16:32:36 -0800890 LogUtil.v("InCallActivity.onForegroundCallChanged", "resetting background color");
linyuh57b093b2017-11-17 14:32:32 -0800891 updateWindowBackgroundColor(0 /* progress */);
Eric Erfanianccca3152017-02-22 16:32:36 -0800892 }
893 }
894
linyuhc3968e62017-11-20 17:40:50 -0800895 private void updateTaskDescription() {
linyuh57b093b2017-11-17 14:32:32 -0800896 int color =
897 getResources().getBoolean(R.bool.is_layout_landscape)
898 ? ResourcesCompat.getColor(
899 getResources(), R.color.statusbar_background_color, getTheme())
900 : InCallPresenter.getInstance().getThemeColorManager().getSecondaryColor();
901 setTaskDescription(
902 new TaskDescription(
903 getResources().getString(R.string.notification_ongoing_call), null /* icon */, color));
904 }
905
Eric Erfanianccca3152017-02-22 16:32:36 -0800906 public void updateWindowBackgroundColor(@FloatRange(from = -1f, to = 1.0f) float progress) {
907 ThemeColorManager themeColorManager = InCallPresenter.getInstance().getThemeColorManager();
908 @ColorInt int top;
909 @ColorInt int middle;
910 @ColorInt int bottom;
911 @ColorInt int gray = 0x66000000;
912
linyuh437ae952018-03-26 12:46:18 -0700913 if (isInMultiWindowMode()) {
Eric Erfanianccca3152017-02-22 16:32:36 -0800914 top = themeColorManager.getBackgroundColorSolid();
915 middle = themeColorManager.getBackgroundColorSolid();
916 bottom = themeColorManager.getBackgroundColorSolid();
917 } else {
918 top = themeColorManager.getBackgroundColorTop();
919 middle = themeColorManager.getBackgroundColorMiddle();
920 bottom = themeColorManager.getBackgroundColorBottom();
921 }
922
923 if (progress < 0) {
924 float correctedProgress = Math.abs(progress);
925 top = ColorUtils.blendARGB(top, gray, correctedProgress);
926 middle = ColorUtils.blendARGB(middle, gray, correctedProgress);
927 bottom = ColorUtils.blendARGB(bottom, gray, correctedProgress);
928 }
929
930 boolean backgroundDirty = false;
931 if (backgroundDrawable == null) {
932 backgroundDrawableColors = new int[] {top, middle, bottom};
933 backgroundDrawable = new GradientDrawable(Orientation.TOP_BOTTOM, backgroundDrawableColors);
934 backgroundDirty = true;
935 } else {
936 if (backgroundDrawableColors[0] != top) {
937 backgroundDrawableColors[0] = top;
938 backgroundDirty = true;
939 }
940 if (backgroundDrawableColors[1] != middle) {
941 backgroundDrawableColors[1] = middle;
942 backgroundDirty = true;
943 }
944 if (backgroundDrawableColors[2] != bottom) {
945 backgroundDrawableColors[2] = bottom;
946 backgroundDirty = true;
947 }
948 if (backgroundDirty) {
949 backgroundDrawable.setColors(backgroundDrawableColors);
950 }
951 }
952
953 if (backgroundDirty) {
954 getWindow().setBackgroundDrawable(backgroundDrawable);
955 }
956 }
957
958 public boolean isVisible() {
959 return isVisible;
960 }
961
962 public boolean getCallCardFragmentVisible() {
erfaniand05d8992018-03-20 19:42:26 -0700963 return didShowInCallScreen
964 || didShowVideoCallScreen
965 || didShowRttCallScreen
966 || didShowSpeakEasyScreen;
Eric Erfanianccca3152017-02-22 16:32:36 -0800967 }
968
969 public void dismissKeyguard(boolean dismiss) {
linyuh9c327da2017-11-14 12:33:48 -0800970 if (dismissKeyguard == dismiss) {
971 return;
972 }
973
974 dismissKeyguard = dismiss;
975 if (dismiss) {
976 getWindow().addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);
977 } else {
978 getWindow().clearFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);
979 }
Eric Erfanianccca3152017-02-22 16:32:36 -0800980 }
981
linyuhc3968e62017-11-20 17:40:50 -0800982 public void showDialogForPostCharWait(String callId, String chars) {
983 if (isVisible) {
984 PostCharDialogFragment fragment = new PostCharDialogFragment(callId, chars);
985 fragment.show(getSupportFragmentManager(), Tags.POST_CHAR_DIALOG_FRAGMENT);
986
987 showPostCharWaitDialogOnResume = false;
988 showPostCharWaitDialogCallId = null;
989 showPostCharWaitDialogChars = null;
990 } else {
991 showPostCharWaitDialogOnResume = true;
992 showPostCharWaitDialogCallId = callId;
993 showPostCharWaitDialogChars = chars;
994 }
Eric Erfanianccca3152017-02-22 16:32:36 -0800995 }
996
linyuh7b86f562017-11-16 11:24:09 -0800997 public void showDialogOrToastForDisconnectedCall(DisconnectMessage disconnectMessage) {
998 LogUtil.i(
999 "InCallActivity.showDialogOrToastForDisconnectedCall",
1000 "disconnect cause: %s",
1001 disconnectMessage);
1002
1003 if (disconnectMessage.dialog == null || isFinishing()) {
1004 return;
1005 }
1006
1007 dismissPendingDialogs();
1008
1009 // Show a toast if the app is in background when a dialog can't be visible.
1010 if (!isVisible()) {
1011 Toast.makeText(getApplicationContext(), disconnectMessage.toastMessage, Toast.LENGTH_LONG)
1012 .show();
1013 return;
1014 }
1015
1016 // Show the dialog.
linyuhc3968e62017-11-20 17:40:50 -08001017 errorDialog = disconnectMessage.dialog;
linyuh7b86f562017-11-16 11:24:09 -08001018 InCallUiLock lock = InCallPresenter.getInstance().acquireInCallUiLock("showErrorDialog");
1019 disconnectMessage.dialog.setOnDismissListener(
1020 dialogInterface -> {
1021 lock.release();
1022 onDialogDismissed();
1023 });
1024 disconnectMessage.dialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
1025 disconnectMessage.dialog.show();
1026 }
1027
1028 private void onDialogDismissed() {
linyuhc3968e62017-11-20 17:40:50 -08001029 errorDialog = null;
linyuh7b86f562017-11-16 11:24:09 -08001030 CallList.getInstance().onErrorDialogDismissed();
Eric Erfanianccca3152017-02-22 16:32:36 -08001031 }
1032
1033 public void dismissPendingDialogs() {
linyuhc3968e62017-11-20 17:40:50 -08001034 LogUtil.enterBlock("InCallActivity.dismissPendingDialogs");
linyuhf99f6302017-11-15 11:23:51 -08001035
1036 if (!isVisible) {
1037 // Defer the dismissing action as the activity is not visible and onSaveInstanceState may have
1038 // been called.
Eric Erfanianccca3152017-02-22 16:32:36 -08001039 LogUtil.i(
1040 "InCallActivity.dismissPendingDialogs", "defer actions since activity is not visible");
1041 needDismissPendingDialogs = true;
linyuhf99f6302017-11-15 11:23:51 -08001042 return;
Eric Erfanianccca3152017-02-22 16:32:36 -08001043 }
linyuhf99f6302017-11-15 11:23:51 -08001044
1045 // Dismiss the error dialog
linyuhf99f6302017-11-15 11:23:51 -08001046 if (errorDialog != null) {
1047 errorDialog.dismiss();
linyuhc3968e62017-11-20 17:40:50 -08001048 errorDialog = null;
linyuhf99f6302017-11-15 11:23:51 -08001049 }
1050
1051 // Dismiss the phone account selection dialog
linyuhf99f6302017-11-15 11:23:51 -08001052 if (selectPhoneAccountDialogFragment != null) {
1053 selectPhoneAccountDialogFragment.dismiss();
linyuhc3968e62017-11-20 17:40:50 -08001054 selectPhoneAccountDialogFragment = null;
linyuhf99f6302017-11-15 11:23:51 -08001055 }
1056
1057 // Dismiss the dialog for international call on WiFi
1058 InternationalCallOnWifiDialogFragment internationalCallOnWifiFragment =
1059 (InternationalCallOnWifiDialogFragment)
linyuhc3968e62017-11-20 17:40:50 -08001060 getSupportFragmentManager().findFragmentByTag(Tags.INTERNATIONAL_CALL_ON_WIFI);
linyuhf99f6302017-11-15 11:23:51 -08001061 if (internationalCallOnWifiFragment != null) {
1062 internationalCallOnWifiFragment.dismiss();
1063 }
1064
1065 // Dismiss the answer screen
1066 AnswerScreen answerScreen = getAnswerScreen();
1067 if (answerScreen != null) {
1068 answerScreen.dismissPendingDialogs();
1069 }
1070
1071 needDismissPendingDialogs = false;
Eric Erfanianccca3152017-02-22 16:32:36 -08001072 }
1073
linyuhc3968e62017-11-20 17:40:50 -08001074 private void enableInCallOrientationEventListener(boolean enable) {
linyuh69a25062017-11-15 16:18:51 -08001075 if (enable) {
1076 inCallOrientationEventListener.enable(true /* notifyDeviceOrientationChange */);
1077 } else {
1078 inCallOrientationEventListener.disable();
1079 }
Eric Erfanianccca3152017-02-22 16:32:36 -08001080 }
1081
1082 public void setExcludeFromRecents(boolean exclude) {
linyuhc3968e62017-11-20 17:40:50 -08001083 int taskId = getTaskId();
1084
1085 List<AppTask> tasks = getSystemService(ActivityManager.class).getAppTasks();
1086 for (AppTask task : tasks) {
1087 try {
1088 if (task.getTaskInfo().id == taskId) {
1089 task.setExcludeFromRecents(exclude);
1090 }
1091 } catch (RuntimeException e) {
1092 LogUtil.e("InCallActivity.setExcludeFromRecents", "RuntimeException:\n%s", e);
1093 }
1094 }
Eric Erfanianccca3152017-02-22 16:32:36 -08001095 }
1096
Eric Erfanianccca3152017-02-22 16:32:36 -08001097 @Nullable
1098 public FragmentManager getDialpadFragmentManager() {
wangqifd4c9f72018-03-08 18:21:50 -08001099 InCallScreen inCallScreen = getInCallOrRttCallScreen();
Eric Erfanianccca3152017-02-22 16:32:36 -08001100 if (inCallScreen != null) {
1101 return inCallScreen.getInCallScreenFragment().getChildFragmentManager();
1102 }
1103 return null;
1104 }
1105
1106 public int getDialpadContainerId() {
wangqifd4c9f72018-03-08 18:21:50 -08001107 return getInCallOrRttCallScreen().getAnswerAndDialpadContainerResourceId();
Eric Erfanianccca3152017-02-22 16:32:36 -08001108 }
1109
1110 @Override
1111 public AnswerScreenDelegate newAnswerScreenDelegate(AnswerScreen answerScreen) {
1112 DialerCall call = CallList.getInstance().getCallById(answerScreen.getCallId());
1113 if (call == null) {
1114 // This is a work around for a bug where we attempt to create a new delegate after the call
1115 // has already been removed. An example of when this can happen is:
1116 // 1. incoming video call in landscape mode
1117 // 2. remote party hangs up
1118 // 3. activity switches from landscape to portrait
1119 // At step #3 the answer fragment will try to create a new answer delegate but the call won't
1120 // exist. In this case we'll simply return a stub delegate that does nothing. This is ok
1121 // because this new state is transient and the activity will be destroyed soon.
1122 LogUtil.i("InCallActivity.onPrimaryCallStateChanged", "call doesn't exist, using stub");
1123 return new AnswerScreenPresenterStub();
1124 } else {
1125 return new AnswerScreenPresenter(
1126 this, answerScreen, CallList.getInstance().getCallById(answerScreen.getCallId()));
1127 }
1128 }
1129
1130 @Override
1131 public InCallScreenDelegate newInCallScreenDelegate() {
1132 return new CallCardPresenter(this);
1133 }
1134
1135 @Override
1136 public InCallButtonUiDelegate newInCallButtonUiDelegate() {
1137 return new CallButtonPresenter(this);
1138 }
1139
1140 @Override
Eric Erfanian90508232017-03-24 09:31:16 -07001141 public VideoCallScreenDelegate newVideoCallScreenDelegate(VideoCallScreen videoCallScreen) {
1142 DialerCall dialerCall = CallList.getInstance().getCallById(videoCallScreen.getCallId());
1143 if (dialerCall != null && dialerCall.getVideoTech().shouldUseSurfaceView()) {
1144 return dialerCall.getVideoTech().createVideoCallScreenDelegate(this, videoCallScreen);
1145 }
Eric Erfanianccca3152017-02-22 16:32:36 -08001146 return new VideoCallPresenter();
1147 }
1148
1149 public void onPrimaryCallStateChanged() {
Eric Erfanian2ca43182017-08-31 06:57:16 -07001150 Trace.beginSection("InCallActivity.onPrimaryCallStateChanged");
Eric Erfanianccca3152017-02-22 16:32:36 -08001151 showMainInCallFragment();
Eric Erfanian2ca43182017-08-31 06:57:16 -07001152 Trace.endSection();
Eric Erfanianccca3152017-02-22 16:32:36 -08001153 }
1154
linyuh7b86f562017-11-16 11:24:09 -08001155 public void showDialogOrToastForWifiHandoverFailure(DialerCall call) {
1156 if (call.showWifiHandoverAlertAsToast()) {
1157 Toast.makeText(this, R.string.video_call_lte_to_wifi_failed_message, Toast.LENGTH_SHORT)
1158 .show();
1159 return;
1160 }
1161
1162 dismissPendingDialogs();
1163
1164 AlertDialog.Builder builder =
1165 new AlertDialog.Builder(this).setTitle(R.string.video_call_lte_to_wifi_failed_title);
1166
1167 // This allows us to use the theme of the dialog instead of the activity
1168 View dialogCheckBoxView =
1169 View.inflate(builder.getContext(), R.layout.video_call_lte_to_wifi_failed, null /* root */);
1170 CheckBox wifiHandoverFailureCheckbox =
1171 (CheckBox) dialogCheckBoxView.findViewById(R.id.video_call_lte_to_wifi_failed_checkbox);
1172 wifiHandoverFailureCheckbox.setChecked(false);
1173
1174 InCallUiLock lock = InCallPresenter.getInstance().acquireInCallUiLock("WifiFailedDialog");
linyuhc3968e62017-11-20 17:40:50 -08001175 errorDialog =
linyuh7b86f562017-11-16 11:24:09 -08001176 builder
1177 .setView(dialogCheckBoxView)
1178 .setMessage(R.string.video_call_lte_to_wifi_failed_message)
1179 .setOnCancelListener(dialogInterface -> onDialogDismissed())
1180 .setPositiveButton(
1181 android.R.string.ok,
1182 (dialogInterface, id) -> {
1183 call.setDoNotShowDialogForHandoffToWifiFailure(
1184 wifiHandoverFailureCheckbox.isChecked());
1185 dialogInterface.cancel();
1186 onDialogDismissed();
1187 })
1188 .setOnDismissListener(dialogInterface -> lock.release())
1189 .create();
linyuh7b86f562017-11-16 11:24:09 -08001190 errorDialog.show();
Eric Erfanianccca3152017-02-22 16:32:36 -08001191 }
1192
linyuh7b86f562017-11-16 11:24:09 -08001193 public void showDialogForInternationalCallOnWifi(@NonNull DialerCall call) {
linyuh7b86f562017-11-16 11:24:09 -08001194 InternationalCallOnWifiDialogFragment fragment =
yuegb47528e2018-04-24 12:12:57 -07001195 InternationalCallOnWifiDialogFragment.newInstance(call.getId());
linyuhc3968e62017-11-20 17:40:50 -08001196 fragment.show(getSupportFragmentManager(), Tags.INTERNATIONAL_CALL_ON_WIFI);
Eric Erfanianc857f902017-05-15 14:05:33 -07001197 }
1198
wangqibc28ea72018-04-02 16:23:00 -07001199 public void showDialogForRttRequest(DialerCall call, int rttRequestId) {
1200 LogUtil.enterBlock("InCallActivity.showDialogForRttRequest");
1201 DialogFragment fragment = RttRequestDialogFragment.newInstance(call.getId(), rttRequestId);
1202 fragment.show(getSupportFragmentManager(), Tags.RTT_REQUEST_DIALOG);
1203 }
1204
Eric Erfanian938468d2017-10-24 14:05:52 -07001205 @Override
1206 public void onMultiWindowModeChanged(boolean isInMultiWindowMode) {
1207 super.onMultiWindowModeChanged(isInMultiWindowMode);
linyuh57b093b2017-11-17 14:32:32 -08001208 updateNavigationBar(isDialpadVisible());
1209 }
1210
linyuhc3968e62017-11-20 17:40:50 -08001211 private void updateNavigationBar(boolean isDialpadVisible) {
linyuh437ae952018-03-26 12:46:18 -07001212 if (isInMultiWindowMode()) {
linyuh57b093b2017-11-17 14:32:32 -08001213 return;
1214 }
1215
1216 View navigationBarBackground = getWindow().findViewById(R.id.navigation_bar_background);
1217 if (navigationBarBackground != null) {
1218 navigationBarBackground.setVisibility(isDialpadVisible ? View.VISIBLE : View.GONE);
Eric Erfanian938468d2017-10-24 14:05:52 -07001219 }
1220 }
1221
Eric Erfanianccca3152017-02-22 16:32:36 -08001222 public void setAllowOrientationChange(boolean allowOrientationChange) {
wangqi9982f0d2017-10-11 17:46:07 -07001223 if (this.allowOrientationChange == allowOrientationChange) {
1224 return;
1225 }
1226 this.allowOrientationChange = allowOrientationChange;
Eric Erfanianccca3152017-02-22 16:32:36 -08001227 if (!allowOrientationChange) {
1228 setRequestedOrientation(InCallOrientationEventListener.ACTIVITY_PREFERENCE_DISALLOW_ROTATION);
1229 } else {
1230 setRequestedOrientation(InCallOrientationEventListener.ACTIVITY_PREFERENCE_ALLOW_ROTATION);
1231 }
1232 enableInCallOrientationEventListener(allowOrientationChange);
1233 }
1234
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001235 public void hideMainInCallFragment() {
linyuhc3968e62017-11-20 17:40:50 -08001236 LogUtil.enterBlock("InCallActivity.hideMainInCallFragment");
1237 if (getCallCardFragmentVisible()) {
Eric Erfanianccca3152017-02-22 16:32:36 -08001238 FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
1239 hideInCallScreenFragment(transaction);
1240 hideVideoCallScreenFragment(transaction);
1241 transaction.commitAllowingStateLoss();
1242 getSupportFragmentManager().executePendingTransactions();
1243 }
1244 }
1245
1246 private void showMainInCallFragment() {
Eric Erfanian2ca43182017-08-31 06:57:16 -07001247 Trace.beginSection("InCallActivity.showMainInCallFragment");
Eric Erfanianccca3152017-02-22 16:32:36 -08001248 // If the activity's onStart method hasn't been called yet then defer doing any work.
1249 if (!isVisible) {
1250 LogUtil.i("InCallActivity.showMainInCallFragment", "not visible yet/anymore");
Eric Erfanian2ca43182017-08-31 06:57:16 -07001251 Trace.endSection();
Eric Erfanianccca3152017-02-22 16:32:36 -08001252 return;
1253 }
1254
1255 // Don't let this be reentrant.
1256 if (isInShowMainInCallFragment) {
1257 LogUtil.i("InCallActivity.showMainInCallFragment", "already in method, bailing");
Eric Erfanian2ca43182017-08-31 06:57:16 -07001258 Trace.endSection();
Eric Erfanianccca3152017-02-22 16:32:36 -08001259 return;
1260 }
1261
1262 isInShowMainInCallFragment = true;
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001263 ShouldShowUiResult shouldShowAnswerUi = getShouldShowAnswerUi();
1264 ShouldShowUiResult shouldShowVideoUi = getShouldShowVideoUi();
wangqi219b8702018-02-13 09:34:41 -08001265 ShouldShowUiResult shouldShowRttUi = getShouldShowRttUi();
erfaniand05d8992018-03-20 19:42:26 -07001266 ShouldShowUiResult shouldShowSpeakEasyUi = getShouldShowSpeakEasyUi();
Eric Erfanianccca3152017-02-22 16:32:36 -08001267 LogUtil.i(
1268 "InCallActivity.showMainInCallFragment",
wangqi219b8702018-02-13 09:34:41 -08001269 "shouldShowAnswerUi: %b, shouldShowRttUi: %b, shouldShowVideoUi: %b "
1270 + "didShowAnswerScreen: %b, didShowInCallScreen: %b, didShowRttCallScreen: %b, "
erfaniand05d8992018-03-20 19:42:26 -07001271 + "didShowVideoCallScreen: %b"
1272 + "didShowSpeakEasyScreen: %b",
Eric Erfanianccca3152017-02-22 16:32:36 -08001273 shouldShowAnswerUi.shouldShow,
wangqi219b8702018-02-13 09:34:41 -08001274 shouldShowRttUi.shouldShow,
Eric Erfanian10b34a52017-05-04 08:23:17 -07001275 shouldShowVideoUi.shouldShow,
Eric Erfanianccca3152017-02-22 16:32:36 -08001276 didShowAnswerScreen,
1277 didShowInCallScreen,
wangqi219b8702018-02-13 09:34:41 -08001278 didShowRttCallScreen,
erfaniand05d8992018-03-20 19:42:26 -07001279 didShowVideoCallScreen,
1280 didShowSpeakEasyScreen);
Eric Erfanianccca3152017-02-22 16:32:36 -08001281 // Only video call ui allows orientation change.
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001282 setAllowOrientationChange(shouldShowVideoUi.shouldShow);
Eric Erfanianccca3152017-02-22 16:32:36 -08001283
1284 FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
wangqi219b8702018-02-13 09:34:41 -08001285 boolean didChange;
Eric Erfanianccca3152017-02-22 16:32:36 -08001286 if (shouldShowAnswerUi.shouldShow) {
wangqi219b8702018-02-13 09:34:41 -08001287 didChange = hideInCallScreenFragment(transaction);
1288 didChange |= hideVideoCallScreenFragment(transaction);
1289 didChange |= hideRttCallScreenFragment(transaction);
erfaniand05d8992018-03-20 19:42:26 -07001290 didChange |= hideSpeakEasyFragment(transaction);
wangqi219b8702018-02-13 09:34:41 -08001291 didChange |= showAnswerScreenFragment(transaction, shouldShowAnswerUi.call);
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001292 } else if (shouldShowVideoUi.shouldShow) {
wangqi219b8702018-02-13 09:34:41 -08001293 didChange = hideInCallScreenFragment(transaction);
1294 didChange |= showVideoCallScreenFragment(transaction, shouldShowVideoUi.call);
1295 didChange |= hideRttCallScreenFragment(transaction);
erfaniand05d8992018-03-20 19:42:26 -07001296 didChange |= hideSpeakEasyFragment(transaction);
wangqi219b8702018-02-13 09:34:41 -08001297 didChange |= hideAnswerScreenFragment(transaction);
1298 } else if (shouldShowRttUi.shouldShow) {
1299 didChange = hideInCallScreenFragment(transaction);
1300 didChange |= hideVideoCallScreenFragment(transaction);
1301 didChange |= hideAnswerScreenFragment(transaction);
erfaniand05d8992018-03-20 19:42:26 -07001302 didChange |= hideSpeakEasyFragment(transaction);
wangqi219b8702018-02-13 09:34:41 -08001303 didChange |= showRttCallScreenFragment(transaction, shouldShowRttUi.call);
erfaniand05d8992018-03-20 19:42:26 -07001304 } else if (shouldShowSpeakEasyUi.shouldShow) {
1305 didChange = hideInCallScreenFragment(transaction);
1306 didChange |= hideVideoCallScreenFragment(transaction);
1307 didChange |= hideAnswerScreenFragment(transaction);
1308 didChange |= hideRttCallScreenFragment(transaction);
1309 didChange |= showSpeakEasyFragment(transaction, shouldShowSpeakEasyUi.call);
Eric Erfanianccca3152017-02-22 16:32:36 -08001310 } else {
wangqi219b8702018-02-13 09:34:41 -08001311 didChange = showInCallScreenFragment(transaction);
1312 didChange |= hideVideoCallScreenFragment(transaction);
1313 didChange |= hideRttCallScreenFragment(transaction);
erfaniand05d8992018-03-20 19:42:26 -07001314 didChange |= hideSpeakEasyFragment(transaction);
wangqi219b8702018-02-13 09:34:41 -08001315 didChange |= hideAnswerScreenFragment(transaction);
Eric Erfanianccca3152017-02-22 16:32:36 -08001316 }
1317
wangqi219b8702018-02-13 09:34:41 -08001318 if (didChange) {
Eric Erfanian2ca43182017-08-31 06:57:16 -07001319 Trace.beginSection("InCallActivity.commitTransaction");
Eric Erfanianccca3152017-02-22 16:32:36 -08001320 transaction.commitNow();
Eric Erfanian2ca43182017-08-31 06:57:16 -07001321 Trace.endSection();
Eric Erfanianccca3152017-02-22 16:32:36 -08001322 Logger.get(this).logScreenView(ScreenEvent.Type.INCALL, this);
1323 }
1324 isInShowMainInCallFragment = false;
Eric Erfanian2ca43182017-08-31 06:57:16 -07001325 Trace.endSection();
Eric Erfanianccca3152017-02-22 16:32:36 -08001326 }
1327
erfaniand05d8992018-03-20 19:42:26 -07001328 private boolean showSpeakEasyFragment(FragmentTransaction transaction, DialerCall call) {
1329
erfaniand05d8992018-03-20 19:42:26 -07001330 if (didShowSpeakEasyScreen) {
erfanian612d13a2018-04-04 15:27:57 -07001331 if (lastShownSpeakEasyScreenUniqueCallid.equals(call.getUniqueCallId())) {
erfanian12243de2018-04-17 12:17:08 -07001332 LogUtil.i("InCallActivity.showSpeakEasyFragment", "found existing fragment");
erfanian612d13a2018-04-04 15:27:57 -07001333 return false;
1334 }
1335 hideSpeakEasyFragment(transaction);
erfanian12243de2018-04-17 12:17:08 -07001336 LogUtil.i("InCallActivity.showSpeakEasyFragment", "hid existing fragment");
erfaniand05d8992018-03-20 19:42:26 -07001337 }
1338
1339 Optional<Fragment> speakEasyFragment = speakEasyCallManager.getSpeakEasyFragment(call);
1340 if (speakEasyFragment.isPresent()) {
1341 transaction.add(R.id.main, speakEasyFragment.get(), Tags.SPEAK_EASY_SCREEN);
1342 didShowSpeakEasyScreen = true;
erfanian612d13a2018-04-04 15:27:57 -07001343 lastShownSpeakEasyScreenUniqueCallid = call.getUniqueCallId();
erfanian12243de2018-04-17 12:17:08 -07001344 LogUtil.i(
1345 "InCallActivity.showSpeakEasyFragment",
1346 "set fragment for call %s",
1347 lastShownSpeakEasyScreenUniqueCallid);
erfaniand05d8992018-03-20 19:42:26 -07001348 return true;
1349 }
1350 return false;
1351 }
1352
1353 private Fragment getSpeakEasyScreen() {
1354 return getSupportFragmentManager().findFragmentByTag(Tags.SPEAK_EASY_SCREEN);
1355 }
1356
1357 private boolean hideSpeakEasyFragment(FragmentTransaction transaction) {
1358 if (!didShowSpeakEasyScreen) {
1359 return false;
1360 }
1361
1362 Fragment speakEasyFragment = getSpeakEasyScreen();
1363
1364 if (speakEasyFragment != null) {
1365 transaction.remove(speakEasyFragment);
1366 didShowSpeakEasyScreen = false;
1367 return true;
1368 }
1369 return false;
1370 }
1371
erfanian12243de2018-04-17 12:17:08 -07001372 @VisibleForTesting
erfaniand05d8992018-03-20 19:42:26 -07001373 public void setSpeakEasyCallManager(SpeakEasyCallManager speakEasyCallManager) {
erfanian87dbb622018-04-04 15:43:00 -07001374 this.speakEasyCallManager = speakEasyCallManager;
erfaniand05d8992018-03-20 19:42:26 -07001375 }
1376
erfanian12243de2018-04-17 12:17:08 -07001377 @Nullable
erfaniand05d8992018-03-20 19:42:26 -07001378 public SpeakEasyCallManager getSpeakEasyCallManager() {
erfanian12243de2018-04-17 12:17:08 -07001379 if (this.speakEasyCallManager == null) {
1380 this.speakEasyCallManager = InCallPresenter.getInstance().getSpeakEasyCallManager();
1381 }
erfaniand05d8992018-03-20 19:42:26 -07001382 return speakEasyCallManager;
1383 }
1384
1385 private ShouldShowUiResult getShouldShowSpeakEasyUi() {
1386 SpeakEasyCallManager speakEasyCallManager = getSpeakEasyCallManager();
1387
1388 if (speakEasyCallManager == null) {
1389 return new ShouldShowUiResult(false, null);
1390 }
1391
erfanian3bb7cb62018-04-11 09:01:15 -07001392 DialerCall call =
1393 CallList.getInstance().getIncomingCall() != null
1394 ? CallList.getInstance().getIncomingCall()
1395 : CallList.getInstance().getActiveCall();
erfaniand05d8992018-03-20 19:42:26 -07001396
1397 if (call == null) {
1398 return new ShouldShowUiResult(false, call);
1399 }
1400
1401 if (!call.isSpeakEasyCall() || !call.isSpeakEasyEligible()) {
1402 return new ShouldShowUiResult(false, call);
1403 }
1404
1405 Optional<Fragment> speakEasyFragment = speakEasyCallManager.getSpeakEasyFragment(call);
1406
1407 if (!speakEasyFragment.isPresent()) {
1408 return new ShouldShowUiResult(false, call);
1409 }
1410 return new ShouldShowUiResult(true, call);
1411 }
1412
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001413 private ShouldShowUiResult getShouldShowAnswerUi() {
Eric Erfanianccca3152017-02-22 16:32:36 -08001414 DialerCall call = CallList.getInstance().getIncomingCall();
erfanian3bb7cb62018-04-11 09:01:15 -07001415 if (call != null && !call.isSpeakEasyCall()) {
Eric Erfanianccca3152017-02-22 16:32:36 -08001416 LogUtil.i("InCallActivity.getShouldShowAnswerUi", "found incoming call");
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001417 return new ShouldShowUiResult(true, call);
Eric Erfanianccca3152017-02-22 16:32:36 -08001418 }
1419
1420 call = CallList.getInstance().getVideoUpgradeRequestCall();
1421 if (call != null) {
1422 LogUtil.i("InCallActivity.getShouldShowAnswerUi", "found video upgrade request");
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001423 return new ShouldShowUiResult(true, call);
Eric Erfanianccca3152017-02-22 16:32:36 -08001424 }
1425
1426 // Check if we're showing the answer screen and the call is disconnected. If this condition is
1427 // true then we won't switch from the answer UI to the in call UI. This prevents flicker when
1428 // the user rejects an incoming call.
1429 call = CallList.getInstance().getFirstCall();
1430 if (call == null) {
1431 call = CallList.getInstance().getBackgroundCall();
1432 }
1433 if (didShowAnswerScreen && (call == null || call.getState() == State.DISCONNECTED)) {
1434 LogUtil.i("InCallActivity.getShouldShowAnswerUi", "found disconnecting incoming call");
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001435 return new ShouldShowUiResult(true, call);
Eric Erfanianccca3152017-02-22 16:32:36 -08001436 }
1437
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001438 return new ShouldShowUiResult(false, null);
Eric Erfanianccca3152017-02-22 16:32:36 -08001439 }
1440
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001441 private static ShouldShowUiResult getShouldShowVideoUi() {
Eric Erfanianccca3152017-02-22 16:32:36 -08001442 DialerCall call = CallList.getInstance().getFirstCall();
1443 if (call == null) {
1444 LogUtil.i("InCallActivity.getShouldShowVideoUi", "null call");
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001445 return new ShouldShowUiResult(false, null);
Eric Erfanianccca3152017-02-22 16:32:36 -08001446 }
1447
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001448 if (call.isVideoCall()) {
Eric Erfanianccca3152017-02-22 16:32:36 -08001449 LogUtil.i("InCallActivity.getShouldShowVideoUi", "found video call");
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001450 return new ShouldShowUiResult(true, call);
Eric Erfanianccca3152017-02-22 16:32:36 -08001451 }
1452
linyuh8fbecce2017-12-18 13:53:09 -08001453 if (call.hasSentVideoUpgradeRequest() || call.hasReceivedVideoUpgradeRequest()) {
Eric Erfanianccca3152017-02-22 16:32:36 -08001454 LogUtil.i("InCallActivity.getShouldShowVideoUi", "upgrading to video");
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001455 return new ShouldShowUiResult(true, call);
Eric Erfanianccca3152017-02-22 16:32:36 -08001456 }
1457
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001458 return new ShouldShowUiResult(false, null);
Eric Erfanianccca3152017-02-22 16:32:36 -08001459 }
1460
wangqi219b8702018-02-13 09:34:41 -08001461 private static ShouldShowUiResult getShouldShowRttUi() {
1462 DialerCall call = CallList.getInstance().getFirstCall();
1463 if (call == null) {
1464 LogUtil.i("InCallActivity.getShouldShowRttUi", "null call");
1465 return new ShouldShowUiResult(false, null);
1466 }
1467
wangqif6be6172018-03-30 15:57:56 -07001468 if (call.isActiveRttCall()) {
wangqi219b8702018-02-13 09:34:41 -08001469 LogUtil.i("InCallActivity.getShouldShowRttUi", "found rtt call");
1470 return new ShouldShowUiResult(true, call);
1471 }
1472
1473 if (call.hasSentRttUpgradeRequest()) {
1474 LogUtil.i("InCallActivity.getShouldShowRttUi", "upgrading to rtt");
1475 return new ShouldShowUiResult(true, call);
1476 }
1477
1478 return new ShouldShowUiResult(false, null);
1479 }
1480
Eric Erfanianccca3152017-02-22 16:32:36 -08001481 private boolean showAnswerScreenFragment(FragmentTransaction transaction, DialerCall call) {
1482 // When rejecting a call the active call can become null in which case we should continue
1483 // showing the answer screen.
1484 if (didShowAnswerScreen && call == null) {
1485 return false;
1486 }
1487
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001488 Assert.checkArgument(call != null, "didShowAnswerScreen was false but call was still null");
1489
1490 boolean isVideoUpgradeRequest = call.hasReceivedVideoUpgradeRequest();
Eric Erfanianccca3152017-02-22 16:32:36 -08001491
1492 // Check if we're already showing an answer screen for this call.
1493 if (didShowAnswerScreen) {
1494 AnswerScreen answerScreen = getAnswerScreen();
1495 if (answerScreen.getCallId().equals(call.getId())
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001496 && answerScreen.isVideoCall() == call.isVideoCall()
Eric Erfanian2ca43182017-08-31 06:57:16 -07001497 && answerScreen.isVideoUpgradeRequest() == isVideoUpgradeRequest
1498 && !answerScreen.isActionTimeout()) {
1499 LogUtil.d(
1500 "InCallActivity.showAnswerScreenFragment",
1501 "answer fragment exists for same call and has NOT been accepted/rejected/timed out");
Eric Erfanianccca3152017-02-22 16:32:36 -08001502 return false;
1503 }
Eric Erfanian2ca43182017-08-31 06:57:16 -07001504 if (answerScreen.isActionTimeout()) {
1505 LogUtil.i(
1506 "InCallActivity.showAnswerScreenFragment",
1507 "answer fragment exists but has been accepted/rejected and timed out");
1508 } else {
1509 LogUtil.i(
1510 "InCallActivity.showAnswerScreenFragment",
1511 "answer fragment exists but arguments do not match");
1512 }
Eric Erfanianccca3152017-02-22 16:32:36 -08001513 hideAnswerScreenFragment(transaction);
1514 }
1515
1516 // Show a new answer screen.
1517 AnswerScreen answerScreen =
Eric Erfanianfc37b022017-03-21 10:11:17 -07001518 AnswerBindings.createAnswerScreen(
1519 call.getId(),
wangqif6be6172018-03-30 15:57:56 -07001520 call.isActiveRttCall(),
Eric Erfanianfc37b022017-03-21 10:11:17 -07001521 call.isVideoCall(),
1522 isVideoUpgradeRequest,
Eric Erfanian90508232017-03-24 09:31:16 -07001523 call.getVideoTech().isSelfManagedCamera(),
1524 shouldAllowAnswerAndRelease(call),
erfaniand05d8992018-03-20 19:42:26 -07001525 CallList.getInstance().getBackgroundCall() != null,
1526 call.isSpeakEasyEligible());
linyuhc3968e62017-11-20 17:40:50 -08001527 transaction.add(R.id.main, answerScreen.getAnswerScreenFragment(), Tags.ANSWER_SCREEN);
Eric Erfanianccca3152017-02-22 16:32:36 -08001528
1529 Logger.get(this).logScreenView(ScreenEvent.Type.INCOMING_CALL, this);
1530 didShowAnswerScreen = true;
1531 return true;
1532 }
1533
Eric Erfanian90508232017-03-24 09:31:16 -07001534 private boolean shouldAllowAnswerAndRelease(DialerCall call) {
1535 if (CallList.getInstance().getActiveCall() == null) {
1536 LogUtil.i("InCallActivity.shouldAllowAnswerAndRelease", "no active call");
1537 return false;
1538 }
1539 if (getSystemService(TelephonyManager.class).getPhoneType()
1540 == TelephonyManager.PHONE_TYPE_CDMA) {
1541 LogUtil.i("InCallActivity.shouldAllowAnswerAndRelease", "PHONE_TYPE_CDMA not supported");
1542 return false;
1543 }
1544 if (call.isVideoCall() || call.hasReceivedVideoUpgradeRequest()) {
1545 LogUtil.i("InCallActivity.shouldAllowAnswerAndRelease", "video call");
1546 return false;
1547 }
linyuhc3968e62017-11-20 17:40:50 -08001548 if (!ConfigProviderBindings.get(this)
1549 .getBoolean(ConfigNames.ANSWER_AND_RELEASE_ENABLED, true)) {
Eric Erfanian90508232017-03-24 09:31:16 -07001550 LogUtil.i("InCallActivity.shouldAllowAnswerAndRelease", "disabled by config");
1551 return false;
1552 }
1553
1554 return true;
1555 }
1556
Eric Erfanianccca3152017-02-22 16:32:36 -08001557 private boolean hideAnswerScreenFragment(FragmentTransaction transaction) {
1558 if (!didShowAnswerScreen) {
1559 return false;
1560 }
1561 AnswerScreen answerScreen = getAnswerScreen();
1562 if (answerScreen != null) {
1563 transaction.remove(answerScreen.getAnswerScreenFragment());
1564 }
1565
1566 didShowAnswerScreen = false;
1567 return true;
1568 }
1569
1570 private boolean showInCallScreenFragment(FragmentTransaction transaction) {
1571 if (didShowInCallScreen) {
1572 return false;
1573 }
Eric Erfanian2ca43182017-08-31 06:57:16 -07001574 InCallScreen inCallScreen = InCallBindings.createInCallScreen();
linyuhc3968e62017-11-20 17:40:50 -08001575 transaction.add(R.id.main, inCallScreen.getInCallScreenFragment(), Tags.IN_CALL_SCREEN);
Eric Erfanianccca3152017-02-22 16:32:36 -08001576 Logger.get(this).logScreenView(ScreenEvent.Type.INCALL, this);
1577 didShowInCallScreen = true;
1578 return true;
1579 }
1580
1581 private boolean hideInCallScreenFragment(FragmentTransaction transaction) {
1582 if (!didShowInCallScreen) {
1583 return false;
1584 }
1585 InCallScreen inCallScreen = getInCallScreen();
1586 if (inCallScreen != null) {
Eric Erfanian2ca43182017-08-31 06:57:16 -07001587 transaction.remove(inCallScreen.getInCallScreenFragment());
Eric Erfanianccca3152017-02-22 16:32:36 -08001588 }
1589 didShowInCallScreen = false;
1590 return true;
1591 }
1592
wangqi219b8702018-02-13 09:34:41 -08001593 private boolean showRttCallScreenFragment(FragmentTransaction transaction, DialerCall call) {
1594 if (didShowRttCallScreen) {
1595 // This shouldn't happen since only one RTT call is allow at same time.
1596 if (!getRttCallScreen().getCallId().equals(call.getId())) {
1597 LogUtil.e("InCallActivity.showRttCallScreenFragment", "RTT call id doesn't match");
1598 }
1599 return false;
1600 }
1601 RttCallScreen rttCallScreen = RttBindings.createRttCallScreen(call.getId());
1602 transaction.add(R.id.main, rttCallScreen.getRttCallScreenFragment(), Tags.RTT_CALL_SCREEN);
1603 Logger.get(this).logScreenView(ScreenEvent.Type.INCALL, this);
1604 didShowRttCallScreen = true;
1605 return true;
1606 }
1607
1608 private boolean hideRttCallScreenFragment(FragmentTransaction transaction) {
1609 if (!didShowRttCallScreen) {
1610 return false;
1611 }
1612 RttCallScreen rttCallScreen = getRttCallScreen();
1613 if (rttCallScreen != null) {
1614 transaction.remove(rttCallScreen.getRttCallScreenFragment());
1615 }
1616 didShowRttCallScreen = false;
1617 return true;
1618 }
1619
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001620 private boolean showVideoCallScreenFragment(FragmentTransaction transaction, DialerCall call) {
Eric Erfanianccca3152017-02-22 16:32:36 -08001621 if (didShowVideoCallScreen) {
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001622 VideoCallScreen videoCallScreen = getVideoCallScreen();
1623 if (videoCallScreen.getCallId().equals(call.getId())) {
1624 return false;
1625 }
1626 LogUtil.i(
1627 "InCallActivity.showVideoCallScreenFragment",
1628 "video call fragment exists but arguments do not match");
1629 hideVideoCallScreenFragment(transaction);
Eric Erfanianccca3152017-02-22 16:32:36 -08001630 }
1631
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001632 LogUtil.i("InCallActivity.showVideoCallScreenFragment", "call: %s", call);
1633
Eric Erfanian90508232017-03-24 09:31:16 -07001634 VideoCallScreen videoCallScreen =
1635 VideoBindings.createVideoCallScreen(
1636 call.getId(), call.getVideoTech().shouldUseSurfaceView());
linyuhc3968e62017-11-20 17:40:50 -08001637 transaction.add(
1638 R.id.main, videoCallScreen.getVideoCallScreenFragment(), Tags.VIDEO_CALL_SCREEN);
Eric Erfanianccca3152017-02-22 16:32:36 -08001639
1640 Logger.get(this).logScreenView(ScreenEvent.Type.INCALL, this);
1641 didShowVideoCallScreen = true;
1642 return true;
1643 }
1644
1645 private boolean hideVideoCallScreenFragment(FragmentTransaction transaction) {
1646 if (!didShowVideoCallScreen) {
1647 return false;
1648 }
1649 VideoCallScreen videoCallScreen = getVideoCallScreen();
1650 if (videoCallScreen != null) {
1651 transaction.remove(videoCallScreen.getVideoCallScreenFragment());
1652 }
1653 didShowVideoCallScreen = false;
1654 return true;
1655 }
1656
linyuhc3968e62017-11-20 17:40:50 -08001657 private AnswerScreen getAnswerScreen() {
1658 return (AnswerScreen) getSupportFragmentManager().findFragmentByTag(Tags.ANSWER_SCREEN);
Eric Erfanianccca3152017-02-22 16:32:36 -08001659 }
1660
linyuhc3968e62017-11-20 17:40:50 -08001661 private InCallScreen getInCallScreen() {
1662 return (InCallScreen) getSupportFragmentManager().findFragmentByTag(Tags.IN_CALL_SCREEN);
Eric Erfanianccca3152017-02-22 16:32:36 -08001663 }
1664
linyuhc3968e62017-11-20 17:40:50 -08001665 private VideoCallScreen getVideoCallScreen() {
1666 return (VideoCallScreen) getSupportFragmentManager().findFragmentByTag(Tags.VIDEO_CALL_SCREEN);
Eric Erfanianccca3152017-02-22 16:32:36 -08001667 }
1668
wangqi219b8702018-02-13 09:34:41 -08001669 private RttCallScreen getRttCallScreen() {
1670 return (RttCallScreen) getSupportFragmentManager().findFragmentByTag(Tags.RTT_CALL_SCREEN);
1671 }
1672
wangqifd4c9f72018-03-08 18:21:50 -08001673 private InCallScreen getInCallOrRttCallScreen() {
1674 InCallScreen inCallScreen = null;
1675 if (didShowInCallScreen) {
1676 inCallScreen = getInCallScreen();
1677 }
1678 if (didShowRttCallScreen) {
1679 inCallScreen = getRttCallScreen();
1680 }
1681 return inCallScreen;
1682 }
1683
Eric Erfanianccca3152017-02-22 16:32:36 -08001684 @Override
1685 public void onPseudoScreenStateChanged(boolean isOn) {
1686 LogUtil.i("InCallActivity.onPseudoScreenStateChanged", "isOn: " + isOn);
1687 pseudoBlackScreenOverlay.setVisibility(isOn ? View.GONE : View.VISIBLE);
1688 }
1689
1690 /**
1691 * For some touch related issue, turning off the screen can be faked by drawing a black view over
1692 * the activity. All touch events started when the screen is "off" is rejected.
1693 *
1694 * @see PseudoScreenState
1695 */
1696 @Override
1697 public boolean dispatchTouchEvent(MotionEvent event) {
1698 // Reject any gesture that started when the screen is in the fake off state.
1699 if (touchDownWhenPseudoScreenOff) {
1700 if (event.getAction() == MotionEvent.ACTION_UP) {
1701 touchDownWhenPseudoScreenOff = false;
1702 }
1703 return true;
1704 }
1705 // Reject all touch event when the screen is in the fake off state.
1706 if (!InCallPresenter.getInstance().getPseudoScreenState().isOn()) {
1707 if (event.getAction() == MotionEvent.ACTION_DOWN) {
1708 touchDownWhenPseudoScreenOff = true;
1709 LogUtil.i("InCallActivity.dispatchTouchEvent", "touchDownWhenPseudoScreenOff");
1710 }
1711 return true;
1712 }
1713 return super.dispatchTouchEvent(event);
1714 }
1715
wangqi219b8702018-02-13 09:34:41 -08001716 @Override
1717 public RttCallScreenDelegate newRttCallScreenDelegate(RttCallScreen videoCallScreen) {
1718 return new RttCallPresenter();
1719 }
1720
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001721 private static class ShouldShowUiResult {
Eric Erfanianccca3152017-02-22 16:32:36 -08001722 public final boolean shouldShow;
1723 public final DialerCall call;
1724
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001725 ShouldShowUiResult(boolean shouldShow, DialerCall call) {
Eric Erfanianccca3152017-02-22 16:32:36 -08001726 this.shouldShow = shouldShow;
1727 this.call = call;
1728 }
1729 }
linyuhc3968e62017-11-20 17:40:50 -08001730
1731 private static final class IntentExtraNames {
1732 static final String FOR_FULL_SCREEN = "InCallActivity.for_full_screen_intent";
1733 static final String NEW_OUTGOING_CALL = "InCallActivity.new_outgoing_call";
1734 static final String SHOW_DIALPAD = "InCallActivity.show_dialpad";
1735 }
1736
1737 private static final class KeysForSavedInstance {
1738 static final String DIALPAD_TEXT = "InCallActivity.dialpad_text";
1739 static final String DID_SHOW_ANSWER_SCREEN = "did_show_answer_screen";
1740 static final String DID_SHOW_IN_CALL_SCREEN = "did_show_in_call_screen";
1741 static final String DID_SHOW_VIDEO_CALL_SCREEN = "did_show_video_call_screen";
wangqi153af2f2018-02-15 16:21:49 -08001742 static final String DID_SHOW_RTT_CALL_SCREEN = "did_show_rtt_call_screen";
erfaniand05d8992018-03-20 19:42:26 -07001743 static final String DID_SHOW_SPEAK_EASY_SCREEN = "did_show_speak_easy_screen";
linyuhc3968e62017-11-20 17:40:50 -08001744 }
1745
1746 /** Request codes for pending intents. */
1747 public static final class PendingIntentRequestCodes {
1748 static final int NON_FULL_SCREEN = 0;
1749 static final int FULL_SCREEN = 1;
1750 static final int BUBBLE = 2;
1751 }
1752
1753 private static final class Tags {
1754 static final String ANSWER_SCREEN = "tag_answer_screen";
1755 static final String DIALPAD_FRAGMENT = "tag_dialpad_fragment";
1756 static final String IN_CALL_SCREEN = "tag_in_call_screen";
1757 static final String INTERNATIONAL_CALL_ON_WIFI = "tag_international_call_on_wifi";
1758 static final String SELECT_ACCOUNT_FRAGMENT = "tag_select_account_fragment";
1759 static final String VIDEO_CALL_SCREEN = "tag_video_call_screen";
wangqi219b8702018-02-13 09:34:41 -08001760 static final String RTT_CALL_SCREEN = "tag_rtt_call_screen";
linyuhc3968e62017-11-20 17:40:50 -08001761 static final String POST_CHAR_DIALOG_FRAGMENT = "tag_post_char_dialog_fragment";
erfaniand05d8992018-03-20 19:42:26 -07001762 static final String SPEAK_EASY_SCREEN = "tag_speak_easy_screen";
wangqibc28ea72018-04-02 16:23:00 -07001763 static final String RTT_REQUEST_DIALOG = "tag_rtt_request_dialog";
linyuhc3968e62017-11-20 17:40:50 -08001764 }
1765
1766 private static final class ConfigNames {
1767 static final String ANSWER_AND_RELEASE_ENABLED = "answer_and_release_enabled";
1768 }
1769
linyuhc3968e62017-11-20 17:40:50 -08001770 private static final class SelectPhoneAccountListener
1771 extends SelectPhoneAccountDialogFragment.SelectPhoneAccountListener {
1772 private static final String TAG = SelectPhoneAccountListener.class.getCanonicalName();
1773
twyen73a74c32018-03-07 12:12:24 -08001774 private final Context appContext;
1775
1776 SelectPhoneAccountListener(Context appContext) {
1777 this.appContext = appContext;
1778 }
1779
linyuhc3968e62017-11-20 17:40:50 -08001780 @Override
1781 public void onPhoneAccountSelected(
1782 PhoneAccountHandle selectedAccountHandle, boolean setDefault, String callId) {
1783 DialerCall call = CallList.getInstance().getCallById(callId);
1784 LogUtil.i(TAG, "Phone account select with call:\n%s", call);
1785
1786 if (call != null) {
twyen73a74c32018-03-07 12:12:24 -08001787 call.phoneAccountSelected(selectedAccountHandle, false);
1788 if (call.getPreferredAccountRecorder() != null) {
1789 call.getPreferredAccountRecorder().record(appContext, selectedAccountHandle, setDefault);
1790 }
linyuhc3968e62017-11-20 17:40:50 -08001791 }
1792 }
1793
1794 @Override
1795 public void onDialogDismissed(String callId) {
1796 DialerCall call = CallList.getInstance().getCallById(callId);
1797 LogUtil.i(TAG, "Disconnecting call:\n%s" + call);
1798
1799 if (call != null) {
1800 call.disconnect();
1801 }
1802 }
1803 }
Eric Erfanianccca3152017-02-22 16:32:36 -08001804}