blob: 68de8dcc3b1184ee9a920ae9f6e48ba46c15cc3b [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;
twyen66adad02018-04-24 13:51:08 -070058import com.android.contacts.common.widget.SelectPhoneAccountDialogOptions;
59import com.android.contacts.common.widget.SelectPhoneAccountDialogOptionsUtil;
linyuhc3968e62017-11-20 17:40:50 -080060import com.android.dialer.animation.AnimUtils;
61import com.android.dialer.animation.AnimationListenerAdapter;
Eric Erfaniand5e47f62017-03-15 14:41:07 -070062import com.android.dialer.common.Assert;
Eric Erfanianccca3152017-02-22 16:32:36 -080063import com.android.dialer.common.LogUtil;
twyen73a74c32018-03-07 12:12:24 -080064import com.android.dialer.common.concurrent.DialerExecutorComponent;
weijiaxu650e7cc2017-10-31 12:38:54 -070065import com.android.dialer.common.concurrent.ThreadUtil;
Eric Erfanian2ca43182017-08-31 06:57:16 -070066import com.android.dialer.configprovider.ConfigProviderBindings;
twyen73a74c32018-03-07 12:12:24 -080067import com.android.dialer.logging.DialerImpression.Type;
Eric Erfanianccca3152017-02-22 16:32:36 -080068import com.android.dialer.logging.Logger;
Eric Erfanian8369df02017-05-03 10:27:13 -070069import com.android.dialer.logging.ScreenEvent;
zachh7a96dc72018-02-20 22:16:03 -080070import com.android.dialer.metrics.Metrics;
71import com.android.dialer.metrics.MetricsComponent;
twyen73a74c32018-03-07 12:12:24 -080072import com.android.dialer.preferredsim.PreferredAccountRecorder;
73import com.android.dialer.preferredsim.PreferredAccountWorker;
74import com.android.dialer.preferredsim.suggestion.SuggestionProvider;
linyuhc3968e62017-11-20 17:40:50 -080075import com.android.dialer.util.ViewUtil;
Eric Erfanianccca3152017-02-22 16:32:36 -080076import com.android.incallui.answer.bindings.AnswerBindings;
77import com.android.incallui.answer.protocol.AnswerScreen;
78import com.android.incallui.answer.protocol.AnswerScreenDelegate;
79import com.android.incallui.answer.protocol.AnswerScreenDelegateFactory;
80import com.android.incallui.answerproximitysensor.PseudoScreenState;
linyuh57b093b2017-11-17 14:32:32 -080081import com.android.incallui.audiomode.AudioModeProvider;
Eric Erfanianccca3152017-02-22 16:32:36 -080082import com.android.incallui.call.CallList;
83import com.android.incallui.call.DialerCall;
84import com.android.incallui.call.DialerCall.State;
linyuh57b093b2017-11-17 14:32:32 -080085import com.android.incallui.call.TelecomAdapter;
Eric Erfanian2ca43182017-08-31 06:57:16 -070086import com.android.incallui.callpending.CallPendingActivity;
87import com.android.incallui.disconnectdialog.DisconnectMessage;
Eric Erfanianccca3152017-02-22 16:32:36 -080088import com.android.incallui.incall.bindings.InCallBindings;
89import com.android.incallui.incall.protocol.InCallButtonUiDelegate;
90import com.android.incallui.incall.protocol.InCallButtonUiDelegateFactory;
91import com.android.incallui.incall.protocol.InCallScreen;
92import com.android.incallui.incall.protocol.InCallScreenDelegate;
93import com.android.incallui.incall.protocol.InCallScreenDelegateFactory;
linyuh7b86f562017-11-16 11:24:09 -080094import com.android.incallui.incalluilock.InCallUiLock;
wangqi219b8702018-02-13 09:34:41 -080095import com.android.incallui.rtt.bindings.RttBindings;
96import com.android.incallui.rtt.protocol.RttCallScreen;
97import com.android.incallui.rtt.protocol.RttCallScreenDelegate;
98import com.android.incallui.rtt.protocol.RttCallScreenDelegateFactory;
erfaniand05d8992018-03-20 19:42:26 -070099import com.android.incallui.speakeasy.SpeakEasyCallManager;
linyuhf99f6302017-11-15 11:23:51 -0800100import com.android.incallui.telecomeventui.InternationalCallOnWifiDialogFragment;
Eric Erfanianccca3152017-02-22 16:32:36 -0800101import com.android.incallui.video.bindings.VideoBindings;
102import com.android.incallui.video.protocol.VideoCallScreen;
103import com.android.incallui.video.protocol.VideoCallScreenDelegate;
104import com.android.incallui.video.protocol.VideoCallScreenDelegateFactory;
linyuhc3968e62017-11-20 17:40:50 -0800105import com.google.common.base.Optional;
106import java.lang.annotation.Retention;
107import java.lang.annotation.RetentionPolicy;
108import java.util.ArrayList;
109import java.util.List;
Eric Erfanianccca3152017-02-22 16:32:36 -0800110
111/** Version of {@link InCallActivity} that shows the new UI */
112public class InCallActivity extends TransactionSafeFragmentActivity
113 implements AnswerScreenDelegateFactory,
114 InCallScreenDelegateFactory,
115 InCallButtonUiDelegateFactory,
116 VideoCallScreenDelegateFactory,
wangqi219b8702018-02-13 09:34:41 -0800117 RttCallScreenDelegateFactory,
Eric Erfanianccca3152017-02-22 16:32:36 -0800118 PseudoScreenState.StateChangedListener {
119
linyuhc3968e62017-11-20 17:40:50 -0800120 @Retention(RetentionPolicy.SOURCE)
121 @IntDef({
122 DIALPAD_REQUEST_NONE,
123 DIALPAD_REQUEST_SHOW,
124 DIALPAD_REQUEST_HIDE,
125 })
126 @interface DialpadRequestType {}
Eric Erfanian2ca43182017-08-31 06:57:16 -0700127
linyuhc3968e62017-11-20 17:40:50 -0800128 private static final int DIALPAD_REQUEST_NONE = 1;
129 private static final int DIALPAD_REQUEST_SHOW = 2;
130 private static final int DIALPAD_REQUEST_HIDE = 3;
linyuh57b093b2017-11-17 14:32:32 -0800131
linyuhc3968e62017-11-20 17:40:50 -0800132 private static Optional<Integer> audioRouteForTesting = Optional.absent();
linyuh57b093b2017-11-17 14:32:32 -0800133
twyen73a74c32018-03-07 12:12:24 -0800134 private SelectPhoneAccountListener selectPhoneAccountListener;
Eric Erfanianccca3152017-02-22 16:32:36 -0800135
linyuhc3968e62017-11-20 17:40:50 -0800136 private Animation dialpadSlideInAnimation;
137 private Animation dialpadSlideOutAnimation;
138 private Dialog errorDialog;
139 private GradientDrawable backgroundDrawable;
linyuh69a25062017-11-15 16:18:51 -0800140 private InCallOrientationEventListener inCallOrientationEventListener;
linyuhc3968e62017-11-20 17:40:50 -0800141 private View pseudoBlackScreenOverlay;
142 private SelectPhoneAccountDialogFragment selectPhoneAccountDialogFragment;
143 private String dtmfTextToPrepopulate;
144 private String showPostCharWaitDialogCallId;
145 private String showPostCharWaitDialogChars;
146 private boolean allowOrientationChange;
147 private boolean animateDialpadOnShow;
Eric Erfanianccca3152017-02-22 16:32:36 -0800148 private boolean didShowAnswerScreen;
149 private boolean didShowInCallScreen;
150 private boolean didShowVideoCallScreen;
wangqi219b8702018-02-13 09:34:41 -0800151 private boolean didShowRttCallScreen;
erfaniand05d8992018-03-20 19:42:26 -0700152 private boolean didShowSpeakEasyScreen;
erfanian612d13a2018-04-04 15:27:57 -0700153 private String lastShownSpeakEasyScreenUniqueCallid = "";
linyuh9c327da2017-11-14 12:33:48 -0800154 private boolean dismissKeyguard;
Eric Erfanianccca3152017-02-22 16:32:36 -0800155 private boolean isInShowMainInCallFragment;
linyuhc3968e62017-11-20 17:40:50 -0800156 private boolean isRecreating; // whether the activity is going to be recreated
157 private boolean isVisible;
Eric Erfanianccca3152017-02-22 16:32:36 -0800158 private boolean needDismissPendingDialogs;
linyuhc3968e62017-11-20 17:40:50 -0800159 private boolean showPostCharWaitDialogOnResume;
160 private boolean touchDownWhenPseudoScreenOff;
161 private int[] backgroundDrawableColors;
162 @DialpadRequestType private int showDialpadRequest = DIALPAD_REQUEST_NONE;
erfaniand05d8992018-03-20 19:42:26 -0700163 private SpeakEasyCallManager speakEasyCallManager;
Eric Erfanianccca3152017-02-22 16:32:36 -0800164
165 public static Intent getIntent(
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700166 Context context, boolean showDialpad, boolean newOutgoingCall, boolean isForFullScreen) {
Eric Erfanianccca3152017-02-22 16:32:36 -0800167 Intent intent = new Intent(Intent.ACTION_MAIN, null);
168 intent.setFlags(Intent.FLAG_ACTIVITY_NO_USER_ACTION | Intent.FLAG_ACTIVITY_NEW_TASK);
169 intent.setClass(context, InCallActivity.class);
linyuhc3968e62017-11-20 17:40:50 -0800170 if (showDialpad) {
171 intent.putExtra(IntentExtraNames.SHOW_DIALPAD, true);
172 }
173 intent.putExtra(IntentExtraNames.NEW_OUTGOING_CALL, newOutgoingCall);
174 intent.putExtra(IntentExtraNames.FOR_FULL_SCREEN, isForFullScreen);
Eric Erfanianccca3152017-02-22 16:32:36 -0800175 return intent;
176 }
177
178 @Override
179 protected void onResumeFragments() {
180 super.onResumeFragments();
181 if (needDismissPendingDialogs) {
182 dismissPendingDialogs();
183 }
184 }
185
186 @Override
linyuhc3968e62017-11-20 17:40:50 -0800187 protected void onCreate(Bundle bundle) {
Eric Erfanian2ca43182017-08-31 06:57:16 -0700188 Trace.beginSection("InCallActivity.onCreate");
linyuhc3968e62017-11-20 17:40:50 -0800189 super.onCreate(bundle);
Eric Erfanianccca3152017-02-22 16:32:36 -0800190
twyen73a74c32018-03-07 12:12:24 -0800191 selectPhoneAccountListener = new SelectPhoneAccountListener(getApplicationContext());
192
linyuhc3968e62017-11-20 17:40:50 -0800193 if (bundle != null) {
194 didShowAnswerScreen = bundle.getBoolean(KeysForSavedInstance.DID_SHOW_ANSWER_SCREEN);
195 didShowInCallScreen = bundle.getBoolean(KeysForSavedInstance.DID_SHOW_IN_CALL_SCREEN);
196 didShowVideoCallScreen = bundle.getBoolean(KeysForSavedInstance.DID_SHOW_VIDEO_CALL_SCREEN);
wangqi153af2f2018-02-15 16:21:49 -0800197 didShowRttCallScreen = bundle.getBoolean(KeysForSavedInstance.DID_SHOW_RTT_CALL_SCREEN);
Eric Erfanianccca3152017-02-22 16:32:36 -0800198 }
199
linyuhc3968e62017-11-20 17:40:50 -0800200 setWindowFlags();
201 setContentView(R.layout.incall_screen);
202 internalResolveIntent(getIntent());
203
204 boolean isLandscape =
205 getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE;
206 boolean isRtl = ViewUtil.isRtl();
207 if (isLandscape) {
208 dialpadSlideInAnimation =
209 AnimationUtils.loadAnimation(
210 this, isRtl ? R.anim.dialpad_slide_in_left : R.anim.dialpad_slide_in_right);
211 dialpadSlideOutAnimation =
212 AnimationUtils.loadAnimation(
213 this, isRtl ? R.anim.dialpad_slide_out_left : R.anim.dialpad_slide_out_right);
214 } else {
215 dialpadSlideInAnimation = AnimationUtils.loadAnimation(this, R.anim.dialpad_slide_in_bottom);
216 dialpadSlideOutAnimation =
217 AnimationUtils.loadAnimation(this, R.anim.dialpad_slide_out_bottom);
218 }
219 dialpadSlideInAnimation.setInterpolator(AnimUtils.EASE_IN);
220 dialpadSlideOutAnimation.setInterpolator(AnimUtils.EASE_OUT);
221 dialpadSlideOutAnimation.setAnimationListener(
222 new AnimationListenerAdapter() {
223 @Override
224 public void onAnimationEnd(Animation animation) {
225 hideDialpadFragment();
226 }
227 });
228
229 if (bundle != null && showDialpadRequest == DIALPAD_REQUEST_NONE) {
230 // If the dialpad was shown before, set related variables so that it can be shown and
231 // populated with the previous DTMF text during onResume().
232 if (bundle.containsKey(IntentExtraNames.SHOW_DIALPAD)) {
233 boolean showDialpad = bundle.getBoolean(IntentExtraNames.SHOW_DIALPAD);
234 showDialpadRequest = showDialpad ? DIALPAD_REQUEST_SHOW : DIALPAD_REQUEST_HIDE;
235 animateDialpadOnShow = false;
236 }
237 dtmfTextToPrepopulate = bundle.getString(KeysForSavedInstance.DIALPAD_TEXT);
238
239 SelectPhoneAccountDialogFragment selectPhoneAccountDialogFragment =
240 (SelectPhoneAccountDialogFragment)
241 getFragmentManager().findFragmentByTag(Tags.SELECT_ACCOUNT_FRAGMENT);
242 if (selectPhoneAccountDialogFragment != null) {
243 selectPhoneAccountDialogFragment.setListener(selectPhoneAccountListener);
244 }
245 }
246
linyuh69a25062017-11-15 16:18:51 -0800247 inCallOrientationEventListener = new InCallOrientationEventListener(this);
Eric Erfanianccca3152017-02-22 16:32:36 -0800248
249 getWindow()
250 .getDecorView()
251 .setSystemUiVisibility(
252 View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
253
254 pseudoBlackScreenOverlay = findViewById(R.id.psuedo_black_screen_overlay);
Eric Erfanian2ca43182017-08-31 06:57:16 -0700255 sendBroadcast(CallPendingActivity.getFinishBroadcast());
256 Trace.endSection();
zachh7a96dc72018-02-20 22:16:03 -0800257 MetricsComponent.get(this)
258 .metrics()
259 .stopTimer(Metrics.ON_CALL_ADDED_TO_ON_INCALL_UI_SHOWN_INCOMING);
260 MetricsComponent.get(this)
261 .metrics()
262 .stopTimer(Metrics.ON_CALL_ADDED_TO_ON_INCALL_UI_SHOWN_OUTGOING);
Eric Erfanianccca3152017-02-22 16:32:36 -0800263 }
264
linyuhc3968e62017-11-20 17:40:50 -0800265 private void setWindowFlags() {
266 // Allow the activity to be shown when the screen is locked and filter out touch events that are
267 // "too fat".
268 int flags =
269 WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
270 | WindowManager.LayoutParams.FLAG_IGNORE_CHEEK_PRESSES;
271
linyuhf79d1cb2017-12-15 17:49:56 -0800272 // When the audio stream is not via Bluetooth, turn on the screen once the activity is shown.
273 // When the audio stream is via Bluetooth, turn on the screen only for an incoming call.
linyuhc3968e62017-11-20 17:40:50 -0800274 final int audioRoute = getAudioRoute();
linyuhf79d1cb2017-12-15 17:49:56 -0800275 if (audioRoute != CallAudioState.ROUTE_BLUETOOTH
276 || CallList.getInstance().getIncomingCall() != null) {
linyuhc3968e62017-11-20 17:40:50 -0800277 flags |= WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON;
278 }
279
280 getWindow().addFlags(flags);
281 }
282
283 private static int getAudioRoute() {
284 if (audioRouteForTesting.isPresent()) {
285 return audioRouteForTesting.get();
286 }
287
288 return AudioModeProvider.getInstance().getAudioState().getRoute();
289 }
290
291 @VisibleForTesting(otherwise = VisibleForTesting.NONE)
292 public static void setAudioRouteForTesting(int audioRoute) {
293 audioRouteForTesting = Optional.of(audioRoute);
294 }
295
296 private void internalResolveIntent(Intent intent) {
297 if (!intent.getAction().equals(Intent.ACTION_MAIN)) {
298 return;
299 }
300
301 if (intent.hasExtra(IntentExtraNames.SHOW_DIALPAD)) {
302 // IntentExtraNames.SHOW_DIALPAD can be used to specify whether the DTMF dialpad should be
303 // initially visible. If the extra is absent, leave the dialpad in its previous state.
304 boolean showDialpad = intent.getBooleanExtra(IntentExtraNames.SHOW_DIALPAD, false);
305 relaunchedFromDialer(showDialpad);
306 }
307
308 DialerCall outgoingCall = CallList.getInstance().getOutgoingCall();
309 if (outgoingCall == null) {
310 outgoingCall = CallList.getInstance().getPendingOutgoingCall();
311 }
312 if (intent.getBooleanExtra(IntentExtraNames.NEW_OUTGOING_CALL, false)) {
313 intent.removeExtra(IntentExtraNames.NEW_OUTGOING_CALL);
314
315 // InCallActivity is responsible for disconnecting a new outgoing call if there is no way of
316 // making it (i.e. no valid call capable accounts).
linyuh122fb0b2018-03-26 13:35:32 -0700317 if (InCallPresenter.isCallWithNoValidAccounts(outgoingCall)) {
linyuhc3968e62017-11-20 17:40:50 -0800318 LogUtil.i(
319 "InCallActivity.internalResolveIntent", "Call with no valid accounts, disconnecting");
320 outgoingCall.disconnect();
321 }
322
323 dismissKeyguard(true);
324 }
325
326 if (showPhoneAccountSelectionDialog()) {
327 hideMainInCallFragment();
328 }
329 }
330
331 /**
332 * When relaunching from the dialer app, {@code showDialpad} indicates whether the dialpad should
333 * be shown on launch.
334 *
335 * @param showDialpad {@code true} to indicate the dialpad should be shown on launch, and {@code
336 * false} to indicate no change should be made to the dialpad visibility.
337 */
338 private void relaunchedFromDialer(boolean showDialpad) {
339 showDialpadRequest = showDialpad ? DIALPAD_REQUEST_SHOW : DIALPAD_REQUEST_NONE;
340 animateDialpadOnShow = true;
341
342 if (showDialpadRequest == DIALPAD_REQUEST_SHOW) {
343 // If there's only one line in use, AND it's on hold, then we're sure the user
344 // wants to use the dialpad toward the exact line, so un-hold the holding line.
345 DialerCall call = CallList.getInstance().getActiveOrBackgroundCall();
346 if (call != null && call.getState() == State.ONHOLD) {
347 call.unhold();
348 }
349 }
350 }
351
352 /**
353 * Show a phone account selection dialog if there is a call waiting for phone account selection.
354 *
355 * @return true if the dialog was shown.
356 */
357 private boolean showPhoneAccountSelectionDialog() {
358 DialerCall waitingForAccountCall = CallList.getInstance().getWaitingForAccountCall();
359 if (waitingForAccountCall == null) {
360 return false;
361 }
362
twyen73a74c32018-03-07 12:12:24 -0800363 DialerExecutorComponent.get(this)
364 .dialerExecutorFactory()
365 .createNonUiTaskBuilder(new PreferredAccountWorker(waitingForAccountCall.getNumber()))
366 .onSuccess(
367 (result -> {
368 if (result.getPhoneAccountHandle().isPresent()) {
369 Logger.get(this).logImpression(Type.DUAL_SIM_SELECTION_PREFERRED_USED);
370 selectPhoneAccountListener.onPhoneAccountSelected(
371 result.getPhoneAccountHandle().get(), false, waitingForAccountCall.getId());
372 return;
373 }
374 if (result.getSuggestion().isPresent()) {
375 LogUtil.i(
376 "CallingAccountSelector.processPreferredAccount",
377 "SIM suggested: " + result.getSuggestion().get().reason);
378 if (result.getSuggestion().get().shouldAutoSelect) {
379 Logger.get(this).logImpression(Type.DUAL_SIM_SELECTION_SUGGESTION_AUTO_SELECTED);
380 LogUtil.i(
381 "CallingAccountSelector.processPreferredAccount", "Auto selected suggestion");
382 selectPhoneAccountListener.onPhoneAccountSelected(
383 result.getSuggestion().get().phoneAccountHandle,
384 false,
385 waitingForAccountCall.getId());
386 return;
387 }
388 }
389 Bundle extras = waitingForAccountCall.getIntentExtras();
390 List<PhoneAccountHandle> phoneAccountHandles =
391 extras == null
392 ? new ArrayList<>()
393 : extras.getParcelableArrayList(Call.AVAILABLE_PHONE_ACCOUNTS);
linyuhc3968e62017-11-20 17:40:50 -0800394
twyen73a74c32018-03-07 12:12:24 -0800395 waitingForAccountCall.setPreferredAccountRecorder(
396 new PreferredAccountRecorder(
397 waitingForAccountCall.getNumber(),
398 result.getSuggestion().orNull(),
399 result.getDataId().orNull()));
twyen66adad02018-04-24 13:51:08 -0700400 SelectPhoneAccountDialogOptions.Builder optionsBuilder =
401 SelectPhoneAccountDialogOptions.newBuilder()
402 .setTitle(R.string.select_phone_account_for_calls)
403 .setCanSetDefault(result.getDataId().isPresent())
404 .setSetDefaultLabel(R.string.select_phone_account_for_calls_remember)
405 .setCallId(waitingForAccountCall.getId());
406
407 for (PhoneAccountHandle phoneAccountHandle : phoneAccountHandles) {
408 SelectPhoneAccountDialogOptions.Entry.Builder entryBuilder =
409 SelectPhoneAccountDialogOptions.Entry.newBuilder();
410 SelectPhoneAccountDialogOptionsUtil.setPhoneAccountHandle(
411 entryBuilder, phoneAccountHandle);
412 Optional<String> hint =
413 SuggestionProvider.getHint(
414 this, phoneAccountHandle, result.getSuggestion().orNull());
415 if (hint.isPresent()) {
416 entryBuilder.setHint(hint.get());
417 }
418 optionsBuilder.addEntries(entryBuilder);
419 }
420
twyen73a74c32018-03-07 12:12:24 -0800421 selectPhoneAccountDialogFragment =
422 SelectPhoneAccountDialogFragment.newInstance(
twyen66adad02018-04-24 13:51:08 -0700423 optionsBuilder.build(), selectPhoneAccountListener);
twyen73a74c32018-03-07 12:12:24 -0800424 selectPhoneAccountDialogFragment.show(
425 getFragmentManager(), Tags.SELECT_ACCOUNT_FRAGMENT);
426 }))
427 .build()
428 .executeParallel(this);
429
linyuhc3968e62017-11-20 17:40:50 -0800430 return true;
431 }
432
Eric Erfanianccca3152017-02-22 16:32:36 -0800433 @Override
434 protected void onSaveInstanceState(Bundle out) {
linyuh57b093b2017-11-17 14:32:32 -0800435 LogUtil.enterBlock("InCallActivity.onSaveInstanceState");
436
437 // TODO: DialpadFragment should handle this as part of its own state
linyuhc3968e62017-11-20 17:40:50 -0800438 out.putBoolean(IntentExtraNames.SHOW_DIALPAD, isDialpadVisible());
linyuh57b093b2017-11-17 14:32:32 -0800439 DialpadFragment dialpadFragment = getDialpadFragment();
440 if (dialpadFragment != null) {
linyuhc3968e62017-11-20 17:40:50 -0800441 out.putString(KeysForSavedInstance.DIALPAD_TEXT, dialpadFragment.getDtmfText());
linyuh57b093b2017-11-17 14:32:32 -0800442 }
443
linyuhc3968e62017-11-20 17:40:50 -0800444 out.putBoolean(KeysForSavedInstance.DID_SHOW_ANSWER_SCREEN, didShowAnswerScreen);
445 out.putBoolean(KeysForSavedInstance.DID_SHOW_IN_CALL_SCREEN, didShowInCallScreen);
446 out.putBoolean(KeysForSavedInstance.DID_SHOW_VIDEO_CALL_SCREEN, didShowVideoCallScreen);
wangqi153af2f2018-02-15 16:21:49 -0800447 out.putBoolean(KeysForSavedInstance.DID_SHOW_RTT_CALL_SCREEN, didShowRttCallScreen);
erfaniand05d8992018-03-20 19:42:26 -0700448 out.putBoolean(KeysForSavedInstance.DID_SHOW_SPEAK_EASY_SCREEN, didShowSpeakEasyScreen);
linyuh57b093b2017-11-17 14:32:32 -0800449
Eric Erfanianccca3152017-02-22 16:32:36 -0800450 super.onSaveInstanceState(out);
451 isVisible = false;
452 }
453
454 @Override
455 protected void onStart() {
Eric Erfanian2ca43182017-08-31 06:57:16 -0700456 Trace.beginSection("InCallActivity.onStart");
Eric Erfanianccca3152017-02-22 16:32:36 -0800457 super.onStart();
linyuh57b093b2017-11-17 14:32:32 -0800458
Eric Erfanianccca3152017-02-22 16:32:36 -0800459 isVisible = true;
460 showMainInCallFragment();
linyuh57b093b2017-11-17 14:32:32 -0800461
462 InCallPresenter.getInstance().setActivity(this);
463 enableInCallOrientationEventListener(
464 getRequestedOrientation()
465 == InCallOrientationEventListener.ACTIVITY_PREFERENCE_ALLOW_ROTATION);
466 InCallPresenter.getInstance().onActivityStarted();
467
yueg10f6e822018-01-17 15:32:18 -0800468 if (!isRecreating) {
469 InCallPresenter.getInstance().onUiShowing(true);
470 }
471
linyuh437ae952018-03-26 12:46:18 -0700472 if (isInMultiWindowMode() && !getResources().getBoolean(R.bool.incall_dialpad_allowed)) {
Eric Erfanianccca3152017-02-22 16:32:36 -0800473 // Hide the dialpad because there may not be enough room
474 showDialpadFragment(false, false);
475 }
linyuh57b093b2017-11-17 14:32:32 -0800476
Eric Erfanian2ca43182017-08-31 06:57:16 -0700477 Trace.endSection();
Eric Erfanianccca3152017-02-22 16:32:36 -0800478 }
479
480 @Override
481 protected void onResume() {
Eric Erfanian2ca43182017-08-31 06:57:16 -0700482 Trace.beginSection("InCallActivity.onResume");
Eric Erfanianccca3152017-02-22 16:32:36 -0800483 super.onResume();
linyuhc3968e62017-11-20 17:40:50 -0800484
485 if (!InCallPresenter.getInstance().isReadyForTearDown()) {
486 updateTaskDescription();
linyuhc3968e62017-11-20 17:40:50 -0800487 }
488
489 // If there is a pending request to show or hide the dialpad, handle that now.
490 if (showDialpadRequest != DIALPAD_REQUEST_NONE) {
491 if (showDialpadRequest == DIALPAD_REQUEST_SHOW) {
492 // Exit fullscreen so that the user has access to the dialpad hide/show button.
493 // This is important when showing the dialpad from within dialer.
494 InCallPresenter.getInstance().setFullScreen(false /* isFullScreen */, true /* force */);
495
496 showDialpadFragment(true /* show */, animateDialpadOnShow /* animate */);
497 animateDialpadOnShow = false;
498
499 DialpadFragment dialpadFragment = getDialpadFragment();
500 if (dialpadFragment != null) {
501 dialpadFragment.setDtmfText(dtmfTextToPrepopulate);
502 dtmfTextToPrepopulate = null;
503 }
504 } else {
505 LogUtil.i("InCallActivity.onResume", "Force-hide the dialpad");
506 if (getDialpadFragment() != null) {
507 showDialpadFragment(false /* show */, false /* animate */);
508 }
509 }
510 showDialpadRequest = DIALPAD_REQUEST_NONE;
511 }
512 updateNavigationBar(isDialpadVisible());
513
514 if (showPostCharWaitDialogOnResume) {
515 showDialogForPostCharWait(showPostCharWaitDialogCallId, showPostCharWaitDialogChars);
516 }
517
518 CallList.getInstance()
519 .onInCallUiShown(getIntent().getBooleanExtra(IntentExtraNames.FOR_FULL_SCREEN, false));
520
Eric Erfanianccca3152017-02-22 16:32:36 -0800521 PseudoScreenState pseudoScreenState = InCallPresenter.getInstance().getPseudoScreenState();
522 pseudoScreenState.addListener(this);
523 onPseudoScreenStateChanged(pseudoScreenState.isOn());
Eric Erfanian2ca43182017-08-31 06:57:16 -0700524 Trace.endSection();
weijiaxu650e7cc2017-10-31 12:38:54 -0700525 // add 1 sec delay to get memory snapshot so that dialer wont react slowly on resume.
526 ThreadUtil.postDelayedOnUiThread(
weijiaxuc950a9b2017-11-06 16:39:04 -0800527 () ->
zachh7a96dc72018-02-20 22:16:03 -0800528 MetricsComponent.get(this)
529 .metrics()
530 .recordMemory(Metrics.INCALL_ACTIVITY_ON_RESUME_MEMORY_EVENT_NAME),
weijiaxu650e7cc2017-10-31 12:38:54 -0700531 1000);
Eric Erfanianccca3152017-02-22 16:32:36 -0800532 }
533
Eric Erfanianccca3152017-02-22 16:32:36 -0800534 @Override
535 protected void onPause() {
Eric Erfanian2ca43182017-08-31 06:57:16 -0700536 Trace.beginSection("InCallActivity.onPause");
Eric Erfanianccca3152017-02-22 16:32:36 -0800537 super.onPause();
linyuh57b093b2017-11-17 14:32:32 -0800538
539 DialpadFragment dialpadFragment = getDialpadFragment();
540 if (dialpadFragment != null) {
541 dialpadFragment.onDialerKeyUp(null);
542 }
543
Eric Erfanianccca3152017-02-22 16:32:36 -0800544 InCallPresenter.getInstance().getPseudoScreenState().removeListener(this);
Eric Erfanian2ca43182017-08-31 06:57:16 -0700545 Trace.endSection();
Eric Erfanianccca3152017-02-22 16:32:36 -0800546 }
547
548 @Override
549 protected void onStop() {
Eric Erfanian2ca43182017-08-31 06:57:16 -0700550 Trace.beginSection("InCallActivity.onStop");
wangqi4d705e52017-09-28 12:23:35 -0700551 isVisible = false;
Eric Erfanianccca3152017-02-22 16:32:36 -0800552 super.onStop();
linyuh57b093b2017-11-17 14:32:32 -0800553
554 // Disconnects the call waiting for a phone account when the activity is hidden (e.g., after the
555 // user presses the home button).
556 // Without this the pending call will get stuck on phone account selection and new calls can't
557 // be created.
558 // Skip this when the screen is locked since the activity may complete its current life cycle
559 // and restart.
linyuhc3968e62017-11-20 17:40:50 -0800560 if (!isRecreating && !getSystemService(KeyguardManager.class).isKeyguardLocked()) {
linyuh57b093b2017-11-17 14:32:32 -0800561 DialerCall waitingForAccountCall = CallList.getInstance().getWaitingForAccountCall();
562 if (waitingForAccountCall != null) {
563 waitingForAccountCall.disconnect();
564 }
565 }
566
567 enableInCallOrientationEventListener(false);
568 InCallPresenter.getInstance().updateIsChangingConfigurations();
569 InCallPresenter.getInstance().onActivityStopped();
linyuhc3968e62017-11-20 17:40:50 -0800570 if (!isRecreating) {
yueg10f6e822018-01-17 15:32:18 -0800571 InCallPresenter.getInstance().onUiShowing(false);
wangqie6060522018-04-05 11:47:15 -0700572 }
573 if (errorDialog != null) {
574 errorDialog.dismiss();
linyuh57b093b2017-11-17 14:32:32 -0800575 }
576
yueg10f6e822018-01-17 15:32:18 -0800577 if (isFinishing()) {
578 InCallPresenter.getInstance().unsetActivity(this);
579 }
580
Eric Erfanian2ca43182017-08-31 06:57:16 -0700581 Trace.endSection();
Eric Erfanianccca3152017-02-22 16:32:36 -0800582 }
583
584 @Override
585 protected void onDestroy() {
Eric Erfanian2ca43182017-08-31 06:57:16 -0700586 Trace.beginSection("InCallActivity.onDestroy");
Eric Erfanianccca3152017-02-22 16:32:36 -0800587 super.onDestroy();
linyuh57b093b2017-11-17 14:32:32 -0800588
589 InCallPresenter.getInstance().unsetActivity(this);
590 InCallPresenter.getInstance().updateIsChangingConfigurations();
Eric Erfanian2ca43182017-08-31 06:57:16 -0700591 Trace.endSection();
Eric Erfanianccca3152017-02-22 16:32:36 -0800592 }
593
594 @Override
595 public void finish() {
596 if (shouldCloseActivityOnFinish()) {
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700597 // When user select incall ui from recents after the call is disconnected, it tries to launch
598 // a new InCallActivity but InCallPresenter is already teared down at this point, which causes
599 // crash.
600 // By calling finishAndRemoveTask() instead of finish() the task associated with
601 // InCallActivity is cleared completely. So system won't try to create a new InCallActivity in
602 // this case.
603 //
604 // Calling finish won't clear the task and normally when an activity finishes it shouldn't
605 // clear the task since there could be parent activity in the same task that's still alive.
606 // But InCallActivity is special since it's singleInstance which means it's root activity and
607 // only instance of activity in the task. So it should be safe to also remove task when
608 // finishing.
609 // It's also necessary in the sense of it's excluded from recents. So whenever the activity
610 // finishes, the task should also be removed since it doesn't make sense to go back to it in
611 // anyway anymore.
612 super.finishAndRemoveTask();
Eric Erfanianccca3152017-02-22 16:32:36 -0800613 }
614 }
615
616 private boolean shouldCloseActivityOnFinish() {
linyuhc3968e62017-11-20 17:40:50 -0800617 if (!isVisible) {
Eric Erfanianccca3152017-02-22 16:32:36 -0800618 LogUtil.i(
619 "InCallActivity.shouldCloseActivityOnFinish",
620 "allowing activity to be closed because it's not visible");
621 return true;
622 }
623
twyen8efb4952017-10-06 16:35:54 -0700624 if (InCallPresenter.getInstance().isInCallUiLocked()) {
Eric Erfanianccca3152017-02-22 16:32:36 -0800625 LogUtil.i(
626 "InCallActivity.shouldCloseActivityOnFinish",
twyen8efb4952017-10-06 16:35:54 -0700627 "in call ui is locked, not closing activity");
Eric Erfanianccca3152017-02-22 16:32:36 -0800628 return false;
629 }
630
631 LogUtil.i(
632 "InCallActivity.shouldCloseActivityOnFinish",
twyen8efb4952017-10-06 16:35:54 -0700633 "activity is visible and has no locks, allowing activity to close");
Eric Erfanianccca3152017-02-22 16:32:36 -0800634 return true;
635 }
636
637 @Override
638 protected void onNewIntent(Intent intent) {
linyuhc3968e62017-11-20 17:40:50 -0800639 LogUtil.enterBlock("InCallActivity.onNewIntent");
Eric Erfanianccca3152017-02-22 16:32:36 -0800640
641 // If the screen is off, we need to make sure it gets turned on for incoming calls.
642 // This normally works just fine thanks to FLAG_TURN_SCREEN_ON but that only works
643 // when the activity is first created. Therefore, to ensure the screen is turned on
644 // for the call waiting case, we recreate() the current activity. There should be no jank from
645 // this since the screen is already off and will remain so until our new activity is up.
linyuhc3968e62017-11-20 17:40:50 -0800646 if (!isVisible) {
647 onNewIntent(intent, true /* isRecreating */);
Eric Erfanianccca3152017-02-22 16:32:36 -0800648 LogUtil.i("InCallActivity.onNewIntent", "Restarting InCallActivity to force screen on.");
649 recreate();
Eric Erfanian10b34a52017-05-04 08:23:17 -0700650 } else {
linyuhc3968e62017-11-20 17:40:50 -0800651 onNewIntent(intent, false /* isRecreating */);
652 }
653 }
654
yuega3305352018-01-09 11:02:47 -0800655 @VisibleForTesting
656 void onNewIntent(Intent intent, boolean isRecreating) {
linyuhc3968e62017-11-20 17:40:50 -0800657 this.isRecreating = isRecreating;
658
659 // We're being re-launched with a new Intent. Since it's possible for a single InCallActivity
660 // instance to persist indefinitely (even if we finish() ourselves), this sequence can
661 // happen any time the InCallActivity needs to be displayed.
662
663 // Stash away the new intent so that we can get it in the future by calling getIntent().
664 // Otherwise getIntent() will return the original Intent from when we first got created.
665 setIntent(intent);
666
667 // Activities are always paused before receiving a new intent, so we can count on our onResume()
668 // method being called next.
669
670 // Just like in onCreate(), handle the intent.
671 // Skip if InCallActivity is going to be recreated since this will be called in onCreate().
672 if (!isRecreating) {
673 internalResolveIntent(intent);
Eric Erfanianccca3152017-02-22 16:32:36 -0800674 }
675 }
676
677 @Override
678 public void onBackPressed() {
linyuh57b093b2017-11-17 14:32:32 -0800679 LogUtil.enterBlock("InCallActivity.onBackPressed");
680
linyuhc3968e62017-11-20 17:40:50 -0800681 if (!isVisible) {
linyuh57b093b2017-11-17 14:32:32 -0800682 return;
Eric Erfanianccca3152017-02-22 16:32:36 -0800683 }
linyuh57b093b2017-11-17 14:32:32 -0800684
685 if (!getCallCardFragmentVisible()) {
686 return;
687 }
688
689 DialpadFragment dialpadFragment = getDialpadFragment();
690 if (dialpadFragment != null && dialpadFragment.isVisible()) {
691 showDialpadFragment(false /* show */, true /* animate */);
692 return;
693 }
694
695 if (CallList.getInstance().getIncomingCall() != null) {
696 LogUtil.i(
697 "InCallActivity.onBackPressed",
698 "Ignore the press of the back key when an incoming call is ringing");
699 return;
700 }
701
702 // Nothing special to do. Fall back to the default behavior.
703 super.onBackPressed();
Eric Erfanianccca3152017-02-22 16:32:36 -0800704 }
705
706 @Override
707 public boolean onOptionsItemSelected(MenuItem item) {
708 LogUtil.i("InCallActivity.onOptionsItemSelected", "item: " + item);
709 if (item.getItemId() == android.R.id.home) {
710 onBackPressed();
711 return true;
712 }
713 return super.onOptionsItemSelected(item);
714 }
715
716 @Override
717 public boolean onKeyUp(int keyCode, KeyEvent event) {
linyuh57b093b2017-11-17 14:32:32 -0800718 DialpadFragment dialpadFragment = getDialpadFragment();
719 if (dialpadFragment != null
720 && dialpadFragment.isVisible()
721 && dialpadFragment.onDialerKeyUp(event)) {
722 return true;
723 }
724
725 if (keyCode == KeyEvent.KEYCODE_CALL) {
726 // Always consume KEYCODE_CALL to ensure the PhoneWindow won't do anything with it.
727 return true;
728 }
729
730 return super.onKeyUp(keyCode, event);
Eric Erfanianccca3152017-02-22 16:32:36 -0800731 }
732
733 @Override
734 public boolean onKeyDown(int keyCode, KeyEvent event) {
linyuh57b093b2017-11-17 14:32:32 -0800735 switch (keyCode) {
736 case KeyEvent.KEYCODE_CALL:
737 if (!InCallPresenter.getInstance().handleCallKey()) {
738 LogUtil.e(
739 "InCallActivity.onKeyDown",
740 "InCallPresenter should always handle KEYCODE_CALL in onKeyDown");
741 }
742 // Always consume KEYCODE_CALL to ensure the PhoneWindow won't do anything with it.
743 return true;
744
745 // Note that KEYCODE_ENDCALL isn't handled here as the standard system-wide handling of it
746 // is exactly what's needed, namely
747 // (1) "hang up" if there's an active call, or
748 // (2) "don't answer" if there's an incoming call.
749 // (See PhoneWindowManager for implementation details.)
750
751 case KeyEvent.KEYCODE_CAMERA:
752 // Consume KEYCODE_CAMERA since it's easy to accidentally press the camera button.
753 return true;
754
755 case KeyEvent.KEYCODE_VOLUME_UP:
756 case KeyEvent.KEYCODE_VOLUME_DOWN:
757 case KeyEvent.KEYCODE_VOLUME_MUTE:
758 // Ringer silencing handled by PhoneWindowManager.
759 break;
760
761 case KeyEvent.KEYCODE_MUTE:
762 TelecomAdapter.getInstance()
763 .mute(!AudioModeProvider.getInstance().getAudioState().isMuted());
764 return true;
765
766 case KeyEvent.KEYCODE_SLASH:
767 // When verbose logging is enabled, dump the view for debugging/testing purposes.
768 if (LogUtil.isVerboseEnabled()) {
769 View decorView = getWindow().getDecorView();
770 LogUtil.v("InCallActivity.onKeyDown", "View dump:\n%s", decorView);
771 return true;
772 }
773 break;
774
775 case KeyEvent.KEYCODE_EQUALS:
776 break;
777
778 default: // fall out
779 }
780
781 // Pass other key events to DialpadFragment's "onDialerKeyDown" method in case the user types
782 // in DTMF (Dual-tone multi-frequency signaling) code.
783 DialpadFragment dialpadFragment = getDialpadFragment();
784 if (dialpadFragment != null
785 && dialpadFragment.isVisible()
786 && dialpadFragment.onDialerKeyDown(event)) {
787 return true;
788 }
789
790 return super.onKeyDown(keyCode, event);
Eric Erfanianccca3152017-02-22 16:32:36 -0800791 }
792
793 public boolean isInCallScreenAnimating() {
794 return false;
795 }
796
797 public void showConferenceFragment(boolean show) {
798 if (show) {
799 startActivity(new Intent(this, ManageConferenceActivity.class));
800 }
801 }
802
linyuhc3968e62017-11-20 17:40:50 -0800803 public void showDialpadFragment(boolean show, boolean animate) {
804 if (show == isDialpadVisible()) {
805 return;
Eric Erfanianccca3152017-02-22 16:32:36 -0800806 }
linyuhc3968e62017-11-20 17:40:50 -0800807
808 FragmentManager dialpadFragmentManager = getDialpadFragmentManager();
809 if (dialpadFragmentManager == null) {
810 LogUtil.i("InCallActivity.showDialpadFragment", "Unable to obtain a FragmentManager");
811 return;
812 }
813
814 if (!animate) {
815 if (show) {
816 showDialpadFragment();
817 } else {
818 hideDialpadFragment();
819 }
820 } else {
821 if (show) {
822 showDialpadFragment();
823 getDialpadFragment().animateShowDialpad();
824 }
825 getDialpadFragment()
826 .getView()
827 .startAnimation(show ? dialpadSlideInAnimation : dialpadSlideOutAnimation);
828 }
829
830 ProximitySensor sensor = InCallPresenter.getInstance().getProximitySensor();
831 if (sensor != null) {
832 sensor.onDialpadVisible(show);
833 }
834 showDialpadRequest = DIALPAD_REQUEST_NONE;
835
836 // Note: onInCallScreenDialpadVisibilityChange is called here to ensure that the dialpad FAB
837 // repositions itself.
wangqifd4c9f72018-03-08 18:21:50 -0800838 getInCallOrRttCallScreen().onInCallScreenDialpadVisibilityChange(show);
linyuhc3968e62017-11-20 17:40:50 -0800839 }
840
841 private void showDialpadFragment() {
842 FragmentManager dialpadFragmentManager = getDialpadFragmentManager();
843 if (dialpadFragmentManager == null) {
844 return;
845 }
846
847 FragmentTransaction transaction = dialpadFragmentManager.beginTransaction();
848 DialpadFragment dialpadFragment = getDialpadFragment();
849 if (dialpadFragment == null) {
wangqifd4c9f72018-03-08 18:21:50 -0800850 dialpadFragment = new DialpadFragment();
851 transaction.add(getDialpadContainerId(), dialpadFragment, Tags.DIALPAD_FRAGMENT);
linyuhc3968e62017-11-20 17:40:50 -0800852 } else {
853 transaction.show(dialpadFragment);
calderwoodrad5883872017-12-12 15:29:12 -0800854 dialpadFragment.setUserVisibleHint(true);
linyuhc3968e62017-11-20 17:40:50 -0800855 }
wangqifd4c9f72018-03-08 18:21:50 -0800856 // RTT call screen doesn't show end call button inside dialpad, thus the space reserved for end
857 // call button should be removed.
858 dialpadFragment.setShouldShowEndCallSpace(didShowInCallScreen);
linyuhc3968e62017-11-20 17:40:50 -0800859 transaction.commitAllowingStateLoss();
860 dialpadFragmentManager.executePendingTransactions();
861
862 Logger.get(this).logScreenView(ScreenEvent.Type.INCALL_DIALPAD, this);
863 updateNavigationBar(true /* isDialpadVisible */);
864 }
865
866 private void hideDialpadFragment() {
867 FragmentManager dialpadFragmentManager = getDialpadFragmentManager();
868 if (dialpadFragmentManager == null) {
869 return;
870 }
871
calderwoodrad5883872017-12-12 15:29:12 -0800872 DialpadFragment dialpadFragment = getDialpadFragment();
linyuhc3968e62017-11-20 17:40:50 -0800873 if (dialpadFragment != null) {
874 FragmentTransaction transaction = dialpadFragmentManager.beginTransaction();
875 transaction.hide(dialpadFragment);
876 transaction.commitAllowingStateLoss();
877 dialpadFragmentManager.executePendingTransactions();
calderwoodrad5883872017-12-12 15:29:12 -0800878 dialpadFragment.setUserVisibleHint(false);
linyuhc3968e62017-11-20 17:40:50 -0800879 }
880 updateNavigationBar(false /* isDialpadVisible */);
Eric Erfanianccca3152017-02-22 16:32:36 -0800881 }
882
883 public boolean isDialpadVisible() {
linyuh69a25062017-11-15 16:18:51 -0800884 DialpadFragment dialpadFragment = getDialpadFragment();
calderwoodraa584bcd2018-01-24 12:19:56 -0800885 return dialpadFragment != null
886 && dialpadFragment.isAdded()
887 && !dialpadFragment.isHidden()
888 && dialpadFragment.getView() != null
889 && dialpadFragment.getUserVisibleHint();
linyuh69a25062017-11-15 16:18:51 -0800890 }
891
linyuhc3968e62017-11-20 17:40:50 -0800892 /** Returns the {@link DialpadFragment} that's shown by this activity, or {@code null} */
linyuh69a25062017-11-15 16:18:51 -0800893 @Nullable
linyuhc3968e62017-11-20 17:40:50 -0800894 private DialpadFragment getDialpadFragment() {
linyuh69a25062017-11-15 16:18:51 -0800895 FragmentManager fragmentManager = getDialpadFragmentManager();
896 if (fragmentManager == null) {
897 return null;
898 }
linyuhc3968e62017-11-20 17:40:50 -0800899 return (DialpadFragment) fragmentManager.findFragmentByTag(Tags.DIALPAD_FRAGMENT);
Eric Erfanianccca3152017-02-22 16:32:36 -0800900 }
901
902 public void onForegroundCallChanged(DialerCall newForegroundCall) {
linyuh57b093b2017-11-17 14:32:32 -0800903 updateTaskDescription();
904
905 if (newForegroundCall == null || !didShowAnswerScreen) {
Eric Erfanianccca3152017-02-22 16:32:36 -0800906 LogUtil.v("InCallActivity.onForegroundCallChanged", "resetting background color");
linyuh57b093b2017-11-17 14:32:32 -0800907 updateWindowBackgroundColor(0 /* progress */);
Eric Erfanianccca3152017-02-22 16:32:36 -0800908 }
909 }
910
linyuhc3968e62017-11-20 17:40:50 -0800911 private void updateTaskDescription() {
linyuh57b093b2017-11-17 14:32:32 -0800912 int color =
913 getResources().getBoolean(R.bool.is_layout_landscape)
914 ? ResourcesCompat.getColor(
915 getResources(), R.color.statusbar_background_color, getTheme())
916 : InCallPresenter.getInstance().getThemeColorManager().getSecondaryColor();
917 setTaskDescription(
918 new TaskDescription(
919 getResources().getString(R.string.notification_ongoing_call), null /* icon */, color));
920 }
921
Eric Erfanianccca3152017-02-22 16:32:36 -0800922 public void updateWindowBackgroundColor(@FloatRange(from = -1f, to = 1.0f) float progress) {
923 ThemeColorManager themeColorManager = InCallPresenter.getInstance().getThemeColorManager();
924 @ColorInt int top;
925 @ColorInt int middle;
926 @ColorInt int bottom;
927 @ColorInt int gray = 0x66000000;
928
linyuh437ae952018-03-26 12:46:18 -0700929 if (isInMultiWindowMode()) {
Eric Erfanianccca3152017-02-22 16:32:36 -0800930 top = themeColorManager.getBackgroundColorSolid();
931 middle = themeColorManager.getBackgroundColorSolid();
932 bottom = themeColorManager.getBackgroundColorSolid();
933 } else {
934 top = themeColorManager.getBackgroundColorTop();
935 middle = themeColorManager.getBackgroundColorMiddle();
936 bottom = themeColorManager.getBackgroundColorBottom();
937 }
938
939 if (progress < 0) {
940 float correctedProgress = Math.abs(progress);
941 top = ColorUtils.blendARGB(top, gray, correctedProgress);
942 middle = ColorUtils.blendARGB(middle, gray, correctedProgress);
943 bottom = ColorUtils.blendARGB(bottom, gray, correctedProgress);
944 }
945
946 boolean backgroundDirty = false;
947 if (backgroundDrawable == null) {
948 backgroundDrawableColors = new int[] {top, middle, bottom};
949 backgroundDrawable = new GradientDrawable(Orientation.TOP_BOTTOM, backgroundDrawableColors);
950 backgroundDirty = true;
951 } else {
952 if (backgroundDrawableColors[0] != top) {
953 backgroundDrawableColors[0] = top;
954 backgroundDirty = true;
955 }
956 if (backgroundDrawableColors[1] != middle) {
957 backgroundDrawableColors[1] = middle;
958 backgroundDirty = true;
959 }
960 if (backgroundDrawableColors[2] != bottom) {
961 backgroundDrawableColors[2] = bottom;
962 backgroundDirty = true;
963 }
964 if (backgroundDirty) {
965 backgroundDrawable.setColors(backgroundDrawableColors);
966 }
967 }
968
969 if (backgroundDirty) {
970 getWindow().setBackgroundDrawable(backgroundDrawable);
971 }
972 }
973
974 public boolean isVisible() {
975 return isVisible;
976 }
977
978 public boolean getCallCardFragmentVisible() {
erfaniand05d8992018-03-20 19:42:26 -0700979 return didShowInCallScreen
980 || didShowVideoCallScreen
981 || didShowRttCallScreen
982 || didShowSpeakEasyScreen;
Eric Erfanianccca3152017-02-22 16:32:36 -0800983 }
984
985 public void dismissKeyguard(boolean dismiss) {
linyuh9c327da2017-11-14 12:33:48 -0800986 if (dismissKeyguard == dismiss) {
987 return;
988 }
989
990 dismissKeyguard = dismiss;
991 if (dismiss) {
992 getWindow().addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);
993 } else {
994 getWindow().clearFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);
995 }
Eric Erfanianccca3152017-02-22 16:32:36 -0800996 }
997
linyuhc3968e62017-11-20 17:40:50 -0800998 public void showDialogForPostCharWait(String callId, String chars) {
999 if (isVisible) {
1000 PostCharDialogFragment fragment = new PostCharDialogFragment(callId, chars);
1001 fragment.show(getSupportFragmentManager(), Tags.POST_CHAR_DIALOG_FRAGMENT);
1002
1003 showPostCharWaitDialogOnResume = false;
1004 showPostCharWaitDialogCallId = null;
1005 showPostCharWaitDialogChars = null;
1006 } else {
1007 showPostCharWaitDialogOnResume = true;
1008 showPostCharWaitDialogCallId = callId;
1009 showPostCharWaitDialogChars = chars;
1010 }
Eric Erfanianccca3152017-02-22 16:32:36 -08001011 }
1012
linyuh7b86f562017-11-16 11:24:09 -08001013 public void showDialogOrToastForDisconnectedCall(DisconnectMessage disconnectMessage) {
1014 LogUtil.i(
1015 "InCallActivity.showDialogOrToastForDisconnectedCall",
1016 "disconnect cause: %s",
1017 disconnectMessage);
1018
1019 if (disconnectMessage.dialog == null || isFinishing()) {
1020 return;
1021 }
1022
1023 dismissPendingDialogs();
1024
1025 // Show a toast if the app is in background when a dialog can't be visible.
1026 if (!isVisible()) {
1027 Toast.makeText(getApplicationContext(), disconnectMessage.toastMessage, Toast.LENGTH_LONG)
1028 .show();
1029 return;
1030 }
1031
1032 // Show the dialog.
linyuhc3968e62017-11-20 17:40:50 -08001033 errorDialog = disconnectMessage.dialog;
linyuh7b86f562017-11-16 11:24:09 -08001034 InCallUiLock lock = InCallPresenter.getInstance().acquireInCallUiLock("showErrorDialog");
1035 disconnectMessage.dialog.setOnDismissListener(
1036 dialogInterface -> {
1037 lock.release();
1038 onDialogDismissed();
1039 });
1040 disconnectMessage.dialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
1041 disconnectMessage.dialog.show();
1042 }
1043
1044 private void onDialogDismissed() {
linyuhc3968e62017-11-20 17:40:50 -08001045 errorDialog = null;
linyuh7b86f562017-11-16 11:24:09 -08001046 CallList.getInstance().onErrorDialogDismissed();
Eric Erfanianccca3152017-02-22 16:32:36 -08001047 }
1048
1049 public void dismissPendingDialogs() {
linyuhc3968e62017-11-20 17:40:50 -08001050 LogUtil.enterBlock("InCallActivity.dismissPendingDialogs");
linyuhf99f6302017-11-15 11:23:51 -08001051
1052 if (!isVisible) {
1053 // Defer the dismissing action as the activity is not visible and onSaveInstanceState may have
1054 // been called.
Eric Erfanianccca3152017-02-22 16:32:36 -08001055 LogUtil.i(
1056 "InCallActivity.dismissPendingDialogs", "defer actions since activity is not visible");
1057 needDismissPendingDialogs = true;
linyuhf99f6302017-11-15 11:23:51 -08001058 return;
Eric Erfanianccca3152017-02-22 16:32:36 -08001059 }
linyuhf99f6302017-11-15 11:23:51 -08001060
1061 // Dismiss the error dialog
linyuhf99f6302017-11-15 11:23:51 -08001062 if (errorDialog != null) {
1063 errorDialog.dismiss();
linyuhc3968e62017-11-20 17:40:50 -08001064 errorDialog = null;
linyuhf99f6302017-11-15 11:23:51 -08001065 }
1066
1067 // Dismiss the phone account selection dialog
linyuhf99f6302017-11-15 11:23:51 -08001068 if (selectPhoneAccountDialogFragment != null) {
1069 selectPhoneAccountDialogFragment.dismiss();
linyuhc3968e62017-11-20 17:40:50 -08001070 selectPhoneAccountDialogFragment = null;
linyuhf99f6302017-11-15 11:23:51 -08001071 }
1072
1073 // Dismiss the dialog for international call on WiFi
1074 InternationalCallOnWifiDialogFragment internationalCallOnWifiFragment =
1075 (InternationalCallOnWifiDialogFragment)
linyuhc3968e62017-11-20 17:40:50 -08001076 getSupportFragmentManager().findFragmentByTag(Tags.INTERNATIONAL_CALL_ON_WIFI);
linyuhf99f6302017-11-15 11:23:51 -08001077 if (internationalCallOnWifiFragment != null) {
1078 internationalCallOnWifiFragment.dismiss();
1079 }
1080
1081 // Dismiss the answer screen
1082 AnswerScreen answerScreen = getAnswerScreen();
1083 if (answerScreen != null) {
1084 answerScreen.dismissPendingDialogs();
1085 }
1086
1087 needDismissPendingDialogs = false;
Eric Erfanianccca3152017-02-22 16:32:36 -08001088 }
1089
linyuhc3968e62017-11-20 17:40:50 -08001090 private void enableInCallOrientationEventListener(boolean enable) {
linyuh69a25062017-11-15 16:18:51 -08001091 if (enable) {
1092 inCallOrientationEventListener.enable(true /* notifyDeviceOrientationChange */);
1093 } else {
1094 inCallOrientationEventListener.disable();
1095 }
Eric Erfanianccca3152017-02-22 16:32:36 -08001096 }
1097
1098 public void setExcludeFromRecents(boolean exclude) {
linyuhc3968e62017-11-20 17:40:50 -08001099 int taskId = getTaskId();
1100
1101 List<AppTask> tasks = getSystemService(ActivityManager.class).getAppTasks();
1102 for (AppTask task : tasks) {
1103 try {
1104 if (task.getTaskInfo().id == taskId) {
1105 task.setExcludeFromRecents(exclude);
1106 }
1107 } catch (RuntimeException e) {
1108 LogUtil.e("InCallActivity.setExcludeFromRecents", "RuntimeException:\n%s", e);
1109 }
1110 }
Eric Erfanianccca3152017-02-22 16:32:36 -08001111 }
1112
Eric Erfanianccca3152017-02-22 16:32:36 -08001113 @Nullable
1114 public FragmentManager getDialpadFragmentManager() {
wangqifd4c9f72018-03-08 18:21:50 -08001115 InCallScreen inCallScreen = getInCallOrRttCallScreen();
Eric Erfanianccca3152017-02-22 16:32:36 -08001116 if (inCallScreen != null) {
1117 return inCallScreen.getInCallScreenFragment().getChildFragmentManager();
1118 }
1119 return null;
1120 }
1121
1122 public int getDialpadContainerId() {
wangqifd4c9f72018-03-08 18:21:50 -08001123 return getInCallOrRttCallScreen().getAnswerAndDialpadContainerResourceId();
Eric Erfanianccca3152017-02-22 16:32:36 -08001124 }
1125
1126 @Override
1127 public AnswerScreenDelegate newAnswerScreenDelegate(AnswerScreen answerScreen) {
1128 DialerCall call = CallList.getInstance().getCallById(answerScreen.getCallId());
1129 if (call == null) {
1130 // This is a work around for a bug where we attempt to create a new delegate after the call
1131 // has already been removed. An example of when this can happen is:
1132 // 1. incoming video call in landscape mode
1133 // 2. remote party hangs up
1134 // 3. activity switches from landscape to portrait
1135 // At step #3 the answer fragment will try to create a new answer delegate but the call won't
1136 // exist. In this case we'll simply return a stub delegate that does nothing. This is ok
1137 // because this new state is transient and the activity will be destroyed soon.
1138 LogUtil.i("InCallActivity.onPrimaryCallStateChanged", "call doesn't exist, using stub");
1139 return new AnswerScreenPresenterStub();
1140 } else {
1141 return new AnswerScreenPresenter(
1142 this, answerScreen, CallList.getInstance().getCallById(answerScreen.getCallId()));
1143 }
1144 }
1145
1146 @Override
1147 public InCallScreenDelegate newInCallScreenDelegate() {
1148 return new CallCardPresenter(this);
1149 }
1150
1151 @Override
1152 public InCallButtonUiDelegate newInCallButtonUiDelegate() {
1153 return new CallButtonPresenter(this);
1154 }
1155
1156 @Override
Eric Erfanian90508232017-03-24 09:31:16 -07001157 public VideoCallScreenDelegate newVideoCallScreenDelegate(VideoCallScreen videoCallScreen) {
1158 DialerCall dialerCall = CallList.getInstance().getCallById(videoCallScreen.getCallId());
1159 if (dialerCall != null && dialerCall.getVideoTech().shouldUseSurfaceView()) {
1160 return dialerCall.getVideoTech().createVideoCallScreenDelegate(this, videoCallScreen);
1161 }
Eric Erfanianccca3152017-02-22 16:32:36 -08001162 return new VideoCallPresenter();
1163 }
1164
1165 public void onPrimaryCallStateChanged() {
Eric Erfanian2ca43182017-08-31 06:57:16 -07001166 Trace.beginSection("InCallActivity.onPrimaryCallStateChanged");
Eric Erfanianccca3152017-02-22 16:32:36 -08001167 showMainInCallFragment();
Eric Erfanian2ca43182017-08-31 06:57:16 -07001168 Trace.endSection();
Eric Erfanianccca3152017-02-22 16:32:36 -08001169 }
1170
linyuh7b86f562017-11-16 11:24:09 -08001171 public void showDialogOrToastForWifiHandoverFailure(DialerCall call) {
1172 if (call.showWifiHandoverAlertAsToast()) {
1173 Toast.makeText(this, R.string.video_call_lte_to_wifi_failed_message, Toast.LENGTH_SHORT)
1174 .show();
1175 return;
1176 }
1177
1178 dismissPendingDialogs();
1179
1180 AlertDialog.Builder builder =
1181 new AlertDialog.Builder(this).setTitle(R.string.video_call_lte_to_wifi_failed_title);
1182
1183 // This allows us to use the theme of the dialog instead of the activity
1184 View dialogCheckBoxView =
1185 View.inflate(builder.getContext(), R.layout.video_call_lte_to_wifi_failed, null /* root */);
1186 CheckBox wifiHandoverFailureCheckbox =
1187 (CheckBox) dialogCheckBoxView.findViewById(R.id.video_call_lte_to_wifi_failed_checkbox);
1188 wifiHandoverFailureCheckbox.setChecked(false);
1189
1190 InCallUiLock lock = InCallPresenter.getInstance().acquireInCallUiLock("WifiFailedDialog");
linyuhc3968e62017-11-20 17:40:50 -08001191 errorDialog =
linyuh7b86f562017-11-16 11:24:09 -08001192 builder
1193 .setView(dialogCheckBoxView)
1194 .setMessage(R.string.video_call_lte_to_wifi_failed_message)
1195 .setOnCancelListener(dialogInterface -> onDialogDismissed())
1196 .setPositiveButton(
1197 android.R.string.ok,
1198 (dialogInterface, id) -> {
1199 call.setDoNotShowDialogForHandoffToWifiFailure(
1200 wifiHandoverFailureCheckbox.isChecked());
1201 dialogInterface.cancel();
1202 onDialogDismissed();
1203 })
1204 .setOnDismissListener(dialogInterface -> lock.release())
1205 .create();
linyuh7b86f562017-11-16 11:24:09 -08001206 errorDialog.show();
Eric Erfanianccca3152017-02-22 16:32:36 -08001207 }
1208
linyuh7b86f562017-11-16 11:24:09 -08001209 public void showDialogForInternationalCallOnWifi(@NonNull DialerCall call) {
linyuh7b86f562017-11-16 11:24:09 -08001210 InternationalCallOnWifiDialogFragment fragment =
yuegb47528e2018-04-24 12:12:57 -07001211 InternationalCallOnWifiDialogFragment.newInstance(call.getId());
linyuhc3968e62017-11-20 17:40:50 -08001212 fragment.show(getSupportFragmentManager(), Tags.INTERNATIONAL_CALL_ON_WIFI);
Eric Erfanianc857f902017-05-15 14:05:33 -07001213 }
1214
wangqibc28ea72018-04-02 16:23:00 -07001215 public void showDialogForRttRequest(DialerCall call, int rttRequestId) {
1216 LogUtil.enterBlock("InCallActivity.showDialogForRttRequest");
1217 DialogFragment fragment = RttRequestDialogFragment.newInstance(call.getId(), rttRequestId);
1218 fragment.show(getSupportFragmentManager(), Tags.RTT_REQUEST_DIALOG);
1219 }
1220
Eric Erfanian938468d2017-10-24 14:05:52 -07001221 @Override
1222 public void onMultiWindowModeChanged(boolean isInMultiWindowMode) {
1223 super.onMultiWindowModeChanged(isInMultiWindowMode);
linyuh57b093b2017-11-17 14:32:32 -08001224 updateNavigationBar(isDialpadVisible());
1225 }
1226
linyuhc3968e62017-11-20 17:40:50 -08001227 private void updateNavigationBar(boolean isDialpadVisible) {
linyuh437ae952018-03-26 12:46:18 -07001228 if (isInMultiWindowMode()) {
linyuh57b093b2017-11-17 14:32:32 -08001229 return;
1230 }
1231
1232 View navigationBarBackground = getWindow().findViewById(R.id.navigation_bar_background);
1233 if (navigationBarBackground != null) {
1234 navigationBarBackground.setVisibility(isDialpadVisible ? View.VISIBLE : View.GONE);
Eric Erfanian938468d2017-10-24 14:05:52 -07001235 }
1236 }
1237
Eric Erfanianccca3152017-02-22 16:32:36 -08001238 public void setAllowOrientationChange(boolean allowOrientationChange) {
wangqi9982f0d2017-10-11 17:46:07 -07001239 if (this.allowOrientationChange == allowOrientationChange) {
1240 return;
1241 }
1242 this.allowOrientationChange = allowOrientationChange;
Eric Erfanianccca3152017-02-22 16:32:36 -08001243 if (!allowOrientationChange) {
1244 setRequestedOrientation(InCallOrientationEventListener.ACTIVITY_PREFERENCE_DISALLOW_ROTATION);
1245 } else {
1246 setRequestedOrientation(InCallOrientationEventListener.ACTIVITY_PREFERENCE_ALLOW_ROTATION);
1247 }
1248 enableInCallOrientationEventListener(allowOrientationChange);
1249 }
1250
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001251 public void hideMainInCallFragment() {
linyuhc3968e62017-11-20 17:40:50 -08001252 LogUtil.enterBlock("InCallActivity.hideMainInCallFragment");
1253 if (getCallCardFragmentVisible()) {
Eric Erfanianccca3152017-02-22 16:32:36 -08001254 FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
1255 hideInCallScreenFragment(transaction);
1256 hideVideoCallScreenFragment(transaction);
1257 transaction.commitAllowingStateLoss();
1258 getSupportFragmentManager().executePendingTransactions();
1259 }
1260 }
1261
1262 private void showMainInCallFragment() {
Eric Erfanian2ca43182017-08-31 06:57:16 -07001263 Trace.beginSection("InCallActivity.showMainInCallFragment");
Eric Erfanianccca3152017-02-22 16:32:36 -08001264 // If the activity's onStart method hasn't been called yet then defer doing any work.
1265 if (!isVisible) {
1266 LogUtil.i("InCallActivity.showMainInCallFragment", "not visible yet/anymore");
Eric Erfanian2ca43182017-08-31 06:57:16 -07001267 Trace.endSection();
Eric Erfanianccca3152017-02-22 16:32:36 -08001268 return;
1269 }
1270
1271 // Don't let this be reentrant.
1272 if (isInShowMainInCallFragment) {
1273 LogUtil.i("InCallActivity.showMainInCallFragment", "already in method, bailing");
Eric Erfanian2ca43182017-08-31 06:57:16 -07001274 Trace.endSection();
Eric Erfanianccca3152017-02-22 16:32:36 -08001275 return;
1276 }
1277
1278 isInShowMainInCallFragment = true;
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001279 ShouldShowUiResult shouldShowAnswerUi = getShouldShowAnswerUi();
1280 ShouldShowUiResult shouldShowVideoUi = getShouldShowVideoUi();
wangqi219b8702018-02-13 09:34:41 -08001281 ShouldShowUiResult shouldShowRttUi = getShouldShowRttUi();
erfaniand05d8992018-03-20 19:42:26 -07001282 ShouldShowUiResult shouldShowSpeakEasyUi = getShouldShowSpeakEasyUi();
Eric Erfanianccca3152017-02-22 16:32:36 -08001283 LogUtil.i(
1284 "InCallActivity.showMainInCallFragment",
wangqi219b8702018-02-13 09:34:41 -08001285 "shouldShowAnswerUi: %b, shouldShowRttUi: %b, shouldShowVideoUi: %b "
1286 + "didShowAnswerScreen: %b, didShowInCallScreen: %b, didShowRttCallScreen: %b, "
erfaniand05d8992018-03-20 19:42:26 -07001287 + "didShowVideoCallScreen: %b"
1288 + "didShowSpeakEasyScreen: %b",
Eric Erfanianccca3152017-02-22 16:32:36 -08001289 shouldShowAnswerUi.shouldShow,
wangqi219b8702018-02-13 09:34:41 -08001290 shouldShowRttUi.shouldShow,
Eric Erfanian10b34a52017-05-04 08:23:17 -07001291 shouldShowVideoUi.shouldShow,
Eric Erfanianccca3152017-02-22 16:32:36 -08001292 didShowAnswerScreen,
1293 didShowInCallScreen,
wangqi219b8702018-02-13 09:34:41 -08001294 didShowRttCallScreen,
erfaniand05d8992018-03-20 19:42:26 -07001295 didShowVideoCallScreen,
1296 didShowSpeakEasyScreen);
Eric Erfanianccca3152017-02-22 16:32:36 -08001297 // Only video call ui allows orientation change.
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001298 setAllowOrientationChange(shouldShowVideoUi.shouldShow);
Eric Erfanianccca3152017-02-22 16:32:36 -08001299
1300 FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
wangqi219b8702018-02-13 09:34:41 -08001301 boolean didChange;
Eric Erfanianccca3152017-02-22 16:32:36 -08001302 if (shouldShowAnswerUi.shouldShow) {
wangqi219b8702018-02-13 09:34:41 -08001303 didChange = hideInCallScreenFragment(transaction);
1304 didChange |= hideVideoCallScreenFragment(transaction);
1305 didChange |= hideRttCallScreenFragment(transaction);
erfaniand05d8992018-03-20 19:42:26 -07001306 didChange |= hideSpeakEasyFragment(transaction);
wangqi219b8702018-02-13 09:34:41 -08001307 didChange |= showAnswerScreenFragment(transaction, shouldShowAnswerUi.call);
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001308 } else if (shouldShowVideoUi.shouldShow) {
wangqi219b8702018-02-13 09:34:41 -08001309 didChange = hideInCallScreenFragment(transaction);
1310 didChange |= showVideoCallScreenFragment(transaction, shouldShowVideoUi.call);
1311 didChange |= hideRttCallScreenFragment(transaction);
erfaniand05d8992018-03-20 19:42:26 -07001312 didChange |= hideSpeakEasyFragment(transaction);
wangqi219b8702018-02-13 09:34:41 -08001313 didChange |= hideAnswerScreenFragment(transaction);
1314 } else if (shouldShowRttUi.shouldShow) {
1315 didChange = hideInCallScreenFragment(transaction);
1316 didChange |= hideVideoCallScreenFragment(transaction);
1317 didChange |= hideAnswerScreenFragment(transaction);
erfaniand05d8992018-03-20 19:42:26 -07001318 didChange |= hideSpeakEasyFragment(transaction);
wangqi219b8702018-02-13 09:34:41 -08001319 didChange |= showRttCallScreenFragment(transaction, shouldShowRttUi.call);
erfaniand05d8992018-03-20 19:42:26 -07001320 } else if (shouldShowSpeakEasyUi.shouldShow) {
1321 didChange = hideInCallScreenFragment(transaction);
1322 didChange |= hideVideoCallScreenFragment(transaction);
1323 didChange |= hideAnswerScreenFragment(transaction);
1324 didChange |= hideRttCallScreenFragment(transaction);
1325 didChange |= showSpeakEasyFragment(transaction, shouldShowSpeakEasyUi.call);
Eric Erfanianccca3152017-02-22 16:32:36 -08001326 } else {
wangqi219b8702018-02-13 09:34:41 -08001327 didChange = showInCallScreenFragment(transaction);
1328 didChange |= hideVideoCallScreenFragment(transaction);
1329 didChange |= hideRttCallScreenFragment(transaction);
erfaniand05d8992018-03-20 19:42:26 -07001330 didChange |= hideSpeakEasyFragment(transaction);
wangqi219b8702018-02-13 09:34:41 -08001331 didChange |= hideAnswerScreenFragment(transaction);
Eric Erfanianccca3152017-02-22 16:32:36 -08001332 }
1333
wangqi219b8702018-02-13 09:34:41 -08001334 if (didChange) {
Eric Erfanian2ca43182017-08-31 06:57:16 -07001335 Trace.beginSection("InCallActivity.commitTransaction");
Eric Erfanianccca3152017-02-22 16:32:36 -08001336 transaction.commitNow();
Eric Erfanian2ca43182017-08-31 06:57:16 -07001337 Trace.endSection();
Eric Erfanianccca3152017-02-22 16:32:36 -08001338 Logger.get(this).logScreenView(ScreenEvent.Type.INCALL, this);
1339 }
1340 isInShowMainInCallFragment = false;
Eric Erfanian2ca43182017-08-31 06:57:16 -07001341 Trace.endSection();
Eric Erfanianccca3152017-02-22 16:32:36 -08001342 }
1343
erfaniand05d8992018-03-20 19:42:26 -07001344 private boolean showSpeakEasyFragment(FragmentTransaction transaction, DialerCall call) {
1345
erfaniand05d8992018-03-20 19:42:26 -07001346 if (didShowSpeakEasyScreen) {
erfanian612d13a2018-04-04 15:27:57 -07001347 if (lastShownSpeakEasyScreenUniqueCallid.equals(call.getUniqueCallId())) {
erfanian12243de2018-04-17 12:17:08 -07001348 LogUtil.i("InCallActivity.showSpeakEasyFragment", "found existing fragment");
erfanian612d13a2018-04-04 15:27:57 -07001349 return false;
1350 }
1351 hideSpeakEasyFragment(transaction);
erfanian12243de2018-04-17 12:17:08 -07001352 LogUtil.i("InCallActivity.showSpeakEasyFragment", "hid existing fragment");
erfaniand05d8992018-03-20 19:42:26 -07001353 }
1354
1355 Optional<Fragment> speakEasyFragment = speakEasyCallManager.getSpeakEasyFragment(call);
1356 if (speakEasyFragment.isPresent()) {
1357 transaction.add(R.id.main, speakEasyFragment.get(), Tags.SPEAK_EASY_SCREEN);
1358 didShowSpeakEasyScreen = true;
erfanian612d13a2018-04-04 15:27:57 -07001359 lastShownSpeakEasyScreenUniqueCallid = call.getUniqueCallId();
erfanian12243de2018-04-17 12:17:08 -07001360 LogUtil.i(
1361 "InCallActivity.showSpeakEasyFragment",
1362 "set fragment for call %s",
1363 lastShownSpeakEasyScreenUniqueCallid);
erfaniand05d8992018-03-20 19:42:26 -07001364 return true;
1365 }
1366 return false;
1367 }
1368
1369 private Fragment getSpeakEasyScreen() {
1370 return getSupportFragmentManager().findFragmentByTag(Tags.SPEAK_EASY_SCREEN);
1371 }
1372
1373 private boolean hideSpeakEasyFragment(FragmentTransaction transaction) {
1374 if (!didShowSpeakEasyScreen) {
1375 return false;
1376 }
1377
1378 Fragment speakEasyFragment = getSpeakEasyScreen();
1379
1380 if (speakEasyFragment != null) {
1381 transaction.remove(speakEasyFragment);
1382 didShowSpeakEasyScreen = false;
1383 return true;
1384 }
1385 return false;
1386 }
1387
erfanian12243de2018-04-17 12:17:08 -07001388 @VisibleForTesting
erfaniand05d8992018-03-20 19:42:26 -07001389 public void setSpeakEasyCallManager(SpeakEasyCallManager speakEasyCallManager) {
erfanian87dbb622018-04-04 15:43:00 -07001390 this.speakEasyCallManager = speakEasyCallManager;
erfaniand05d8992018-03-20 19:42:26 -07001391 }
1392
erfanian12243de2018-04-17 12:17:08 -07001393 @Nullable
erfaniand05d8992018-03-20 19:42:26 -07001394 public SpeakEasyCallManager getSpeakEasyCallManager() {
erfanian12243de2018-04-17 12:17:08 -07001395 if (this.speakEasyCallManager == null) {
1396 this.speakEasyCallManager = InCallPresenter.getInstance().getSpeakEasyCallManager();
1397 }
erfaniand05d8992018-03-20 19:42:26 -07001398 return speakEasyCallManager;
1399 }
1400
1401 private ShouldShowUiResult getShouldShowSpeakEasyUi() {
1402 SpeakEasyCallManager speakEasyCallManager = getSpeakEasyCallManager();
1403
1404 if (speakEasyCallManager == null) {
1405 return new ShouldShowUiResult(false, null);
1406 }
1407
erfanian3bb7cb62018-04-11 09:01:15 -07001408 DialerCall call =
1409 CallList.getInstance().getIncomingCall() != null
1410 ? CallList.getInstance().getIncomingCall()
1411 : CallList.getInstance().getActiveCall();
erfaniand05d8992018-03-20 19:42:26 -07001412
1413 if (call == null) {
1414 return new ShouldShowUiResult(false, call);
1415 }
1416
1417 if (!call.isSpeakEasyCall() || !call.isSpeakEasyEligible()) {
1418 return new ShouldShowUiResult(false, call);
1419 }
1420
1421 Optional<Fragment> speakEasyFragment = speakEasyCallManager.getSpeakEasyFragment(call);
1422
1423 if (!speakEasyFragment.isPresent()) {
1424 return new ShouldShowUiResult(false, call);
1425 }
1426 return new ShouldShowUiResult(true, call);
1427 }
1428
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001429 private ShouldShowUiResult getShouldShowAnswerUi() {
Eric Erfanianccca3152017-02-22 16:32:36 -08001430 DialerCall call = CallList.getInstance().getIncomingCall();
erfanian3bb7cb62018-04-11 09:01:15 -07001431 if (call != null && !call.isSpeakEasyCall()) {
Eric Erfanianccca3152017-02-22 16:32:36 -08001432 LogUtil.i("InCallActivity.getShouldShowAnswerUi", "found incoming call");
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001433 return new ShouldShowUiResult(true, call);
Eric Erfanianccca3152017-02-22 16:32:36 -08001434 }
1435
1436 call = CallList.getInstance().getVideoUpgradeRequestCall();
1437 if (call != null) {
1438 LogUtil.i("InCallActivity.getShouldShowAnswerUi", "found video upgrade request");
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001439 return new ShouldShowUiResult(true, call);
Eric Erfanianccca3152017-02-22 16:32:36 -08001440 }
1441
1442 // Check if we're showing the answer screen and the call is disconnected. If this condition is
1443 // true then we won't switch from the answer UI to the in call UI. This prevents flicker when
1444 // the user rejects an incoming call.
1445 call = CallList.getInstance().getFirstCall();
1446 if (call == null) {
1447 call = CallList.getInstance().getBackgroundCall();
1448 }
1449 if (didShowAnswerScreen && (call == null || call.getState() == State.DISCONNECTED)) {
1450 LogUtil.i("InCallActivity.getShouldShowAnswerUi", "found disconnecting incoming call");
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001451 return new ShouldShowUiResult(true, call);
Eric Erfanianccca3152017-02-22 16:32:36 -08001452 }
1453
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001454 return new ShouldShowUiResult(false, null);
Eric Erfanianccca3152017-02-22 16:32:36 -08001455 }
1456
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001457 private static ShouldShowUiResult getShouldShowVideoUi() {
Eric Erfanianccca3152017-02-22 16:32:36 -08001458 DialerCall call = CallList.getInstance().getFirstCall();
1459 if (call == null) {
1460 LogUtil.i("InCallActivity.getShouldShowVideoUi", "null call");
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001461 return new ShouldShowUiResult(false, null);
Eric Erfanianccca3152017-02-22 16:32:36 -08001462 }
1463
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001464 if (call.isVideoCall()) {
Eric Erfanianccca3152017-02-22 16:32:36 -08001465 LogUtil.i("InCallActivity.getShouldShowVideoUi", "found video call");
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001466 return new ShouldShowUiResult(true, call);
Eric Erfanianccca3152017-02-22 16:32:36 -08001467 }
1468
linyuh8fbecce2017-12-18 13:53:09 -08001469 if (call.hasSentVideoUpgradeRequest() || call.hasReceivedVideoUpgradeRequest()) {
Eric Erfanianccca3152017-02-22 16:32:36 -08001470 LogUtil.i("InCallActivity.getShouldShowVideoUi", "upgrading to video");
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001471 return new ShouldShowUiResult(true, call);
Eric Erfanianccca3152017-02-22 16:32:36 -08001472 }
1473
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001474 return new ShouldShowUiResult(false, null);
Eric Erfanianccca3152017-02-22 16:32:36 -08001475 }
1476
wangqi219b8702018-02-13 09:34:41 -08001477 private static ShouldShowUiResult getShouldShowRttUi() {
1478 DialerCall call = CallList.getInstance().getFirstCall();
1479 if (call == null) {
1480 LogUtil.i("InCallActivity.getShouldShowRttUi", "null call");
1481 return new ShouldShowUiResult(false, null);
1482 }
1483
wangqif6be6172018-03-30 15:57:56 -07001484 if (call.isActiveRttCall()) {
wangqi219b8702018-02-13 09:34:41 -08001485 LogUtil.i("InCallActivity.getShouldShowRttUi", "found rtt call");
1486 return new ShouldShowUiResult(true, call);
1487 }
1488
1489 if (call.hasSentRttUpgradeRequest()) {
1490 LogUtil.i("InCallActivity.getShouldShowRttUi", "upgrading to rtt");
1491 return new ShouldShowUiResult(true, call);
1492 }
1493
1494 return new ShouldShowUiResult(false, null);
1495 }
1496
Eric Erfanianccca3152017-02-22 16:32:36 -08001497 private boolean showAnswerScreenFragment(FragmentTransaction transaction, DialerCall call) {
1498 // When rejecting a call the active call can become null in which case we should continue
1499 // showing the answer screen.
1500 if (didShowAnswerScreen && call == null) {
1501 return false;
1502 }
1503
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001504 Assert.checkArgument(call != null, "didShowAnswerScreen was false but call was still null");
1505
1506 boolean isVideoUpgradeRequest = call.hasReceivedVideoUpgradeRequest();
Eric Erfanianccca3152017-02-22 16:32:36 -08001507
1508 // Check if we're already showing an answer screen for this call.
1509 if (didShowAnswerScreen) {
1510 AnswerScreen answerScreen = getAnswerScreen();
1511 if (answerScreen.getCallId().equals(call.getId())
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001512 && answerScreen.isVideoCall() == call.isVideoCall()
Eric Erfanian2ca43182017-08-31 06:57:16 -07001513 && answerScreen.isVideoUpgradeRequest() == isVideoUpgradeRequest
1514 && !answerScreen.isActionTimeout()) {
1515 LogUtil.d(
1516 "InCallActivity.showAnswerScreenFragment",
1517 "answer fragment exists for same call and has NOT been accepted/rejected/timed out");
Eric Erfanianccca3152017-02-22 16:32:36 -08001518 return false;
1519 }
Eric Erfanian2ca43182017-08-31 06:57:16 -07001520 if (answerScreen.isActionTimeout()) {
1521 LogUtil.i(
1522 "InCallActivity.showAnswerScreenFragment",
1523 "answer fragment exists but has been accepted/rejected and timed out");
1524 } else {
1525 LogUtil.i(
1526 "InCallActivity.showAnswerScreenFragment",
1527 "answer fragment exists but arguments do not match");
1528 }
Eric Erfanianccca3152017-02-22 16:32:36 -08001529 hideAnswerScreenFragment(transaction);
1530 }
1531
1532 // Show a new answer screen.
1533 AnswerScreen answerScreen =
Eric Erfanianfc37b022017-03-21 10:11:17 -07001534 AnswerBindings.createAnswerScreen(
1535 call.getId(),
wangqif6be6172018-03-30 15:57:56 -07001536 call.isActiveRttCall(),
Eric Erfanianfc37b022017-03-21 10:11:17 -07001537 call.isVideoCall(),
1538 isVideoUpgradeRequest,
Eric Erfanian90508232017-03-24 09:31:16 -07001539 call.getVideoTech().isSelfManagedCamera(),
1540 shouldAllowAnswerAndRelease(call),
erfaniand05d8992018-03-20 19:42:26 -07001541 CallList.getInstance().getBackgroundCall() != null,
1542 call.isSpeakEasyEligible());
linyuhc3968e62017-11-20 17:40:50 -08001543 transaction.add(R.id.main, answerScreen.getAnswerScreenFragment(), Tags.ANSWER_SCREEN);
Eric Erfanianccca3152017-02-22 16:32:36 -08001544
1545 Logger.get(this).logScreenView(ScreenEvent.Type.INCOMING_CALL, this);
1546 didShowAnswerScreen = true;
1547 return true;
1548 }
1549
Eric Erfanian90508232017-03-24 09:31:16 -07001550 private boolean shouldAllowAnswerAndRelease(DialerCall call) {
1551 if (CallList.getInstance().getActiveCall() == null) {
1552 LogUtil.i("InCallActivity.shouldAllowAnswerAndRelease", "no active call");
1553 return false;
1554 }
1555 if (getSystemService(TelephonyManager.class).getPhoneType()
1556 == TelephonyManager.PHONE_TYPE_CDMA) {
1557 LogUtil.i("InCallActivity.shouldAllowAnswerAndRelease", "PHONE_TYPE_CDMA not supported");
1558 return false;
1559 }
1560 if (call.isVideoCall() || call.hasReceivedVideoUpgradeRequest()) {
1561 LogUtil.i("InCallActivity.shouldAllowAnswerAndRelease", "video call");
1562 return false;
1563 }
linyuhc3968e62017-11-20 17:40:50 -08001564 if (!ConfigProviderBindings.get(this)
1565 .getBoolean(ConfigNames.ANSWER_AND_RELEASE_ENABLED, true)) {
Eric Erfanian90508232017-03-24 09:31:16 -07001566 LogUtil.i("InCallActivity.shouldAllowAnswerAndRelease", "disabled by config");
1567 return false;
1568 }
1569
1570 return true;
1571 }
1572
Eric Erfanianccca3152017-02-22 16:32:36 -08001573 private boolean hideAnswerScreenFragment(FragmentTransaction transaction) {
1574 if (!didShowAnswerScreen) {
1575 return false;
1576 }
1577 AnswerScreen answerScreen = getAnswerScreen();
1578 if (answerScreen != null) {
1579 transaction.remove(answerScreen.getAnswerScreenFragment());
1580 }
1581
1582 didShowAnswerScreen = false;
1583 return true;
1584 }
1585
1586 private boolean showInCallScreenFragment(FragmentTransaction transaction) {
1587 if (didShowInCallScreen) {
1588 return false;
1589 }
Eric Erfanian2ca43182017-08-31 06:57:16 -07001590 InCallScreen inCallScreen = InCallBindings.createInCallScreen();
linyuhc3968e62017-11-20 17:40:50 -08001591 transaction.add(R.id.main, inCallScreen.getInCallScreenFragment(), Tags.IN_CALL_SCREEN);
Eric Erfanianccca3152017-02-22 16:32:36 -08001592 Logger.get(this).logScreenView(ScreenEvent.Type.INCALL, this);
1593 didShowInCallScreen = true;
1594 return true;
1595 }
1596
1597 private boolean hideInCallScreenFragment(FragmentTransaction transaction) {
1598 if (!didShowInCallScreen) {
1599 return false;
1600 }
1601 InCallScreen inCallScreen = getInCallScreen();
1602 if (inCallScreen != null) {
Eric Erfanian2ca43182017-08-31 06:57:16 -07001603 transaction.remove(inCallScreen.getInCallScreenFragment());
Eric Erfanianccca3152017-02-22 16:32:36 -08001604 }
1605 didShowInCallScreen = false;
1606 return true;
1607 }
1608
wangqi219b8702018-02-13 09:34:41 -08001609 private boolean showRttCallScreenFragment(FragmentTransaction transaction, DialerCall call) {
1610 if (didShowRttCallScreen) {
1611 // This shouldn't happen since only one RTT call is allow at same time.
1612 if (!getRttCallScreen().getCallId().equals(call.getId())) {
1613 LogUtil.e("InCallActivity.showRttCallScreenFragment", "RTT call id doesn't match");
1614 }
1615 return false;
1616 }
1617 RttCallScreen rttCallScreen = RttBindings.createRttCallScreen(call.getId());
1618 transaction.add(R.id.main, rttCallScreen.getRttCallScreenFragment(), Tags.RTT_CALL_SCREEN);
1619 Logger.get(this).logScreenView(ScreenEvent.Type.INCALL, this);
1620 didShowRttCallScreen = true;
1621 return true;
1622 }
1623
1624 private boolean hideRttCallScreenFragment(FragmentTransaction transaction) {
1625 if (!didShowRttCallScreen) {
1626 return false;
1627 }
1628 RttCallScreen rttCallScreen = getRttCallScreen();
1629 if (rttCallScreen != null) {
1630 transaction.remove(rttCallScreen.getRttCallScreenFragment());
1631 }
1632 didShowRttCallScreen = false;
1633 return true;
1634 }
1635
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001636 private boolean showVideoCallScreenFragment(FragmentTransaction transaction, DialerCall call) {
Eric Erfanianccca3152017-02-22 16:32:36 -08001637 if (didShowVideoCallScreen) {
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001638 VideoCallScreen videoCallScreen = getVideoCallScreen();
1639 if (videoCallScreen.getCallId().equals(call.getId())) {
1640 return false;
1641 }
1642 LogUtil.i(
1643 "InCallActivity.showVideoCallScreenFragment",
1644 "video call fragment exists but arguments do not match");
1645 hideVideoCallScreenFragment(transaction);
Eric Erfanianccca3152017-02-22 16:32:36 -08001646 }
1647
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001648 LogUtil.i("InCallActivity.showVideoCallScreenFragment", "call: %s", call);
1649
Eric Erfanian90508232017-03-24 09:31:16 -07001650 VideoCallScreen videoCallScreen =
1651 VideoBindings.createVideoCallScreen(
1652 call.getId(), call.getVideoTech().shouldUseSurfaceView());
linyuhc3968e62017-11-20 17:40:50 -08001653 transaction.add(
1654 R.id.main, videoCallScreen.getVideoCallScreenFragment(), Tags.VIDEO_CALL_SCREEN);
Eric Erfanianccca3152017-02-22 16:32:36 -08001655
1656 Logger.get(this).logScreenView(ScreenEvent.Type.INCALL, this);
1657 didShowVideoCallScreen = true;
1658 return true;
1659 }
1660
1661 private boolean hideVideoCallScreenFragment(FragmentTransaction transaction) {
1662 if (!didShowVideoCallScreen) {
1663 return false;
1664 }
1665 VideoCallScreen videoCallScreen = getVideoCallScreen();
1666 if (videoCallScreen != null) {
1667 transaction.remove(videoCallScreen.getVideoCallScreenFragment());
1668 }
1669 didShowVideoCallScreen = false;
1670 return true;
1671 }
1672
linyuhc3968e62017-11-20 17:40:50 -08001673 private AnswerScreen getAnswerScreen() {
1674 return (AnswerScreen) getSupportFragmentManager().findFragmentByTag(Tags.ANSWER_SCREEN);
Eric Erfanianccca3152017-02-22 16:32:36 -08001675 }
1676
linyuhc3968e62017-11-20 17:40:50 -08001677 private InCallScreen getInCallScreen() {
1678 return (InCallScreen) getSupportFragmentManager().findFragmentByTag(Tags.IN_CALL_SCREEN);
Eric Erfanianccca3152017-02-22 16:32:36 -08001679 }
1680
linyuhc3968e62017-11-20 17:40:50 -08001681 private VideoCallScreen getVideoCallScreen() {
1682 return (VideoCallScreen) getSupportFragmentManager().findFragmentByTag(Tags.VIDEO_CALL_SCREEN);
Eric Erfanianccca3152017-02-22 16:32:36 -08001683 }
1684
wangqi219b8702018-02-13 09:34:41 -08001685 private RttCallScreen getRttCallScreen() {
1686 return (RttCallScreen) getSupportFragmentManager().findFragmentByTag(Tags.RTT_CALL_SCREEN);
1687 }
1688
wangqifd4c9f72018-03-08 18:21:50 -08001689 private InCallScreen getInCallOrRttCallScreen() {
1690 InCallScreen inCallScreen = null;
1691 if (didShowInCallScreen) {
1692 inCallScreen = getInCallScreen();
1693 }
1694 if (didShowRttCallScreen) {
1695 inCallScreen = getRttCallScreen();
1696 }
1697 return inCallScreen;
1698 }
1699
Eric Erfanianccca3152017-02-22 16:32:36 -08001700 @Override
1701 public void onPseudoScreenStateChanged(boolean isOn) {
1702 LogUtil.i("InCallActivity.onPseudoScreenStateChanged", "isOn: " + isOn);
1703 pseudoBlackScreenOverlay.setVisibility(isOn ? View.GONE : View.VISIBLE);
1704 }
1705
1706 /**
1707 * For some touch related issue, turning off the screen can be faked by drawing a black view over
1708 * the activity. All touch events started when the screen is "off" is rejected.
1709 *
1710 * @see PseudoScreenState
1711 */
1712 @Override
1713 public boolean dispatchTouchEvent(MotionEvent event) {
1714 // Reject any gesture that started when the screen is in the fake off state.
1715 if (touchDownWhenPseudoScreenOff) {
1716 if (event.getAction() == MotionEvent.ACTION_UP) {
1717 touchDownWhenPseudoScreenOff = false;
1718 }
1719 return true;
1720 }
1721 // Reject all touch event when the screen is in the fake off state.
1722 if (!InCallPresenter.getInstance().getPseudoScreenState().isOn()) {
1723 if (event.getAction() == MotionEvent.ACTION_DOWN) {
1724 touchDownWhenPseudoScreenOff = true;
1725 LogUtil.i("InCallActivity.dispatchTouchEvent", "touchDownWhenPseudoScreenOff");
1726 }
1727 return true;
1728 }
1729 return super.dispatchTouchEvent(event);
1730 }
1731
wangqi219b8702018-02-13 09:34:41 -08001732 @Override
1733 public RttCallScreenDelegate newRttCallScreenDelegate(RttCallScreen videoCallScreen) {
1734 return new RttCallPresenter();
1735 }
1736
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001737 private static class ShouldShowUiResult {
Eric Erfanianccca3152017-02-22 16:32:36 -08001738 public final boolean shouldShow;
1739 public final DialerCall call;
1740
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001741 ShouldShowUiResult(boolean shouldShow, DialerCall call) {
Eric Erfanianccca3152017-02-22 16:32:36 -08001742 this.shouldShow = shouldShow;
1743 this.call = call;
1744 }
1745 }
linyuhc3968e62017-11-20 17:40:50 -08001746
1747 private static final class IntentExtraNames {
1748 static final String FOR_FULL_SCREEN = "InCallActivity.for_full_screen_intent";
1749 static final String NEW_OUTGOING_CALL = "InCallActivity.new_outgoing_call";
1750 static final String SHOW_DIALPAD = "InCallActivity.show_dialpad";
1751 }
1752
1753 private static final class KeysForSavedInstance {
1754 static final String DIALPAD_TEXT = "InCallActivity.dialpad_text";
1755 static final String DID_SHOW_ANSWER_SCREEN = "did_show_answer_screen";
1756 static final String DID_SHOW_IN_CALL_SCREEN = "did_show_in_call_screen";
1757 static final String DID_SHOW_VIDEO_CALL_SCREEN = "did_show_video_call_screen";
wangqi153af2f2018-02-15 16:21:49 -08001758 static final String DID_SHOW_RTT_CALL_SCREEN = "did_show_rtt_call_screen";
erfaniand05d8992018-03-20 19:42:26 -07001759 static final String DID_SHOW_SPEAK_EASY_SCREEN = "did_show_speak_easy_screen";
linyuhc3968e62017-11-20 17:40:50 -08001760 }
1761
1762 /** Request codes for pending intents. */
1763 public static final class PendingIntentRequestCodes {
1764 static final int NON_FULL_SCREEN = 0;
1765 static final int FULL_SCREEN = 1;
1766 static final int BUBBLE = 2;
1767 }
1768
1769 private static final class Tags {
1770 static final String ANSWER_SCREEN = "tag_answer_screen";
1771 static final String DIALPAD_FRAGMENT = "tag_dialpad_fragment";
1772 static final String IN_CALL_SCREEN = "tag_in_call_screen";
1773 static final String INTERNATIONAL_CALL_ON_WIFI = "tag_international_call_on_wifi";
1774 static final String SELECT_ACCOUNT_FRAGMENT = "tag_select_account_fragment";
1775 static final String VIDEO_CALL_SCREEN = "tag_video_call_screen";
wangqi219b8702018-02-13 09:34:41 -08001776 static final String RTT_CALL_SCREEN = "tag_rtt_call_screen";
linyuhc3968e62017-11-20 17:40:50 -08001777 static final String POST_CHAR_DIALOG_FRAGMENT = "tag_post_char_dialog_fragment";
erfaniand05d8992018-03-20 19:42:26 -07001778 static final String SPEAK_EASY_SCREEN = "tag_speak_easy_screen";
wangqibc28ea72018-04-02 16:23:00 -07001779 static final String RTT_REQUEST_DIALOG = "tag_rtt_request_dialog";
linyuhc3968e62017-11-20 17:40:50 -08001780 }
1781
1782 private static final class ConfigNames {
1783 static final String ANSWER_AND_RELEASE_ENABLED = "answer_and_release_enabled";
1784 }
1785
linyuhc3968e62017-11-20 17:40:50 -08001786 private static final class SelectPhoneAccountListener
1787 extends SelectPhoneAccountDialogFragment.SelectPhoneAccountListener {
1788 private static final String TAG = SelectPhoneAccountListener.class.getCanonicalName();
1789
twyen73a74c32018-03-07 12:12:24 -08001790 private final Context appContext;
1791
1792 SelectPhoneAccountListener(Context appContext) {
1793 this.appContext = appContext;
1794 }
1795
linyuhc3968e62017-11-20 17:40:50 -08001796 @Override
1797 public void onPhoneAccountSelected(
1798 PhoneAccountHandle selectedAccountHandle, boolean setDefault, String callId) {
1799 DialerCall call = CallList.getInstance().getCallById(callId);
1800 LogUtil.i(TAG, "Phone account select with call:\n%s", call);
1801
1802 if (call != null) {
twyen73a74c32018-03-07 12:12:24 -08001803 call.phoneAccountSelected(selectedAccountHandle, false);
1804 if (call.getPreferredAccountRecorder() != null) {
1805 call.getPreferredAccountRecorder().record(appContext, selectedAccountHandle, setDefault);
1806 }
linyuhc3968e62017-11-20 17:40:50 -08001807 }
1808 }
1809
1810 @Override
1811 public void onDialogDismissed(String callId) {
1812 DialerCall call = CallList.getInstance().getCallById(callId);
1813 LogUtil.i(TAG, "Disconnecting call:\n%s" + call);
1814
1815 if (call != null) {
1816 call.disconnect();
1817 }
1818 }
1819 }
Eric Erfanianccca3152017-02-22 16:32:36 -08001820}