blob: 1ba3683f0e30d3a1aabed78cf8ddecfd24f8c827 [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;
erfaniand05d8992018-03-20 19:42:26 -070038import android.support.v4.app.Fragment;
Eric Erfanianccca3152017-02-22 16:32:36 -080039import android.support.v4.app.FragmentManager;
40import android.support.v4.app.FragmentTransaction;
linyuh57b093b2017-11-17 14:32:32 -080041import android.support.v4.content.res.ResourcesCompat;
Eric Erfanianccca3152017-02-22 16:32:36 -080042import android.support.v4.graphics.ColorUtils;
twyen73a74c32018-03-07 12:12:24 -080043import android.telecom.Call;
linyuhc3968e62017-11-20 17:40:50 -080044import android.telecom.CallAudioState;
45import android.telecom.PhoneAccountHandle;
Eric Erfanian90508232017-03-24 09:31:16 -070046import android.telephony.TelephonyManager;
Eric Erfanianccca3152017-02-22 16:32:36 -080047import android.view.KeyEvent;
48import android.view.MenuItem;
49import android.view.MotionEvent;
50import android.view.View;
linyuh9c327da2017-11-14 12:33:48 -080051import android.view.WindowManager;
linyuhc3968e62017-11-20 17:40:50 -080052import android.view.animation.Animation;
53import android.view.animation.AnimationUtils;
linyuh7b86f562017-11-16 11:24:09 -080054import android.widget.CheckBox;
55import android.widget.Toast;
linyuhf99f6302017-11-15 11:23:51 -080056import com.android.contacts.common.widget.SelectPhoneAccountDialogFragment;
linyuhc3968e62017-11-20 17:40:50 -080057import com.android.dialer.animation.AnimUtils;
58import com.android.dialer.animation.AnimationListenerAdapter;
Eric Erfaniand5e47f62017-03-15 14:41:07 -070059import com.android.dialer.common.Assert;
Eric Erfanianccca3152017-02-22 16:32:36 -080060import com.android.dialer.common.LogUtil;
twyen73a74c32018-03-07 12:12:24 -080061import com.android.dialer.common.concurrent.DialerExecutorComponent;
weijiaxu650e7cc2017-10-31 12:38:54 -070062import com.android.dialer.common.concurrent.ThreadUtil;
Eric Erfanian2ca43182017-08-31 06:57:16 -070063import com.android.dialer.configprovider.ConfigProviderBindings;
twyen73a74c32018-03-07 12:12:24 -080064import com.android.dialer.logging.DialerImpression.Type;
Eric Erfanianccca3152017-02-22 16:32:36 -080065import com.android.dialer.logging.Logger;
Eric Erfanian8369df02017-05-03 10:27:13 -070066import com.android.dialer.logging.ScreenEvent;
zachh7a96dc72018-02-20 22:16:03 -080067import com.android.dialer.metrics.Metrics;
68import com.android.dialer.metrics.MetricsComponent;
twyen73a74c32018-03-07 12:12:24 -080069import com.android.dialer.preferredsim.PreferredAccountRecorder;
70import com.android.dialer.preferredsim.PreferredAccountWorker;
71import com.android.dialer.preferredsim.suggestion.SuggestionProvider;
linyuhc3968e62017-11-20 17:40:50 -080072import com.android.dialer.util.ViewUtil;
Eric Erfanianccca3152017-02-22 16:32:36 -080073import com.android.incallui.answer.bindings.AnswerBindings;
74import com.android.incallui.answer.protocol.AnswerScreen;
75import com.android.incallui.answer.protocol.AnswerScreenDelegate;
76import com.android.incallui.answer.protocol.AnswerScreenDelegateFactory;
77import com.android.incallui.answerproximitysensor.PseudoScreenState;
linyuh57b093b2017-11-17 14:32:32 -080078import com.android.incallui.audiomode.AudioModeProvider;
Eric Erfanianccca3152017-02-22 16:32:36 -080079import com.android.incallui.call.CallList;
80import com.android.incallui.call.DialerCall;
81import com.android.incallui.call.DialerCall.State;
linyuh57b093b2017-11-17 14:32:32 -080082import com.android.incallui.call.TelecomAdapter;
Eric Erfanian2ca43182017-08-31 06:57:16 -070083import com.android.incallui.callpending.CallPendingActivity;
84import com.android.incallui.disconnectdialog.DisconnectMessage;
Eric Erfanianccca3152017-02-22 16:32:36 -080085import com.android.incallui.incall.bindings.InCallBindings;
86import com.android.incallui.incall.protocol.InCallButtonUiDelegate;
87import com.android.incallui.incall.protocol.InCallButtonUiDelegateFactory;
88import com.android.incallui.incall.protocol.InCallScreen;
89import com.android.incallui.incall.protocol.InCallScreenDelegate;
90import com.android.incallui.incall.protocol.InCallScreenDelegateFactory;
linyuh7b86f562017-11-16 11:24:09 -080091import com.android.incallui.incalluilock.InCallUiLock;
wangqi219b8702018-02-13 09:34:41 -080092import com.android.incallui.rtt.bindings.RttBindings;
93import com.android.incallui.rtt.protocol.RttCallScreen;
94import com.android.incallui.rtt.protocol.RttCallScreenDelegate;
95import com.android.incallui.rtt.protocol.RttCallScreenDelegateFactory;
erfaniand05d8992018-03-20 19:42:26 -070096import com.android.incallui.speakeasy.SpeakEasyCallManager;
linyuhf99f6302017-11-15 11:23:51 -080097import com.android.incallui.telecomeventui.InternationalCallOnWifiDialogFragment;
Eric Erfanianccca3152017-02-22 16:32:36 -080098import com.android.incallui.video.bindings.VideoBindings;
99import com.android.incallui.video.protocol.VideoCallScreen;
100import com.android.incallui.video.protocol.VideoCallScreenDelegate;
101import com.android.incallui.video.protocol.VideoCallScreenDelegateFactory;
linyuhc3968e62017-11-20 17:40:50 -0800102import com.google.common.base.Optional;
103import java.lang.annotation.Retention;
104import java.lang.annotation.RetentionPolicy;
105import java.util.ArrayList;
106import java.util.List;
Eric Erfanianccca3152017-02-22 16:32:36 -0800107
108/** Version of {@link InCallActivity} that shows the new UI */
109public class InCallActivity extends TransactionSafeFragmentActivity
110 implements AnswerScreenDelegateFactory,
111 InCallScreenDelegateFactory,
112 InCallButtonUiDelegateFactory,
113 VideoCallScreenDelegateFactory,
wangqi219b8702018-02-13 09:34:41 -0800114 RttCallScreenDelegateFactory,
Eric Erfanianccca3152017-02-22 16:32:36 -0800115 PseudoScreenState.StateChangedListener {
116
linyuhc3968e62017-11-20 17:40:50 -0800117 @Retention(RetentionPolicy.SOURCE)
118 @IntDef({
119 DIALPAD_REQUEST_NONE,
120 DIALPAD_REQUEST_SHOW,
121 DIALPAD_REQUEST_HIDE,
122 })
123 @interface DialpadRequestType {}
Eric Erfanian2ca43182017-08-31 06:57:16 -0700124
linyuhc3968e62017-11-20 17:40:50 -0800125 private static final int DIALPAD_REQUEST_NONE = 1;
126 private static final int DIALPAD_REQUEST_SHOW = 2;
127 private static final int DIALPAD_REQUEST_HIDE = 3;
linyuh57b093b2017-11-17 14:32:32 -0800128
linyuhc3968e62017-11-20 17:40:50 -0800129 private static Optional<Integer> audioRouteForTesting = Optional.absent();
linyuh57b093b2017-11-17 14:32:32 -0800130
linyuhc3968e62017-11-20 17:40:50 -0800131 private final InternationalCallOnWifiCallback internationalCallOnWifiCallback =
132 new InternationalCallOnWifiCallback();
twyen73a74c32018-03-07 12:12:24 -0800133
134 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;
linyuh9c327da2017-11-14 12:33:48 -0800153 private boolean dismissKeyguard;
Eric Erfanianccca3152017-02-22 16:32:36 -0800154 private boolean isInShowMainInCallFragment;
linyuhc3968e62017-11-20 17:40:50 -0800155 private boolean isRecreating; // whether the activity is going to be recreated
156 private boolean isVisible;
Eric Erfanianccca3152017-02-22 16:32:36 -0800157 private boolean needDismissPendingDialogs;
linyuhc3968e62017-11-20 17:40:50 -0800158 private boolean showPostCharWaitDialogOnResume;
159 private boolean touchDownWhenPseudoScreenOff;
160 private int[] backgroundDrawableColors;
161 @DialpadRequestType private int showDialpadRequest = DIALPAD_REQUEST_NONE;
erfaniand05d8992018-03-20 19:42:26 -0700162 private SpeakEasyCallManager speakEasyCallManager;
Eric Erfanianccca3152017-02-22 16:32:36 -0800163
164 public static Intent getIntent(
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700165 Context context, boolean showDialpad, boolean newOutgoingCall, boolean isForFullScreen) {
Eric Erfanianccca3152017-02-22 16:32:36 -0800166 Intent intent = new Intent(Intent.ACTION_MAIN, null);
167 intent.setFlags(Intent.FLAG_ACTIVITY_NO_USER_ACTION | Intent.FLAG_ACTIVITY_NEW_TASK);
168 intent.setClass(context, InCallActivity.class);
linyuhc3968e62017-11-20 17:40:50 -0800169 if (showDialpad) {
170 intent.putExtra(IntentExtraNames.SHOW_DIALPAD, true);
171 }
172 intent.putExtra(IntentExtraNames.NEW_OUTGOING_CALL, newOutgoingCall);
173 intent.putExtra(IntentExtraNames.FOR_FULL_SCREEN, isForFullScreen);
Eric Erfanianccca3152017-02-22 16:32:36 -0800174 return intent;
175 }
176
177 @Override
178 protected void onResumeFragments() {
179 super.onResumeFragments();
180 if (needDismissPendingDialogs) {
181 dismissPendingDialogs();
182 }
183 }
184
185 @Override
linyuhc3968e62017-11-20 17:40:50 -0800186 protected void onCreate(Bundle bundle) {
Eric Erfanian2ca43182017-08-31 06:57:16 -0700187 Trace.beginSection("InCallActivity.onCreate");
linyuhc3968e62017-11-20 17:40:50 -0800188 super.onCreate(bundle);
Eric Erfanianccca3152017-02-22 16:32:36 -0800189
twyen73a74c32018-03-07 12:12:24 -0800190 selectPhoneAccountListener = new SelectPhoneAccountListener(getApplicationContext());
191
linyuhc3968e62017-11-20 17:40:50 -0800192 if (bundle != null) {
193 didShowAnswerScreen = bundle.getBoolean(KeysForSavedInstance.DID_SHOW_ANSWER_SCREEN);
194 didShowInCallScreen = bundle.getBoolean(KeysForSavedInstance.DID_SHOW_IN_CALL_SCREEN);
195 didShowVideoCallScreen = bundle.getBoolean(KeysForSavedInstance.DID_SHOW_VIDEO_CALL_SCREEN);
wangqi153af2f2018-02-15 16:21:49 -0800196 didShowRttCallScreen = bundle.getBoolean(KeysForSavedInstance.DID_SHOW_RTT_CALL_SCREEN);
Eric Erfanianccca3152017-02-22 16:32:36 -0800197 }
198
linyuhc3968e62017-11-20 17:40:50 -0800199 setWindowFlags();
200 setContentView(R.layout.incall_screen);
201 internalResolveIntent(getIntent());
202
203 boolean isLandscape =
204 getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE;
205 boolean isRtl = ViewUtil.isRtl();
206 if (isLandscape) {
207 dialpadSlideInAnimation =
208 AnimationUtils.loadAnimation(
209 this, isRtl ? R.anim.dialpad_slide_in_left : R.anim.dialpad_slide_in_right);
210 dialpadSlideOutAnimation =
211 AnimationUtils.loadAnimation(
212 this, isRtl ? R.anim.dialpad_slide_out_left : R.anim.dialpad_slide_out_right);
213 } else {
214 dialpadSlideInAnimation = AnimationUtils.loadAnimation(this, R.anim.dialpad_slide_in_bottom);
215 dialpadSlideOutAnimation =
216 AnimationUtils.loadAnimation(this, R.anim.dialpad_slide_out_bottom);
217 }
218 dialpadSlideInAnimation.setInterpolator(AnimUtils.EASE_IN);
219 dialpadSlideOutAnimation.setInterpolator(AnimUtils.EASE_OUT);
220 dialpadSlideOutAnimation.setAnimationListener(
221 new AnimationListenerAdapter() {
222 @Override
223 public void onAnimationEnd(Animation animation) {
224 hideDialpadFragment();
225 }
226 });
227
228 if (bundle != null && showDialpadRequest == DIALPAD_REQUEST_NONE) {
229 // If the dialpad was shown before, set related variables so that it can be shown and
230 // populated with the previous DTMF text during onResume().
231 if (bundle.containsKey(IntentExtraNames.SHOW_DIALPAD)) {
232 boolean showDialpad = bundle.getBoolean(IntentExtraNames.SHOW_DIALPAD);
233 showDialpadRequest = showDialpad ? DIALPAD_REQUEST_SHOW : DIALPAD_REQUEST_HIDE;
234 animateDialpadOnShow = false;
235 }
236 dtmfTextToPrepopulate = bundle.getString(KeysForSavedInstance.DIALPAD_TEXT);
237
238 SelectPhoneAccountDialogFragment selectPhoneAccountDialogFragment =
239 (SelectPhoneAccountDialogFragment)
240 getFragmentManager().findFragmentByTag(Tags.SELECT_ACCOUNT_FRAGMENT);
241 if (selectPhoneAccountDialogFragment != null) {
242 selectPhoneAccountDialogFragment.setListener(selectPhoneAccountListener);
243 }
244 }
245
246 InternationalCallOnWifiDialogFragment existingInternationalCallOnWifiDialogFragment =
247 (InternationalCallOnWifiDialogFragment)
248 getSupportFragmentManager().findFragmentByTag(Tags.INTERNATIONAL_CALL_ON_WIFI);
249 if (existingInternationalCallOnWifiDialogFragment != null) {
250 existingInternationalCallOnWifiDialogFragment.setCallback(internationalCallOnWifiCallback);
251 }
252
linyuh69a25062017-11-15 16:18:51 -0800253 inCallOrientationEventListener = new InCallOrientationEventListener(this);
Eric Erfanianccca3152017-02-22 16:32:36 -0800254
255 getWindow()
256 .getDecorView()
257 .setSystemUiVisibility(
258 View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
259
260 pseudoBlackScreenOverlay = findViewById(R.id.psuedo_black_screen_overlay);
Eric Erfanian2ca43182017-08-31 06:57:16 -0700261 sendBroadcast(CallPendingActivity.getFinishBroadcast());
262 Trace.endSection();
zachh7a96dc72018-02-20 22:16:03 -0800263 MetricsComponent.get(this)
264 .metrics()
265 .stopTimer(Metrics.ON_CALL_ADDED_TO_ON_INCALL_UI_SHOWN_INCOMING);
266 MetricsComponent.get(this)
267 .metrics()
268 .stopTimer(Metrics.ON_CALL_ADDED_TO_ON_INCALL_UI_SHOWN_OUTGOING);
Eric Erfanianccca3152017-02-22 16:32:36 -0800269 }
270
linyuhc3968e62017-11-20 17:40:50 -0800271 private void setWindowFlags() {
272 // Allow the activity to be shown when the screen is locked and filter out touch events that are
273 // "too fat".
274 int flags =
275 WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
276 | WindowManager.LayoutParams.FLAG_IGNORE_CHEEK_PRESSES;
277
linyuhf79d1cb2017-12-15 17:49:56 -0800278 // When the audio stream is not via Bluetooth, turn on the screen once the activity is shown.
279 // When the audio stream is via Bluetooth, turn on the screen only for an incoming call.
linyuhc3968e62017-11-20 17:40:50 -0800280 final int audioRoute = getAudioRoute();
linyuhf79d1cb2017-12-15 17:49:56 -0800281 if (audioRoute != CallAudioState.ROUTE_BLUETOOTH
282 || CallList.getInstance().getIncomingCall() != null) {
linyuhc3968e62017-11-20 17:40:50 -0800283 flags |= WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON;
284 }
285
286 getWindow().addFlags(flags);
287 }
288
289 private static int getAudioRoute() {
290 if (audioRouteForTesting.isPresent()) {
291 return audioRouteForTesting.get();
292 }
293
294 return AudioModeProvider.getInstance().getAudioState().getRoute();
295 }
296
297 @VisibleForTesting(otherwise = VisibleForTesting.NONE)
298 public static void setAudioRouteForTesting(int audioRoute) {
299 audioRouteForTesting = Optional.of(audioRoute);
300 }
301
302 private void internalResolveIntent(Intent intent) {
303 if (!intent.getAction().equals(Intent.ACTION_MAIN)) {
304 return;
305 }
306
307 if (intent.hasExtra(IntentExtraNames.SHOW_DIALPAD)) {
308 // IntentExtraNames.SHOW_DIALPAD can be used to specify whether the DTMF dialpad should be
309 // initially visible. If the extra is absent, leave the dialpad in its previous state.
310 boolean showDialpad = intent.getBooleanExtra(IntentExtraNames.SHOW_DIALPAD, false);
311 relaunchedFromDialer(showDialpad);
312 }
313
314 DialerCall outgoingCall = CallList.getInstance().getOutgoingCall();
315 if (outgoingCall == null) {
316 outgoingCall = CallList.getInstance().getPendingOutgoingCall();
317 }
318 if (intent.getBooleanExtra(IntentExtraNames.NEW_OUTGOING_CALL, false)) {
319 intent.removeExtra(IntentExtraNames.NEW_OUTGOING_CALL);
320
321 // InCallActivity is responsible for disconnecting a new outgoing call if there is no way of
322 // making it (i.e. no valid call capable accounts).
linyuh122fb0b2018-03-26 13:35:32 -0700323 if (InCallPresenter.isCallWithNoValidAccounts(outgoingCall)) {
linyuhc3968e62017-11-20 17:40:50 -0800324 LogUtil.i(
325 "InCallActivity.internalResolveIntent", "Call with no valid accounts, disconnecting");
326 outgoingCall.disconnect();
327 }
328
329 dismissKeyguard(true);
330 }
331
332 if (showPhoneAccountSelectionDialog()) {
333 hideMainInCallFragment();
334 }
335 }
336
337 /**
338 * When relaunching from the dialer app, {@code showDialpad} indicates whether the dialpad should
339 * be shown on launch.
340 *
341 * @param showDialpad {@code true} to indicate the dialpad should be shown on launch, and {@code
342 * false} to indicate no change should be made to the dialpad visibility.
343 */
344 private void relaunchedFromDialer(boolean showDialpad) {
345 showDialpadRequest = showDialpad ? DIALPAD_REQUEST_SHOW : DIALPAD_REQUEST_NONE;
346 animateDialpadOnShow = true;
347
348 if (showDialpadRequest == DIALPAD_REQUEST_SHOW) {
349 // If there's only one line in use, AND it's on hold, then we're sure the user
350 // wants to use the dialpad toward the exact line, so un-hold the holding line.
351 DialerCall call = CallList.getInstance().getActiveOrBackgroundCall();
352 if (call != null && call.getState() == State.ONHOLD) {
353 call.unhold();
354 }
355 }
356 }
357
358 /**
359 * Show a phone account selection dialog if there is a call waiting for phone account selection.
360 *
361 * @return true if the dialog was shown.
362 */
363 private boolean showPhoneAccountSelectionDialog() {
364 DialerCall waitingForAccountCall = CallList.getInstance().getWaitingForAccountCall();
365 if (waitingForAccountCall == null) {
366 return false;
367 }
368
twyen73a74c32018-03-07 12:12:24 -0800369 DialerExecutorComponent.get(this)
370 .dialerExecutorFactory()
371 .createNonUiTaskBuilder(new PreferredAccountWorker(waitingForAccountCall.getNumber()))
372 .onSuccess(
373 (result -> {
374 if (result.getPhoneAccountHandle().isPresent()) {
375 Logger.get(this).logImpression(Type.DUAL_SIM_SELECTION_PREFERRED_USED);
376 selectPhoneAccountListener.onPhoneAccountSelected(
377 result.getPhoneAccountHandle().get(), false, waitingForAccountCall.getId());
378 return;
379 }
380 if (result.getSuggestion().isPresent()) {
381 LogUtil.i(
382 "CallingAccountSelector.processPreferredAccount",
383 "SIM suggested: " + result.getSuggestion().get().reason);
384 if (result.getSuggestion().get().shouldAutoSelect) {
385 Logger.get(this).logImpression(Type.DUAL_SIM_SELECTION_SUGGESTION_AUTO_SELECTED);
386 LogUtil.i(
387 "CallingAccountSelector.processPreferredAccount", "Auto selected suggestion");
388 selectPhoneAccountListener.onPhoneAccountSelected(
389 result.getSuggestion().get().phoneAccountHandle,
390 false,
391 waitingForAccountCall.getId());
392 return;
393 }
394 }
395 Bundle extras = waitingForAccountCall.getIntentExtras();
396 List<PhoneAccountHandle> phoneAccountHandles =
397 extras == null
398 ? new ArrayList<>()
399 : extras.getParcelableArrayList(Call.AVAILABLE_PHONE_ACCOUNTS);
linyuhc3968e62017-11-20 17:40:50 -0800400
twyen73a74c32018-03-07 12:12:24 -0800401 waitingForAccountCall.setPreferredAccountRecorder(
402 new PreferredAccountRecorder(
403 waitingForAccountCall.getNumber(),
404 result.getSuggestion().orNull(),
405 result.getDataId().orNull()));
406 selectPhoneAccountDialogFragment =
407 SelectPhoneAccountDialogFragment.newInstance(
408 R.string.select_phone_account_for_calls,
409 result.getDataId().isPresent() /* canSetDefault */,
410 R.string.select_phone_account_for_calls_remember /* setDefaultResId */,
411 phoneAccountHandles,
412 selectPhoneAccountListener,
413 waitingForAccountCall.getId(),
414 SuggestionProvider.buildHint(
415 this, phoneAccountHandles, result.getSuggestion().orNull() /* hints */));
416 selectPhoneAccountDialogFragment.show(
417 getFragmentManager(), Tags.SELECT_ACCOUNT_FRAGMENT);
418 }))
419 .build()
420 .executeParallel(this);
421
linyuhc3968e62017-11-20 17:40:50 -0800422 return true;
423 }
424
Eric Erfanianccca3152017-02-22 16:32:36 -0800425 @Override
426 protected void onSaveInstanceState(Bundle out) {
linyuh57b093b2017-11-17 14:32:32 -0800427 LogUtil.enterBlock("InCallActivity.onSaveInstanceState");
428
429 // TODO: DialpadFragment should handle this as part of its own state
linyuhc3968e62017-11-20 17:40:50 -0800430 out.putBoolean(IntentExtraNames.SHOW_DIALPAD, isDialpadVisible());
linyuh57b093b2017-11-17 14:32:32 -0800431 DialpadFragment dialpadFragment = getDialpadFragment();
432 if (dialpadFragment != null) {
linyuhc3968e62017-11-20 17:40:50 -0800433 out.putString(KeysForSavedInstance.DIALPAD_TEXT, dialpadFragment.getDtmfText());
linyuh57b093b2017-11-17 14:32:32 -0800434 }
435
linyuhc3968e62017-11-20 17:40:50 -0800436 out.putBoolean(KeysForSavedInstance.DID_SHOW_ANSWER_SCREEN, didShowAnswerScreen);
437 out.putBoolean(KeysForSavedInstance.DID_SHOW_IN_CALL_SCREEN, didShowInCallScreen);
438 out.putBoolean(KeysForSavedInstance.DID_SHOW_VIDEO_CALL_SCREEN, didShowVideoCallScreen);
wangqi153af2f2018-02-15 16:21:49 -0800439 out.putBoolean(KeysForSavedInstance.DID_SHOW_RTT_CALL_SCREEN, didShowRttCallScreen);
erfaniand05d8992018-03-20 19:42:26 -0700440 out.putBoolean(KeysForSavedInstance.DID_SHOW_SPEAK_EASY_SCREEN, didShowSpeakEasyScreen);
linyuh57b093b2017-11-17 14:32:32 -0800441
Eric Erfanianccca3152017-02-22 16:32:36 -0800442 super.onSaveInstanceState(out);
443 isVisible = false;
444 }
445
446 @Override
447 protected void onStart() {
Eric Erfanian2ca43182017-08-31 06:57:16 -0700448 Trace.beginSection("InCallActivity.onStart");
Eric Erfanianccca3152017-02-22 16:32:36 -0800449 super.onStart();
linyuh57b093b2017-11-17 14:32:32 -0800450
Eric Erfanianccca3152017-02-22 16:32:36 -0800451 isVisible = true;
452 showMainInCallFragment();
linyuh57b093b2017-11-17 14:32:32 -0800453
454 InCallPresenter.getInstance().setActivity(this);
455 enableInCallOrientationEventListener(
456 getRequestedOrientation()
457 == InCallOrientationEventListener.ACTIVITY_PREFERENCE_ALLOW_ROTATION);
458 InCallPresenter.getInstance().onActivityStarted();
459
yueg10f6e822018-01-17 15:32:18 -0800460 if (!isRecreating) {
461 InCallPresenter.getInstance().onUiShowing(true);
462 }
463
linyuh437ae952018-03-26 12:46:18 -0700464 if (isInMultiWindowMode() && !getResources().getBoolean(R.bool.incall_dialpad_allowed)) {
Eric Erfanianccca3152017-02-22 16:32:36 -0800465 // Hide the dialpad because there may not be enough room
466 showDialpadFragment(false, false);
467 }
linyuh57b093b2017-11-17 14:32:32 -0800468
Eric Erfanian2ca43182017-08-31 06:57:16 -0700469 Trace.endSection();
Eric Erfanianccca3152017-02-22 16:32:36 -0800470 }
471
472 @Override
473 protected void onResume() {
Eric Erfanian2ca43182017-08-31 06:57:16 -0700474 Trace.beginSection("InCallActivity.onResume");
Eric Erfanianccca3152017-02-22 16:32:36 -0800475 super.onResume();
linyuhc3968e62017-11-20 17:40:50 -0800476
477 if (!InCallPresenter.getInstance().isReadyForTearDown()) {
478 updateTaskDescription();
linyuhc3968e62017-11-20 17:40:50 -0800479 }
480
481 // If there is a pending request to show or hide the dialpad, handle that now.
482 if (showDialpadRequest != DIALPAD_REQUEST_NONE) {
483 if (showDialpadRequest == DIALPAD_REQUEST_SHOW) {
484 // Exit fullscreen so that the user has access to the dialpad hide/show button.
485 // This is important when showing the dialpad from within dialer.
486 InCallPresenter.getInstance().setFullScreen(false /* isFullScreen */, true /* force */);
487
488 showDialpadFragment(true /* show */, animateDialpadOnShow /* animate */);
489 animateDialpadOnShow = false;
490
491 DialpadFragment dialpadFragment = getDialpadFragment();
492 if (dialpadFragment != null) {
493 dialpadFragment.setDtmfText(dtmfTextToPrepopulate);
494 dtmfTextToPrepopulate = null;
495 }
496 } else {
497 LogUtil.i("InCallActivity.onResume", "Force-hide the dialpad");
498 if (getDialpadFragment() != null) {
499 showDialpadFragment(false /* show */, false /* animate */);
500 }
501 }
502 showDialpadRequest = DIALPAD_REQUEST_NONE;
503 }
504 updateNavigationBar(isDialpadVisible());
505
506 if (showPostCharWaitDialogOnResume) {
507 showDialogForPostCharWait(showPostCharWaitDialogCallId, showPostCharWaitDialogChars);
508 }
509
510 CallList.getInstance()
511 .onInCallUiShown(getIntent().getBooleanExtra(IntentExtraNames.FOR_FULL_SCREEN, false));
512
Eric Erfanianccca3152017-02-22 16:32:36 -0800513 PseudoScreenState pseudoScreenState = InCallPresenter.getInstance().getPseudoScreenState();
514 pseudoScreenState.addListener(this);
515 onPseudoScreenStateChanged(pseudoScreenState.isOn());
Eric Erfanian2ca43182017-08-31 06:57:16 -0700516 Trace.endSection();
weijiaxu650e7cc2017-10-31 12:38:54 -0700517 // add 1 sec delay to get memory snapshot so that dialer wont react slowly on resume.
518 ThreadUtil.postDelayedOnUiThread(
weijiaxuc950a9b2017-11-06 16:39:04 -0800519 () ->
zachh7a96dc72018-02-20 22:16:03 -0800520 MetricsComponent.get(this)
521 .metrics()
522 .recordMemory(Metrics.INCALL_ACTIVITY_ON_RESUME_MEMORY_EVENT_NAME),
weijiaxu650e7cc2017-10-31 12:38:54 -0700523 1000);
Eric Erfanianccca3152017-02-22 16:32:36 -0800524 }
525
Eric Erfanianccca3152017-02-22 16:32:36 -0800526 @Override
527 protected void onPause() {
Eric Erfanian2ca43182017-08-31 06:57:16 -0700528 Trace.beginSection("InCallActivity.onPause");
Eric Erfanianccca3152017-02-22 16:32:36 -0800529 super.onPause();
linyuh57b093b2017-11-17 14:32:32 -0800530
531 DialpadFragment dialpadFragment = getDialpadFragment();
532 if (dialpadFragment != null) {
533 dialpadFragment.onDialerKeyUp(null);
534 }
535
Eric Erfanianccca3152017-02-22 16:32:36 -0800536 InCallPresenter.getInstance().getPseudoScreenState().removeListener(this);
Eric Erfanian2ca43182017-08-31 06:57:16 -0700537 Trace.endSection();
Eric Erfanianccca3152017-02-22 16:32:36 -0800538 }
539
540 @Override
541 protected void onStop() {
Eric Erfanian2ca43182017-08-31 06:57:16 -0700542 Trace.beginSection("InCallActivity.onStop");
wangqi4d705e52017-09-28 12:23:35 -0700543 isVisible = false;
Eric Erfanianccca3152017-02-22 16:32:36 -0800544 super.onStop();
linyuh57b093b2017-11-17 14:32:32 -0800545
546 // Disconnects the call waiting for a phone account when the activity is hidden (e.g., after the
547 // user presses the home button).
548 // Without this the pending call will get stuck on phone account selection and new calls can't
549 // be created.
550 // Skip this when the screen is locked since the activity may complete its current life cycle
551 // and restart.
linyuhc3968e62017-11-20 17:40:50 -0800552 if (!isRecreating && !getSystemService(KeyguardManager.class).isKeyguardLocked()) {
linyuh57b093b2017-11-17 14:32:32 -0800553 DialerCall waitingForAccountCall = CallList.getInstance().getWaitingForAccountCall();
554 if (waitingForAccountCall != null) {
555 waitingForAccountCall.disconnect();
556 }
557 }
558
559 enableInCallOrientationEventListener(false);
560 InCallPresenter.getInstance().updateIsChangingConfigurations();
561 InCallPresenter.getInstance().onActivityStopped();
linyuhc3968e62017-11-20 17:40:50 -0800562 if (!isRecreating) {
yueg10f6e822018-01-17 15:32:18 -0800563 InCallPresenter.getInstance().onUiShowing(false);
linyuh57b093b2017-11-17 14:32:32 -0800564 if (errorDialog != null) {
565 errorDialog.dismiss();
566 }
567 }
568
yueg10f6e822018-01-17 15:32:18 -0800569 if (isFinishing()) {
570 InCallPresenter.getInstance().unsetActivity(this);
571 }
572
Eric Erfanian2ca43182017-08-31 06:57:16 -0700573 Trace.endSection();
Eric Erfanianccca3152017-02-22 16:32:36 -0800574 }
575
576 @Override
577 protected void onDestroy() {
Eric Erfanian2ca43182017-08-31 06:57:16 -0700578 Trace.beginSection("InCallActivity.onDestroy");
Eric Erfanianccca3152017-02-22 16:32:36 -0800579 super.onDestroy();
linyuh57b093b2017-11-17 14:32:32 -0800580
581 InCallPresenter.getInstance().unsetActivity(this);
582 InCallPresenter.getInstance().updateIsChangingConfigurations();
Eric Erfanian2ca43182017-08-31 06:57:16 -0700583 Trace.endSection();
Eric Erfanianccca3152017-02-22 16:32:36 -0800584 }
585
586 @Override
587 public void finish() {
588 if (shouldCloseActivityOnFinish()) {
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700589 // When user select incall ui from recents after the call is disconnected, it tries to launch
590 // a new InCallActivity but InCallPresenter is already teared down at this point, which causes
591 // crash.
592 // By calling finishAndRemoveTask() instead of finish() the task associated with
593 // InCallActivity is cleared completely. So system won't try to create a new InCallActivity in
594 // this case.
595 //
596 // Calling finish won't clear the task and normally when an activity finishes it shouldn't
597 // clear the task since there could be parent activity in the same task that's still alive.
598 // But InCallActivity is special since it's singleInstance which means it's root activity and
599 // only instance of activity in the task. So it should be safe to also remove task when
600 // finishing.
601 // It's also necessary in the sense of it's excluded from recents. So whenever the activity
602 // finishes, the task should also be removed since it doesn't make sense to go back to it in
603 // anyway anymore.
604 super.finishAndRemoveTask();
Eric Erfanianccca3152017-02-22 16:32:36 -0800605 }
606 }
607
608 private boolean shouldCloseActivityOnFinish() {
linyuhc3968e62017-11-20 17:40:50 -0800609 if (!isVisible) {
Eric Erfanianccca3152017-02-22 16:32:36 -0800610 LogUtil.i(
611 "InCallActivity.shouldCloseActivityOnFinish",
612 "allowing activity to be closed because it's not visible");
613 return true;
614 }
615
twyen8efb4952017-10-06 16:35:54 -0700616 if (InCallPresenter.getInstance().isInCallUiLocked()) {
Eric Erfanianccca3152017-02-22 16:32:36 -0800617 LogUtil.i(
618 "InCallActivity.shouldCloseActivityOnFinish",
twyen8efb4952017-10-06 16:35:54 -0700619 "in call ui is locked, not closing activity");
Eric Erfanianccca3152017-02-22 16:32:36 -0800620 return false;
621 }
622
623 LogUtil.i(
624 "InCallActivity.shouldCloseActivityOnFinish",
twyen8efb4952017-10-06 16:35:54 -0700625 "activity is visible and has no locks, allowing activity to close");
Eric Erfanianccca3152017-02-22 16:32:36 -0800626 return true;
627 }
628
629 @Override
630 protected void onNewIntent(Intent intent) {
linyuhc3968e62017-11-20 17:40:50 -0800631 LogUtil.enterBlock("InCallActivity.onNewIntent");
Eric Erfanianccca3152017-02-22 16:32:36 -0800632
633 // If the screen is off, we need to make sure it gets turned on for incoming calls.
634 // This normally works just fine thanks to FLAG_TURN_SCREEN_ON but that only works
635 // when the activity is first created. Therefore, to ensure the screen is turned on
636 // for the call waiting case, we recreate() the current activity. There should be no jank from
637 // this since the screen is already off and will remain so until our new activity is up.
linyuhc3968e62017-11-20 17:40:50 -0800638 if (!isVisible) {
639 onNewIntent(intent, true /* isRecreating */);
Eric Erfanianccca3152017-02-22 16:32:36 -0800640 LogUtil.i("InCallActivity.onNewIntent", "Restarting InCallActivity to force screen on.");
641 recreate();
Eric Erfanian10b34a52017-05-04 08:23:17 -0700642 } else {
linyuhc3968e62017-11-20 17:40:50 -0800643 onNewIntent(intent, false /* isRecreating */);
644 }
645 }
646
yuega3305352018-01-09 11:02:47 -0800647 @VisibleForTesting
648 void onNewIntent(Intent intent, boolean isRecreating) {
linyuhc3968e62017-11-20 17:40:50 -0800649 this.isRecreating = isRecreating;
650
651 // We're being re-launched with a new Intent. Since it's possible for a single InCallActivity
652 // instance to persist indefinitely (even if we finish() ourselves), this sequence can
653 // happen any time the InCallActivity needs to be displayed.
654
655 // Stash away the new intent so that we can get it in the future by calling getIntent().
656 // Otherwise getIntent() will return the original Intent from when we first got created.
657 setIntent(intent);
658
659 // Activities are always paused before receiving a new intent, so we can count on our onResume()
660 // method being called next.
661
662 // Just like in onCreate(), handle the intent.
663 // Skip if InCallActivity is going to be recreated since this will be called in onCreate().
664 if (!isRecreating) {
665 internalResolveIntent(intent);
Eric Erfanianccca3152017-02-22 16:32:36 -0800666 }
667 }
668
669 @Override
670 public void onBackPressed() {
linyuh57b093b2017-11-17 14:32:32 -0800671 LogUtil.enterBlock("InCallActivity.onBackPressed");
672
linyuhc3968e62017-11-20 17:40:50 -0800673 if (!isVisible) {
linyuh57b093b2017-11-17 14:32:32 -0800674 return;
Eric Erfanianccca3152017-02-22 16:32:36 -0800675 }
linyuh57b093b2017-11-17 14:32:32 -0800676
677 if (!getCallCardFragmentVisible()) {
678 return;
679 }
680
681 DialpadFragment dialpadFragment = getDialpadFragment();
682 if (dialpadFragment != null && dialpadFragment.isVisible()) {
683 showDialpadFragment(false /* show */, true /* animate */);
684 return;
685 }
686
687 if (CallList.getInstance().getIncomingCall() != null) {
688 LogUtil.i(
689 "InCallActivity.onBackPressed",
690 "Ignore the press of the back key when an incoming call is ringing");
691 return;
692 }
693
694 // Nothing special to do. Fall back to the default behavior.
695 super.onBackPressed();
Eric Erfanianccca3152017-02-22 16:32:36 -0800696 }
697
698 @Override
699 public boolean onOptionsItemSelected(MenuItem item) {
700 LogUtil.i("InCallActivity.onOptionsItemSelected", "item: " + item);
701 if (item.getItemId() == android.R.id.home) {
702 onBackPressed();
703 return true;
704 }
705 return super.onOptionsItemSelected(item);
706 }
707
708 @Override
709 public boolean onKeyUp(int keyCode, KeyEvent event) {
linyuh57b093b2017-11-17 14:32:32 -0800710 DialpadFragment dialpadFragment = getDialpadFragment();
711 if (dialpadFragment != null
712 && dialpadFragment.isVisible()
713 && dialpadFragment.onDialerKeyUp(event)) {
714 return true;
715 }
716
717 if (keyCode == KeyEvent.KEYCODE_CALL) {
718 // Always consume KEYCODE_CALL to ensure the PhoneWindow won't do anything with it.
719 return true;
720 }
721
722 return super.onKeyUp(keyCode, event);
Eric Erfanianccca3152017-02-22 16:32:36 -0800723 }
724
725 @Override
726 public boolean onKeyDown(int keyCode, KeyEvent event) {
linyuh57b093b2017-11-17 14:32:32 -0800727 switch (keyCode) {
728 case KeyEvent.KEYCODE_CALL:
729 if (!InCallPresenter.getInstance().handleCallKey()) {
730 LogUtil.e(
731 "InCallActivity.onKeyDown",
732 "InCallPresenter should always handle KEYCODE_CALL in onKeyDown");
733 }
734 // Always consume KEYCODE_CALL to ensure the PhoneWindow won't do anything with it.
735 return true;
736
737 // Note that KEYCODE_ENDCALL isn't handled here as the standard system-wide handling of it
738 // is exactly what's needed, namely
739 // (1) "hang up" if there's an active call, or
740 // (2) "don't answer" if there's an incoming call.
741 // (See PhoneWindowManager for implementation details.)
742
743 case KeyEvent.KEYCODE_CAMERA:
744 // Consume KEYCODE_CAMERA since it's easy to accidentally press the camera button.
745 return true;
746
747 case KeyEvent.KEYCODE_VOLUME_UP:
748 case KeyEvent.KEYCODE_VOLUME_DOWN:
749 case KeyEvent.KEYCODE_VOLUME_MUTE:
750 // Ringer silencing handled by PhoneWindowManager.
751 break;
752
753 case KeyEvent.KEYCODE_MUTE:
754 TelecomAdapter.getInstance()
755 .mute(!AudioModeProvider.getInstance().getAudioState().isMuted());
756 return true;
757
758 case KeyEvent.KEYCODE_SLASH:
759 // When verbose logging is enabled, dump the view for debugging/testing purposes.
760 if (LogUtil.isVerboseEnabled()) {
761 View decorView = getWindow().getDecorView();
762 LogUtil.v("InCallActivity.onKeyDown", "View dump:\n%s", decorView);
763 return true;
764 }
765 break;
766
767 case KeyEvent.KEYCODE_EQUALS:
768 break;
769
770 default: // fall out
771 }
772
773 // Pass other key events to DialpadFragment's "onDialerKeyDown" method in case the user types
774 // in DTMF (Dual-tone multi-frequency signaling) code.
775 DialpadFragment dialpadFragment = getDialpadFragment();
776 if (dialpadFragment != null
777 && dialpadFragment.isVisible()
778 && dialpadFragment.onDialerKeyDown(event)) {
779 return true;
780 }
781
782 return super.onKeyDown(keyCode, event);
Eric Erfanianccca3152017-02-22 16:32:36 -0800783 }
784
785 public boolean isInCallScreenAnimating() {
786 return false;
787 }
788
789 public void showConferenceFragment(boolean show) {
790 if (show) {
791 startActivity(new Intent(this, ManageConferenceActivity.class));
792 }
793 }
794
linyuhc3968e62017-11-20 17:40:50 -0800795 public void showDialpadFragment(boolean show, boolean animate) {
796 if (show == isDialpadVisible()) {
797 return;
Eric Erfanianccca3152017-02-22 16:32:36 -0800798 }
linyuhc3968e62017-11-20 17:40:50 -0800799
800 FragmentManager dialpadFragmentManager = getDialpadFragmentManager();
801 if (dialpadFragmentManager == null) {
802 LogUtil.i("InCallActivity.showDialpadFragment", "Unable to obtain a FragmentManager");
803 return;
804 }
805
806 if (!animate) {
807 if (show) {
808 showDialpadFragment();
809 } else {
810 hideDialpadFragment();
811 }
812 } else {
813 if (show) {
814 showDialpadFragment();
815 getDialpadFragment().animateShowDialpad();
816 }
817 getDialpadFragment()
818 .getView()
819 .startAnimation(show ? dialpadSlideInAnimation : dialpadSlideOutAnimation);
820 }
821
822 ProximitySensor sensor = InCallPresenter.getInstance().getProximitySensor();
823 if (sensor != null) {
824 sensor.onDialpadVisible(show);
825 }
826 showDialpadRequest = DIALPAD_REQUEST_NONE;
827
828 // Note: onInCallScreenDialpadVisibilityChange is called here to ensure that the dialpad FAB
829 // repositions itself.
wangqifd4c9f72018-03-08 18:21:50 -0800830 getInCallOrRttCallScreen().onInCallScreenDialpadVisibilityChange(show);
linyuhc3968e62017-11-20 17:40:50 -0800831 }
832
833 private void showDialpadFragment() {
834 FragmentManager dialpadFragmentManager = getDialpadFragmentManager();
835 if (dialpadFragmentManager == null) {
836 return;
837 }
838
839 FragmentTransaction transaction = dialpadFragmentManager.beginTransaction();
840 DialpadFragment dialpadFragment = getDialpadFragment();
841 if (dialpadFragment == null) {
wangqifd4c9f72018-03-08 18:21:50 -0800842 dialpadFragment = new DialpadFragment();
843 transaction.add(getDialpadContainerId(), dialpadFragment, Tags.DIALPAD_FRAGMENT);
linyuhc3968e62017-11-20 17:40:50 -0800844 } else {
845 transaction.show(dialpadFragment);
calderwoodrad5883872017-12-12 15:29:12 -0800846 dialpadFragment.setUserVisibleHint(true);
linyuhc3968e62017-11-20 17:40:50 -0800847 }
wangqifd4c9f72018-03-08 18:21:50 -0800848 // RTT call screen doesn't show end call button inside dialpad, thus the space reserved for end
849 // call button should be removed.
850 dialpadFragment.setShouldShowEndCallSpace(didShowInCallScreen);
linyuhc3968e62017-11-20 17:40:50 -0800851 transaction.commitAllowingStateLoss();
852 dialpadFragmentManager.executePendingTransactions();
853
854 Logger.get(this).logScreenView(ScreenEvent.Type.INCALL_DIALPAD, this);
855 updateNavigationBar(true /* isDialpadVisible */);
856 }
857
858 private void hideDialpadFragment() {
859 FragmentManager dialpadFragmentManager = getDialpadFragmentManager();
860 if (dialpadFragmentManager == null) {
861 return;
862 }
863
calderwoodrad5883872017-12-12 15:29:12 -0800864 DialpadFragment dialpadFragment = getDialpadFragment();
linyuhc3968e62017-11-20 17:40:50 -0800865 if (dialpadFragment != null) {
866 FragmentTransaction transaction = dialpadFragmentManager.beginTransaction();
867 transaction.hide(dialpadFragment);
868 transaction.commitAllowingStateLoss();
869 dialpadFragmentManager.executePendingTransactions();
calderwoodrad5883872017-12-12 15:29:12 -0800870 dialpadFragment.setUserVisibleHint(false);
linyuhc3968e62017-11-20 17:40:50 -0800871 }
872 updateNavigationBar(false /* isDialpadVisible */);
Eric Erfanianccca3152017-02-22 16:32:36 -0800873 }
874
875 public boolean isDialpadVisible() {
linyuh69a25062017-11-15 16:18:51 -0800876 DialpadFragment dialpadFragment = getDialpadFragment();
calderwoodraa584bcd2018-01-24 12:19:56 -0800877 return dialpadFragment != null
878 && dialpadFragment.isAdded()
879 && !dialpadFragment.isHidden()
880 && dialpadFragment.getView() != null
881 && dialpadFragment.getUserVisibleHint();
linyuh69a25062017-11-15 16:18:51 -0800882 }
883
linyuhc3968e62017-11-20 17:40:50 -0800884 /** Returns the {@link DialpadFragment} that's shown by this activity, or {@code null} */
linyuh69a25062017-11-15 16:18:51 -0800885 @Nullable
linyuhc3968e62017-11-20 17:40:50 -0800886 private DialpadFragment getDialpadFragment() {
linyuh69a25062017-11-15 16:18:51 -0800887 FragmentManager fragmentManager = getDialpadFragmentManager();
888 if (fragmentManager == null) {
889 return null;
890 }
linyuhc3968e62017-11-20 17:40:50 -0800891 return (DialpadFragment) fragmentManager.findFragmentByTag(Tags.DIALPAD_FRAGMENT);
Eric Erfanianccca3152017-02-22 16:32:36 -0800892 }
893
894 public void onForegroundCallChanged(DialerCall newForegroundCall) {
linyuh57b093b2017-11-17 14:32:32 -0800895 updateTaskDescription();
896
897 if (newForegroundCall == null || !didShowAnswerScreen) {
Eric Erfanianccca3152017-02-22 16:32:36 -0800898 LogUtil.v("InCallActivity.onForegroundCallChanged", "resetting background color");
linyuh57b093b2017-11-17 14:32:32 -0800899 updateWindowBackgroundColor(0 /* progress */);
Eric Erfanianccca3152017-02-22 16:32:36 -0800900 }
901 }
902
linyuhc3968e62017-11-20 17:40:50 -0800903 private void updateTaskDescription() {
linyuh57b093b2017-11-17 14:32:32 -0800904 int color =
905 getResources().getBoolean(R.bool.is_layout_landscape)
906 ? ResourcesCompat.getColor(
907 getResources(), R.color.statusbar_background_color, getTheme())
908 : InCallPresenter.getInstance().getThemeColorManager().getSecondaryColor();
909 setTaskDescription(
910 new TaskDescription(
911 getResources().getString(R.string.notification_ongoing_call), null /* icon */, color));
912 }
913
Eric Erfanianccca3152017-02-22 16:32:36 -0800914 public void updateWindowBackgroundColor(@FloatRange(from = -1f, to = 1.0f) float progress) {
915 ThemeColorManager themeColorManager = InCallPresenter.getInstance().getThemeColorManager();
916 @ColorInt int top;
917 @ColorInt int middle;
918 @ColorInt int bottom;
919 @ColorInt int gray = 0x66000000;
920
linyuh437ae952018-03-26 12:46:18 -0700921 if (isInMultiWindowMode()) {
Eric Erfanianccca3152017-02-22 16:32:36 -0800922 top = themeColorManager.getBackgroundColorSolid();
923 middle = themeColorManager.getBackgroundColorSolid();
924 bottom = themeColorManager.getBackgroundColorSolid();
925 } else {
926 top = themeColorManager.getBackgroundColorTop();
927 middle = themeColorManager.getBackgroundColorMiddle();
928 bottom = themeColorManager.getBackgroundColorBottom();
929 }
930
931 if (progress < 0) {
932 float correctedProgress = Math.abs(progress);
933 top = ColorUtils.blendARGB(top, gray, correctedProgress);
934 middle = ColorUtils.blendARGB(middle, gray, correctedProgress);
935 bottom = ColorUtils.blendARGB(bottom, gray, correctedProgress);
936 }
937
938 boolean backgroundDirty = false;
939 if (backgroundDrawable == null) {
940 backgroundDrawableColors = new int[] {top, middle, bottom};
941 backgroundDrawable = new GradientDrawable(Orientation.TOP_BOTTOM, backgroundDrawableColors);
942 backgroundDirty = true;
943 } else {
944 if (backgroundDrawableColors[0] != top) {
945 backgroundDrawableColors[0] = top;
946 backgroundDirty = true;
947 }
948 if (backgroundDrawableColors[1] != middle) {
949 backgroundDrawableColors[1] = middle;
950 backgroundDirty = true;
951 }
952 if (backgroundDrawableColors[2] != bottom) {
953 backgroundDrawableColors[2] = bottom;
954 backgroundDirty = true;
955 }
956 if (backgroundDirty) {
957 backgroundDrawable.setColors(backgroundDrawableColors);
958 }
959 }
960
961 if (backgroundDirty) {
962 getWindow().setBackgroundDrawable(backgroundDrawable);
963 }
964 }
965
966 public boolean isVisible() {
967 return isVisible;
968 }
969
970 public boolean getCallCardFragmentVisible() {
erfaniand05d8992018-03-20 19:42:26 -0700971 return didShowInCallScreen
972 || didShowVideoCallScreen
973 || didShowRttCallScreen
974 || didShowSpeakEasyScreen;
Eric Erfanianccca3152017-02-22 16:32:36 -0800975 }
976
977 public void dismissKeyguard(boolean dismiss) {
linyuh9c327da2017-11-14 12:33:48 -0800978 if (dismissKeyguard == dismiss) {
979 return;
980 }
981
982 dismissKeyguard = dismiss;
983 if (dismiss) {
984 getWindow().addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);
985 } else {
986 getWindow().clearFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);
987 }
Eric Erfanianccca3152017-02-22 16:32:36 -0800988 }
989
linyuhc3968e62017-11-20 17:40:50 -0800990 public void showDialogForPostCharWait(String callId, String chars) {
991 if (isVisible) {
992 PostCharDialogFragment fragment = new PostCharDialogFragment(callId, chars);
993 fragment.show(getSupportFragmentManager(), Tags.POST_CHAR_DIALOG_FRAGMENT);
994
995 showPostCharWaitDialogOnResume = false;
996 showPostCharWaitDialogCallId = null;
997 showPostCharWaitDialogChars = null;
998 } else {
999 showPostCharWaitDialogOnResume = true;
1000 showPostCharWaitDialogCallId = callId;
1001 showPostCharWaitDialogChars = chars;
1002 }
Eric Erfanianccca3152017-02-22 16:32:36 -08001003 }
1004
linyuh7b86f562017-11-16 11:24:09 -08001005 public void showDialogOrToastForDisconnectedCall(DisconnectMessage disconnectMessage) {
1006 LogUtil.i(
1007 "InCallActivity.showDialogOrToastForDisconnectedCall",
1008 "disconnect cause: %s",
1009 disconnectMessage);
1010
1011 if (disconnectMessage.dialog == null || isFinishing()) {
1012 return;
1013 }
1014
1015 dismissPendingDialogs();
1016
1017 // Show a toast if the app is in background when a dialog can't be visible.
1018 if (!isVisible()) {
1019 Toast.makeText(getApplicationContext(), disconnectMessage.toastMessage, Toast.LENGTH_LONG)
1020 .show();
1021 return;
1022 }
1023
1024 // Show the dialog.
linyuhc3968e62017-11-20 17:40:50 -08001025 errorDialog = disconnectMessage.dialog;
linyuh7b86f562017-11-16 11:24:09 -08001026 InCallUiLock lock = InCallPresenter.getInstance().acquireInCallUiLock("showErrorDialog");
1027 disconnectMessage.dialog.setOnDismissListener(
1028 dialogInterface -> {
1029 lock.release();
1030 onDialogDismissed();
1031 });
1032 disconnectMessage.dialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
1033 disconnectMessage.dialog.show();
1034 }
1035
1036 private void onDialogDismissed() {
linyuhc3968e62017-11-20 17:40:50 -08001037 errorDialog = null;
linyuh7b86f562017-11-16 11:24:09 -08001038 CallList.getInstance().onErrorDialogDismissed();
Eric Erfanianccca3152017-02-22 16:32:36 -08001039 }
1040
1041 public void dismissPendingDialogs() {
linyuhc3968e62017-11-20 17:40:50 -08001042 LogUtil.enterBlock("InCallActivity.dismissPendingDialogs");
linyuhf99f6302017-11-15 11:23:51 -08001043
1044 if (!isVisible) {
1045 // Defer the dismissing action as the activity is not visible and onSaveInstanceState may have
1046 // been called.
Eric Erfanianccca3152017-02-22 16:32:36 -08001047 LogUtil.i(
1048 "InCallActivity.dismissPendingDialogs", "defer actions since activity is not visible");
1049 needDismissPendingDialogs = true;
linyuhf99f6302017-11-15 11:23:51 -08001050 return;
Eric Erfanianccca3152017-02-22 16:32:36 -08001051 }
linyuhf99f6302017-11-15 11:23:51 -08001052
1053 // Dismiss the error dialog
linyuhf99f6302017-11-15 11:23:51 -08001054 if (errorDialog != null) {
1055 errorDialog.dismiss();
linyuhc3968e62017-11-20 17:40:50 -08001056 errorDialog = null;
linyuhf99f6302017-11-15 11:23:51 -08001057 }
1058
1059 // Dismiss the phone account selection dialog
linyuhf99f6302017-11-15 11:23:51 -08001060 if (selectPhoneAccountDialogFragment != null) {
1061 selectPhoneAccountDialogFragment.dismiss();
linyuhc3968e62017-11-20 17:40:50 -08001062 selectPhoneAccountDialogFragment = null;
linyuhf99f6302017-11-15 11:23:51 -08001063 }
1064
1065 // Dismiss the dialog for international call on WiFi
1066 InternationalCallOnWifiDialogFragment internationalCallOnWifiFragment =
1067 (InternationalCallOnWifiDialogFragment)
linyuhc3968e62017-11-20 17:40:50 -08001068 getSupportFragmentManager().findFragmentByTag(Tags.INTERNATIONAL_CALL_ON_WIFI);
linyuhf99f6302017-11-15 11:23:51 -08001069 if (internationalCallOnWifiFragment != null) {
1070 internationalCallOnWifiFragment.dismiss();
1071 }
1072
1073 // Dismiss the answer screen
1074 AnswerScreen answerScreen = getAnswerScreen();
1075 if (answerScreen != null) {
1076 answerScreen.dismissPendingDialogs();
1077 }
1078
1079 needDismissPendingDialogs = false;
Eric Erfanianccca3152017-02-22 16:32:36 -08001080 }
1081
linyuhc3968e62017-11-20 17:40:50 -08001082 private void enableInCallOrientationEventListener(boolean enable) {
linyuh69a25062017-11-15 16:18:51 -08001083 if (enable) {
1084 inCallOrientationEventListener.enable(true /* notifyDeviceOrientationChange */);
1085 } else {
1086 inCallOrientationEventListener.disable();
1087 }
Eric Erfanianccca3152017-02-22 16:32:36 -08001088 }
1089
1090 public void setExcludeFromRecents(boolean exclude) {
linyuhc3968e62017-11-20 17:40:50 -08001091 int taskId = getTaskId();
1092
1093 List<AppTask> tasks = getSystemService(ActivityManager.class).getAppTasks();
1094 for (AppTask task : tasks) {
1095 try {
1096 if (task.getTaskInfo().id == taskId) {
1097 task.setExcludeFromRecents(exclude);
1098 }
1099 } catch (RuntimeException e) {
1100 LogUtil.e("InCallActivity.setExcludeFromRecents", "RuntimeException:\n%s", e);
1101 }
1102 }
Eric Erfanianccca3152017-02-22 16:32:36 -08001103 }
1104
Eric Erfanianccca3152017-02-22 16:32:36 -08001105 @Nullable
1106 public FragmentManager getDialpadFragmentManager() {
wangqifd4c9f72018-03-08 18:21:50 -08001107 InCallScreen inCallScreen = getInCallOrRttCallScreen();
Eric Erfanianccca3152017-02-22 16:32:36 -08001108 if (inCallScreen != null) {
1109 return inCallScreen.getInCallScreenFragment().getChildFragmentManager();
1110 }
1111 return null;
1112 }
1113
1114 public int getDialpadContainerId() {
wangqifd4c9f72018-03-08 18:21:50 -08001115 return getInCallOrRttCallScreen().getAnswerAndDialpadContainerResourceId();
Eric Erfanianccca3152017-02-22 16:32:36 -08001116 }
1117
1118 @Override
1119 public AnswerScreenDelegate newAnswerScreenDelegate(AnswerScreen answerScreen) {
1120 DialerCall call = CallList.getInstance().getCallById(answerScreen.getCallId());
1121 if (call == null) {
1122 // This is a work around for a bug where we attempt to create a new delegate after the call
1123 // has already been removed. An example of when this can happen is:
1124 // 1. incoming video call in landscape mode
1125 // 2. remote party hangs up
1126 // 3. activity switches from landscape to portrait
1127 // At step #3 the answer fragment will try to create a new answer delegate but the call won't
1128 // exist. In this case we'll simply return a stub delegate that does nothing. This is ok
1129 // because this new state is transient and the activity will be destroyed soon.
1130 LogUtil.i("InCallActivity.onPrimaryCallStateChanged", "call doesn't exist, using stub");
1131 return new AnswerScreenPresenterStub();
1132 } else {
1133 return new AnswerScreenPresenter(
1134 this, answerScreen, CallList.getInstance().getCallById(answerScreen.getCallId()));
1135 }
1136 }
1137
1138 @Override
1139 public InCallScreenDelegate newInCallScreenDelegate() {
1140 return new CallCardPresenter(this);
1141 }
1142
1143 @Override
1144 public InCallButtonUiDelegate newInCallButtonUiDelegate() {
1145 return new CallButtonPresenter(this);
1146 }
1147
1148 @Override
Eric Erfanian90508232017-03-24 09:31:16 -07001149 public VideoCallScreenDelegate newVideoCallScreenDelegate(VideoCallScreen videoCallScreen) {
1150 DialerCall dialerCall = CallList.getInstance().getCallById(videoCallScreen.getCallId());
1151 if (dialerCall != null && dialerCall.getVideoTech().shouldUseSurfaceView()) {
1152 return dialerCall.getVideoTech().createVideoCallScreenDelegate(this, videoCallScreen);
1153 }
Eric Erfanianccca3152017-02-22 16:32:36 -08001154 return new VideoCallPresenter();
1155 }
1156
1157 public void onPrimaryCallStateChanged() {
Eric Erfanian2ca43182017-08-31 06:57:16 -07001158 Trace.beginSection("InCallActivity.onPrimaryCallStateChanged");
Eric Erfanianccca3152017-02-22 16:32:36 -08001159 showMainInCallFragment();
Eric Erfanian2ca43182017-08-31 06:57:16 -07001160 Trace.endSection();
Eric Erfanianccca3152017-02-22 16:32:36 -08001161 }
1162
linyuh7b86f562017-11-16 11:24:09 -08001163 public void showToastForWiFiToLteHandover(DialerCall call) {
1164 if (call.hasShownWiFiToLteHandoverToast()) {
1165 return;
1166 }
1167
1168 Toast.makeText(this, R.string.video_call_wifi_to_lte_handover_toast, Toast.LENGTH_LONG).show();
1169 call.setHasShownWiFiToLteHandoverToast();
Eric Erfanianccca3152017-02-22 16:32:36 -08001170 }
1171
linyuh7b86f562017-11-16 11:24:09 -08001172 public void showDialogOrToastForWifiHandoverFailure(DialerCall call) {
1173 if (call.showWifiHandoverAlertAsToast()) {
1174 Toast.makeText(this, R.string.video_call_lte_to_wifi_failed_message, Toast.LENGTH_SHORT)
1175 .show();
1176 return;
1177 }
1178
1179 dismissPendingDialogs();
1180
1181 AlertDialog.Builder builder =
1182 new AlertDialog.Builder(this).setTitle(R.string.video_call_lte_to_wifi_failed_title);
1183
1184 // This allows us to use the theme of the dialog instead of the activity
1185 View dialogCheckBoxView =
1186 View.inflate(builder.getContext(), R.layout.video_call_lte_to_wifi_failed, null /* root */);
1187 CheckBox wifiHandoverFailureCheckbox =
1188 (CheckBox) dialogCheckBoxView.findViewById(R.id.video_call_lte_to_wifi_failed_checkbox);
1189 wifiHandoverFailureCheckbox.setChecked(false);
1190
1191 InCallUiLock lock = InCallPresenter.getInstance().acquireInCallUiLock("WifiFailedDialog");
linyuhc3968e62017-11-20 17:40:50 -08001192 errorDialog =
linyuh7b86f562017-11-16 11:24:09 -08001193 builder
1194 .setView(dialogCheckBoxView)
1195 .setMessage(R.string.video_call_lte_to_wifi_failed_message)
1196 .setOnCancelListener(dialogInterface -> onDialogDismissed())
1197 .setPositiveButton(
1198 android.R.string.ok,
1199 (dialogInterface, id) -> {
1200 call.setDoNotShowDialogForHandoffToWifiFailure(
1201 wifiHandoverFailureCheckbox.isChecked());
1202 dialogInterface.cancel();
1203 onDialogDismissed();
1204 })
1205 .setOnDismissListener(dialogInterface -> lock.release())
1206 .create();
linyuh7b86f562017-11-16 11:24:09 -08001207 errorDialog.show();
Eric Erfanianccca3152017-02-22 16:32:36 -08001208 }
1209
linyuh7b86f562017-11-16 11:24:09 -08001210 public void showDialogForInternationalCallOnWifi(@NonNull DialerCall call) {
1211 if (!InternationalCallOnWifiDialogFragment.shouldShow(this)) {
1212 LogUtil.i(
1213 "InCallActivity.showDialogForInternationalCallOnWifi",
1214 "InternationalCallOnWifiDialogFragment.shouldShow returned false");
1215 return;
1216 }
1217
1218 InternationalCallOnWifiDialogFragment fragment =
1219 InternationalCallOnWifiDialogFragment.newInstance(
linyuhc3968e62017-11-20 17:40:50 -08001220 call.getId(), internationalCallOnWifiCallback);
1221 fragment.show(getSupportFragmentManager(), Tags.INTERNATIONAL_CALL_ON_WIFI);
Eric Erfanianc857f902017-05-15 14:05:33 -07001222 }
1223
Eric Erfanian938468d2017-10-24 14:05:52 -07001224 @Override
1225 public void onMultiWindowModeChanged(boolean isInMultiWindowMode) {
1226 super.onMultiWindowModeChanged(isInMultiWindowMode);
linyuh57b093b2017-11-17 14:32:32 -08001227 updateNavigationBar(isDialpadVisible());
1228 }
1229
linyuhc3968e62017-11-20 17:40:50 -08001230 private void updateNavigationBar(boolean isDialpadVisible) {
linyuh437ae952018-03-26 12:46:18 -07001231 if (isInMultiWindowMode()) {
linyuh57b093b2017-11-17 14:32:32 -08001232 return;
1233 }
1234
1235 View navigationBarBackground = getWindow().findViewById(R.id.navigation_bar_background);
1236 if (navigationBarBackground != null) {
1237 navigationBarBackground.setVisibility(isDialpadVisible ? View.VISIBLE : View.GONE);
Eric Erfanian938468d2017-10-24 14:05:52 -07001238 }
1239 }
1240
Eric Erfanianccca3152017-02-22 16:32:36 -08001241 public void setAllowOrientationChange(boolean allowOrientationChange) {
wangqi9982f0d2017-10-11 17:46:07 -07001242 if (this.allowOrientationChange == allowOrientationChange) {
1243 return;
1244 }
1245 this.allowOrientationChange = allowOrientationChange;
Eric Erfanianccca3152017-02-22 16:32:36 -08001246 if (!allowOrientationChange) {
1247 setRequestedOrientation(InCallOrientationEventListener.ACTIVITY_PREFERENCE_DISALLOW_ROTATION);
1248 } else {
1249 setRequestedOrientation(InCallOrientationEventListener.ACTIVITY_PREFERENCE_ALLOW_ROTATION);
1250 }
1251 enableInCallOrientationEventListener(allowOrientationChange);
1252 }
1253
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001254 public void hideMainInCallFragment() {
linyuhc3968e62017-11-20 17:40:50 -08001255 LogUtil.enterBlock("InCallActivity.hideMainInCallFragment");
1256 if (getCallCardFragmentVisible()) {
Eric Erfanianccca3152017-02-22 16:32:36 -08001257 FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
1258 hideInCallScreenFragment(transaction);
1259 hideVideoCallScreenFragment(transaction);
1260 transaction.commitAllowingStateLoss();
1261 getSupportFragmentManager().executePendingTransactions();
1262 }
1263 }
1264
1265 private void showMainInCallFragment() {
Eric Erfanian2ca43182017-08-31 06:57:16 -07001266 Trace.beginSection("InCallActivity.showMainInCallFragment");
Eric Erfanianccca3152017-02-22 16:32:36 -08001267 // If the activity's onStart method hasn't been called yet then defer doing any work.
1268 if (!isVisible) {
1269 LogUtil.i("InCallActivity.showMainInCallFragment", "not visible yet/anymore");
Eric Erfanian2ca43182017-08-31 06:57:16 -07001270 Trace.endSection();
Eric Erfanianccca3152017-02-22 16:32:36 -08001271 return;
1272 }
1273
1274 // Don't let this be reentrant.
1275 if (isInShowMainInCallFragment) {
1276 LogUtil.i("InCallActivity.showMainInCallFragment", "already in method, bailing");
Eric Erfanian2ca43182017-08-31 06:57:16 -07001277 Trace.endSection();
Eric Erfanianccca3152017-02-22 16:32:36 -08001278 return;
1279 }
1280
1281 isInShowMainInCallFragment = true;
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001282 ShouldShowUiResult shouldShowAnswerUi = getShouldShowAnswerUi();
1283 ShouldShowUiResult shouldShowVideoUi = getShouldShowVideoUi();
wangqi219b8702018-02-13 09:34:41 -08001284 ShouldShowUiResult shouldShowRttUi = getShouldShowRttUi();
erfaniand05d8992018-03-20 19:42:26 -07001285 ShouldShowUiResult shouldShowSpeakEasyUi = getShouldShowSpeakEasyUi();
Eric Erfanianccca3152017-02-22 16:32:36 -08001286 LogUtil.i(
1287 "InCallActivity.showMainInCallFragment",
wangqi219b8702018-02-13 09:34:41 -08001288 "shouldShowAnswerUi: %b, shouldShowRttUi: %b, shouldShowVideoUi: %b "
1289 + "didShowAnswerScreen: %b, didShowInCallScreen: %b, didShowRttCallScreen: %b, "
erfaniand05d8992018-03-20 19:42:26 -07001290 + "didShowVideoCallScreen: %b"
1291 + "didShowSpeakEasyScreen: %b",
Eric Erfanianccca3152017-02-22 16:32:36 -08001292 shouldShowAnswerUi.shouldShow,
wangqi219b8702018-02-13 09:34:41 -08001293 shouldShowRttUi.shouldShow,
Eric Erfanian10b34a52017-05-04 08:23:17 -07001294 shouldShowVideoUi.shouldShow,
Eric Erfanianccca3152017-02-22 16:32:36 -08001295 didShowAnswerScreen,
1296 didShowInCallScreen,
wangqi219b8702018-02-13 09:34:41 -08001297 didShowRttCallScreen,
erfaniand05d8992018-03-20 19:42:26 -07001298 didShowVideoCallScreen,
1299 didShowSpeakEasyScreen);
Eric Erfanianccca3152017-02-22 16:32:36 -08001300 // Only video call ui allows orientation change.
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001301 setAllowOrientationChange(shouldShowVideoUi.shouldShow);
Eric Erfanianccca3152017-02-22 16:32:36 -08001302
1303 FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
wangqi219b8702018-02-13 09:34:41 -08001304 boolean didChange;
Eric Erfanianccca3152017-02-22 16:32:36 -08001305 if (shouldShowAnswerUi.shouldShow) {
wangqi219b8702018-02-13 09:34:41 -08001306 didChange = hideInCallScreenFragment(transaction);
1307 didChange |= hideVideoCallScreenFragment(transaction);
1308 didChange |= hideRttCallScreenFragment(transaction);
erfaniand05d8992018-03-20 19:42:26 -07001309 didChange |= hideSpeakEasyFragment(transaction);
wangqi219b8702018-02-13 09:34:41 -08001310 didChange |= showAnswerScreenFragment(transaction, shouldShowAnswerUi.call);
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001311 } else if (shouldShowVideoUi.shouldShow) {
wangqi219b8702018-02-13 09:34:41 -08001312 didChange = hideInCallScreenFragment(transaction);
1313 didChange |= showVideoCallScreenFragment(transaction, shouldShowVideoUi.call);
1314 didChange |= hideRttCallScreenFragment(transaction);
erfaniand05d8992018-03-20 19:42:26 -07001315 didChange |= hideSpeakEasyFragment(transaction);
wangqi219b8702018-02-13 09:34:41 -08001316 didChange |= hideAnswerScreenFragment(transaction);
1317 } else if (shouldShowRttUi.shouldShow) {
1318 didChange = hideInCallScreenFragment(transaction);
1319 didChange |= hideVideoCallScreenFragment(transaction);
1320 didChange |= hideAnswerScreenFragment(transaction);
erfaniand05d8992018-03-20 19:42:26 -07001321 didChange |= hideSpeakEasyFragment(transaction);
wangqi219b8702018-02-13 09:34:41 -08001322 didChange |= showRttCallScreenFragment(transaction, shouldShowRttUi.call);
erfaniand05d8992018-03-20 19:42:26 -07001323 } else if (shouldShowSpeakEasyUi.shouldShow) {
1324 didChange = hideInCallScreenFragment(transaction);
1325 didChange |= hideVideoCallScreenFragment(transaction);
1326 didChange |= hideAnswerScreenFragment(transaction);
1327 didChange |= hideRttCallScreenFragment(transaction);
1328 didChange |= showSpeakEasyFragment(transaction, shouldShowSpeakEasyUi.call);
Eric Erfanianccca3152017-02-22 16:32:36 -08001329 } else {
wangqi219b8702018-02-13 09:34:41 -08001330 didChange = showInCallScreenFragment(transaction);
1331 didChange |= hideVideoCallScreenFragment(transaction);
1332 didChange |= hideRttCallScreenFragment(transaction);
erfaniand05d8992018-03-20 19:42:26 -07001333 didChange |= hideSpeakEasyFragment(transaction);
wangqi219b8702018-02-13 09:34:41 -08001334 didChange |= hideAnswerScreenFragment(transaction);
Eric Erfanianccca3152017-02-22 16:32:36 -08001335 }
1336
wangqi219b8702018-02-13 09:34:41 -08001337 if (didChange) {
Eric Erfanian2ca43182017-08-31 06:57:16 -07001338 Trace.beginSection("InCallActivity.commitTransaction");
Eric Erfanianccca3152017-02-22 16:32:36 -08001339 transaction.commitNow();
Eric Erfanian2ca43182017-08-31 06:57:16 -07001340 Trace.endSection();
Eric Erfanianccca3152017-02-22 16:32:36 -08001341 Logger.get(this).logScreenView(ScreenEvent.Type.INCALL, this);
1342 }
1343 isInShowMainInCallFragment = false;
Eric Erfanian2ca43182017-08-31 06:57:16 -07001344 Trace.endSection();
Eric Erfanianccca3152017-02-22 16:32:36 -08001345 }
1346
erfaniand05d8992018-03-20 19:42:26 -07001347 private boolean showSpeakEasyFragment(FragmentTransaction transaction, DialerCall call) {
1348
1349 // TODO(erfanian): Support multiple speakeasy screens.
1350 if (didShowSpeakEasyScreen) {
1351 return false;
1352 }
1353
1354 Optional<Fragment> speakEasyFragment = speakEasyCallManager.getSpeakEasyFragment(call);
1355 if (speakEasyFragment.isPresent()) {
1356 transaction.add(R.id.main, speakEasyFragment.get(), Tags.SPEAK_EASY_SCREEN);
1357 didShowSpeakEasyScreen = true;
1358 return true;
1359 }
1360 return false;
1361 }
1362
1363 private Fragment getSpeakEasyScreen() {
1364 return getSupportFragmentManager().findFragmentByTag(Tags.SPEAK_EASY_SCREEN);
1365 }
1366
1367 private boolean hideSpeakEasyFragment(FragmentTransaction transaction) {
1368 if (!didShowSpeakEasyScreen) {
1369 return false;
1370 }
1371
1372 Fragment speakEasyFragment = getSpeakEasyScreen();
1373
1374 if (speakEasyFragment != null) {
1375 transaction.remove(speakEasyFragment);
1376 didShowSpeakEasyScreen = false;
1377 return true;
1378 }
1379 return false;
1380 }
1381
1382 public void setSpeakEasyCallManager(SpeakEasyCallManager speakEasyCallManager) {
1383 this.speakEasyCallManager = Assert.isNotNull(speakEasyCallManager);
1384 }
1385
1386 public SpeakEasyCallManager getSpeakEasyCallManager() {
1387 return speakEasyCallManager;
1388 }
1389
1390 private ShouldShowUiResult getShouldShowSpeakEasyUi() {
1391 SpeakEasyCallManager speakEasyCallManager = getSpeakEasyCallManager();
1392
1393 if (speakEasyCallManager == null) {
1394 return new ShouldShowUiResult(false, null);
1395 }
1396
1397 // TODO(erfanian): Get a better call?
1398 DialerCall call = CallList.getInstance().getActiveCall();
1399
1400 if (call == null) {
1401 return new ShouldShowUiResult(false, call);
1402 }
1403
1404 if (!call.isSpeakEasyCall() || !call.isSpeakEasyEligible()) {
1405 return new ShouldShowUiResult(false, call);
1406 }
1407
1408 Optional<Fragment> speakEasyFragment = speakEasyCallManager.getSpeakEasyFragment(call);
1409
1410 if (!speakEasyFragment.isPresent()) {
1411 return new ShouldShowUiResult(false, call);
1412 }
1413 return new ShouldShowUiResult(true, call);
1414 }
1415
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001416 private ShouldShowUiResult getShouldShowAnswerUi() {
Eric Erfanianccca3152017-02-22 16:32:36 -08001417 DialerCall call = CallList.getInstance().getIncomingCall();
1418 if (call != null) {
1419 LogUtil.i("InCallActivity.getShouldShowAnswerUi", "found incoming call");
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001420 return new ShouldShowUiResult(true, call);
Eric Erfanianccca3152017-02-22 16:32:36 -08001421 }
1422
1423 call = CallList.getInstance().getVideoUpgradeRequestCall();
1424 if (call != null) {
1425 LogUtil.i("InCallActivity.getShouldShowAnswerUi", "found video upgrade request");
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001426 return new ShouldShowUiResult(true, call);
Eric Erfanianccca3152017-02-22 16:32:36 -08001427 }
1428
1429 // Check if we're showing the answer screen and the call is disconnected. If this condition is
1430 // true then we won't switch from the answer UI to the in call UI. This prevents flicker when
1431 // the user rejects an incoming call.
1432 call = CallList.getInstance().getFirstCall();
1433 if (call == null) {
1434 call = CallList.getInstance().getBackgroundCall();
1435 }
1436 if (didShowAnswerScreen && (call == null || call.getState() == State.DISCONNECTED)) {
1437 LogUtil.i("InCallActivity.getShouldShowAnswerUi", "found disconnecting incoming call");
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001438 return new ShouldShowUiResult(true, call);
Eric Erfanianccca3152017-02-22 16:32:36 -08001439 }
1440
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001441 return new ShouldShowUiResult(false, null);
Eric Erfanianccca3152017-02-22 16:32:36 -08001442 }
1443
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001444 private static ShouldShowUiResult getShouldShowVideoUi() {
Eric Erfanianccca3152017-02-22 16:32:36 -08001445 DialerCall call = CallList.getInstance().getFirstCall();
1446 if (call == null) {
1447 LogUtil.i("InCallActivity.getShouldShowVideoUi", "null call");
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001448 return new ShouldShowUiResult(false, null);
Eric Erfanianccca3152017-02-22 16:32:36 -08001449 }
1450
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001451 if (call.isVideoCall()) {
Eric Erfanianccca3152017-02-22 16:32:36 -08001452 LogUtil.i("InCallActivity.getShouldShowVideoUi", "found video call");
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001453 return new ShouldShowUiResult(true, call);
Eric Erfanianccca3152017-02-22 16:32:36 -08001454 }
1455
linyuh8fbecce2017-12-18 13:53:09 -08001456 if (call.hasSentVideoUpgradeRequest() || call.hasReceivedVideoUpgradeRequest()) {
Eric Erfanianccca3152017-02-22 16:32:36 -08001457 LogUtil.i("InCallActivity.getShouldShowVideoUi", "upgrading to video");
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001458 return new ShouldShowUiResult(true, call);
Eric Erfanianccca3152017-02-22 16:32:36 -08001459 }
1460
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001461 return new ShouldShowUiResult(false, null);
Eric Erfanianccca3152017-02-22 16:32:36 -08001462 }
1463
wangqi219b8702018-02-13 09:34:41 -08001464 private static ShouldShowUiResult getShouldShowRttUi() {
1465 DialerCall call = CallList.getInstance().getFirstCall();
1466 if (call == null) {
1467 LogUtil.i("InCallActivity.getShouldShowRttUi", "null call");
1468 return new ShouldShowUiResult(false, null);
1469 }
1470
wangqif6be6172018-03-30 15:57:56 -07001471 if (call.isActiveRttCall()) {
wangqi219b8702018-02-13 09:34:41 -08001472 LogUtil.i("InCallActivity.getShouldShowRttUi", "found rtt call");
1473 return new ShouldShowUiResult(true, call);
1474 }
1475
1476 if (call.hasSentRttUpgradeRequest()) {
1477 LogUtil.i("InCallActivity.getShouldShowRttUi", "upgrading to rtt");
1478 return new ShouldShowUiResult(true, call);
1479 }
1480
1481 return new ShouldShowUiResult(false, null);
1482 }
1483
Eric Erfanianccca3152017-02-22 16:32:36 -08001484 private boolean showAnswerScreenFragment(FragmentTransaction transaction, DialerCall call) {
1485 // When rejecting a call the active call can become null in which case we should continue
1486 // showing the answer screen.
1487 if (didShowAnswerScreen && call == null) {
1488 return false;
1489 }
1490
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001491 Assert.checkArgument(call != null, "didShowAnswerScreen was false but call was still null");
1492
1493 boolean isVideoUpgradeRequest = call.hasReceivedVideoUpgradeRequest();
Eric Erfanianccca3152017-02-22 16:32:36 -08001494
1495 // Check if we're already showing an answer screen for this call.
1496 if (didShowAnswerScreen) {
1497 AnswerScreen answerScreen = getAnswerScreen();
1498 if (answerScreen.getCallId().equals(call.getId())
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001499 && answerScreen.isVideoCall() == call.isVideoCall()
Eric Erfanian2ca43182017-08-31 06:57:16 -07001500 && answerScreen.isVideoUpgradeRequest() == isVideoUpgradeRequest
1501 && !answerScreen.isActionTimeout()) {
1502 LogUtil.d(
1503 "InCallActivity.showAnswerScreenFragment",
1504 "answer fragment exists for same call and has NOT been accepted/rejected/timed out");
Eric Erfanianccca3152017-02-22 16:32:36 -08001505 return false;
1506 }
Eric Erfanian2ca43182017-08-31 06:57:16 -07001507 if (answerScreen.isActionTimeout()) {
1508 LogUtil.i(
1509 "InCallActivity.showAnswerScreenFragment",
1510 "answer fragment exists but has been accepted/rejected and timed out");
1511 } else {
1512 LogUtil.i(
1513 "InCallActivity.showAnswerScreenFragment",
1514 "answer fragment exists but arguments do not match");
1515 }
Eric Erfanianccca3152017-02-22 16:32:36 -08001516 hideAnswerScreenFragment(transaction);
1517 }
1518
1519 // Show a new answer screen.
1520 AnswerScreen answerScreen =
Eric Erfanianfc37b022017-03-21 10:11:17 -07001521 AnswerBindings.createAnswerScreen(
1522 call.getId(),
wangqif6be6172018-03-30 15:57:56 -07001523 call.isActiveRttCall(),
Eric Erfanianfc37b022017-03-21 10:11:17 -07001524 call.isVideoCall(),
1525 isVideoUpgradeRequest,
Eric Erfanian90508232017-03-24 09:31:16 -07001526 call.getVideoTech().isSelfManagedCamera(),
1527 shouldAllowAnswerAndRelease(call),
erfaniand05d8992018-03-20 19:42:26 -07001528 CallList.getInstance().getBackgroundCall() != null,
1529 call.isSpeakEasyEligible());
linyuhc3968e62017-11-20 17:40:50 -08001530 transaction.add(R.id.main, answerScreen.getAnswerScreenFragment(), Tags.ANSWER_SCREEN);
Eric Erfanianccca3152017-02-22 16:32:36 -08001531
1532 Logger.get(this).logScreenView(ScreenEvent.Type.INCOMING_CALL, this);
1533 didShowAnswerScreen = true;
1534 return true;
1535 }
1536
Eric Erfanian90508232017-03-24 09:31:16 -07001537 private boolean shouldAllowAnswerAndRelease(DialerCall call) {
1538 if (CallList.getInstance().getActiveCall() == null) {
1539 LogUtil.i("InCallActivity.shouldAllowAnswerAndRelease", "no active call");
1540 return false;
1541 }
1542 if (getSystemService(TelephonyManager.class).getPhoneType()
1543 == TelephonyManager.PHONE_TYPE_CDMA) {
1544 LogUtil.i("InCallActivity.shouldAllowAnswerAndRelease", "PHONE_TYPE_CDMA not supported");
1545 return false;
1546 }
1547 if (call.isVideoCall() || call.hasReceivedVideoUpgradeRequest()) {
1548 LogUtil.i("InCallActivity.shouldAllowAnswerAndRelease", "video call");
1549 return false;
1550 }
linyuhc3968e62017-11-20 17:40:50 -08001551 if (!ConfigProviderBindings.get(this)
1552 .getBoolean(ConfigNames.ANSWER_AND_RELEASE_ENABLED, true)) {
Eric Erfanian90508232017-03-24 09:31:16 -07001553 LogUtil.i("InCallActivity.shouldAllowAnswerAndRelease", "disabled by config");
1554 return false;
1555 }
1556
1557 return true;
1558 }
1559
Eric Erfanianccca3152017-02-22 16:32:36 -08001560 private boolean hideAnswerScreenFragment(FragmentTransaction transaction) {
1561 if (!didShowAnswerScreen) {
1562 return false;
1563 }
1564 AnswerScreen answerScreen = getAnswerScreen();
1565 if (answerScreen != null) {
1566 transaction.remove(answerScreen.getAnswerScreenFragment());
1567 }
1568
1569 didShowAnswerScreen = false;
1570 return true;
1571 }
1572
1573 private boolean showInCallScreenFragment(FragmentTransaction transaction) {
1574 if (didShowInCallScreen) {
1575 return false;
1576 }
Eric Erfanian2ca43182017-08-31 06:57:16 -07001577 InCallScreen inCallScreen = InCallBindings.createInCallScreen();
linyuhc3968e62017-11-20 17:40:50 -08001578 transaction.add(R.id.main, inCallScreen.getInCallScreenFragment(), Tags.IN_CALL_SCREEN);
Eric Erfanianccca3152017-02-22 16:32:36 -08001579 Logger.get(this).logScreenView(ScreenEvent.Type.INCALL, this);
1580 didShowInCallScreen = true;
1581 return true;
1582 }
1583
1584 private boolean hideInCallScreenFragment(FragmentTransaction transaction) {
1585 if (!didShowInCallScreen) {
1586 return false;
1587 }
1588 InCallScreen inCallScreen = getInCallScreen();
1589 if (inCallScreen != null) {
Eric Erfanian2ca43182017-08-31 06:57:16 -07001590 transaction.remove(inCallScreen.getInCallScreenFragment());
Eric Erfanianccca3152017-02-22 16:32:36 -08001591 }
1592 didShowInCallScreen = false;
1593 return true;
1594 }
1595
wangqi219b8702018-02-13 09:34:41 -08001596 private boolean showRttCallScreenFragment(FragmentTransaction transaction, DialerCall call) {
1597 if (didShowRttCallScreen) {
1598 // This shouldn't happen since only one RTT call is allow at same time.
1599 if (!getRttCallScreen().getCallId().equals(call.getId())) {
1600 LogUtil.e("InCallActivity.showRttCallScreenFragment", "RTT call id doesn't match");
1601 }
1602 return false;
1603 }
1604 RttCallScreen rttCallScreen = RttBindings.createRttCallScreen(call.getId());
1605 transaction.add(R.id.main, rttCallScreen.getRttCallScreenFragment(), Tags.RTT_CALL_SCREEN);
1606 Logger.get(this).logScreenView(ScreenEvent.Type.INCALL, this);
1607 didShowRttCallScreen = true;
1608 return true;
1609 }
1610
1611 private boolean hideRttCallScreenFragment(FragmentTransaction transaction) {
1612 if (!didShowRttCallScreen) {
1613 return false;
1614 }
1615 RttCallScreen rttCallScreen = getRttCallScreen();
1616 if (rttCallScreen != null) {
1617 transaction.remove(rttCallScreen.getRttCallScreenFragment());
1618 }
1619 didShowRttCallScreen = false;
1620 return true;
1621 }
1622
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001623 private boolean showVideoCallScreenFragment(FragmentTransaction transaction, DialerCall call) {
Eric Erfanianccca3152017-02-22 16:32:36 -08001624 if (didShowVideoCallScreen) {
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001625 VideoCallScreen videoCallScreen = getVideoCallScreen();
1626 if (videoCallScreen.getCallId().equals(call.getId())) {
1627 return false;
1628 }
1629 LogUtil.i(
1630 "InCallActivity.showVideoCallScreenFragment",
1631 "video call fragment exists but arguments do not match");
1632 hideVideoCallScreenFragment(transaction);
Eric Erfanianccca3152017-02-22 16:32:36 -08001633 }
1634
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001635 LogUtil.i("InCallActivity.showVideoCallScreenFragment", "call: %s", call);
1636
Eric Erfanian90508232017-03-24 09:31:16 -07001637 VideoCallScreen videoCallScreen =
1638 VideoBindings.createVideoCallScreen(
1639 call.getId(), call.getVideoTech().shouldUseSurfaceView());
linyuhc3968e62017-11-20 17:40:50 -08001640 transaction.add(
1641 R.id.main, videoCallScreen.getVideoCallScreenFragment(), Tags.VIDEO_CALL_SCREEN);
Eric Erfanianccca3152017-02-22 16:32:36 -08001642
1643 Logger.get(this).logScreenView(ScreenEvent.Type.INCALL, this);
1644 didShowVideoCallScreen = true;
1645 return true;
1646 }
1647
1648 private boolean hideVideoCallScreenFragment(FragmentTransaction transaction) {
1649 if (!didShowVideoCallScreen) {
1650 return false;
1651 }
1652 VideoCallScreen videoCallScreen = getVideoCallScreen();
1653 if (videoCallScreen != null) {
1654 transaction.remove(videoCallScreen.getVideoCallScreenFragment());
1655 }
1656 didShowVideoCallScreen = false;
1657 return true;
1658 }
1659
linyuhc3968e62017-11-20 17:40:50 -08001660 private AnswerScreen getAnswerScreen() {
1661 return (AnswerScreen) getSupportFragmentManager().findFragmentByTag(Tags.ANSWER_SCREEN);
Eric Erfanianccca3152017-02-22 16:32:36 -08001662 }
1663
linyuhc3968e62017-11-20 17:40:50 -08001664 private InCallScreen getInCallScreen() {
1665 return (InCallScreen) getSupportFragmentManager().findFragmentByTag(Tags.IN_CALL_SCREEN);
Eric Erfanianccca3152017-02-22 16:32:36 -08001666 }
1667
linyuhc3968e62017-11-20 17:40:50 -08001668 private VideoCallScreen getVideoCallScreen() {
1669 return (VideoCallScreen) getSupportFragmentManager().findFragmentByTag(Tags.VIDEO_CALL_SCREEN);
Eric Erfanianccca3152017-02-22 16:32:36 -08001670 }
1671
wangqi219b8702018-02-13 09:34:41 -08001672 private RttCallScreen getRttCallScreen() {
1673 return (RttCallScreen) getSupportFragmentManager().findFragmentByTag(Tags.RTT_CALL_SCREEN);
1674 }
1675
wangqifd4c9f72018-03-08 18:21:50 -08001676 private InCallScreen getInCallOrRttCallScreen() {
1677 InCallScreen inCallScreen = null;
1678 if (didShowInCallScreen) {
1679 inCallScreen = getInCallScreen();
1680 }
1681 if (didShowRttCallScreen) {
1682 inCallScreen = getRttCallScreen();
1683 }
1684 return inCallScreen;
1685 }
1686
Eric Erfanianccca3152017-02-22 16:32:36 -08001687 @Override
1688 public void onPseudoScreenStateChanged(boolean isOn) {
1689 LogUtil.i("InCallActivity.onPseudoScreenStateChanged", "isOn: " + isOn);
1690 pseudoBlackScreenOverlay.setVisibility(isOn ? View.GONE : View.VISIBLE);
1691 }
1692
1693 /**
1694 * For some touch related issue, turning off the screen can be faked by drawing a black view over
1695 * the activity. All touch events started when the screen is "off" is rejected.
1696 *
1697 * @see PseudoScreenState
1698 */
1699 @Override
1700 public boolean dispatchTouchEvent(MotionEvent event) {
1701 // Reject any gesture that started when the screen is in the fake off state.
1702 if (touchDownWhenPseudoScreenOff) {
1703 if (event.getAction() == MotionEvent.ACTION_UP) {
1704 touchDownWhenPseudoScreenOff = false;
1705 }
1706 return true;
1707 }
1708 // Reject all touch event when the screen is in the fake off state.
1709 if (!InCallPresenter.getInstance().getPseudoScreenState().isOn()) {
1710 if (event.getAction() == MotionEvent.ACTION_DOWN) {
1711 touchDownWhenPseudoScreenOff = true;
1712 LogUtil.i("InCallActivity.dispatchTouchEvent", "touchDownWhenPseudoScreenOff");
1713 }
1714 return true;
1715 }
1716 return super.dispatchTouchEvent(event);
1717 }
1718
wangqi219b8702018-02-13 09:34:41 -08001719 @Override
1720 public RttCallScreenDelegate newRttCallScreenDelegate(RttCallScreen videoCallScreen) {
1721 return new RttCallPresenter();
1722 }
1723
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001724 private static class ShouldShowUiResult {
Eric Erfanianccca3152017-02-22 16:32:36 -08001725 public final boolean shouldShow;
1726 public final DialerCall call;
1727
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001728 ShouldShowUiResult(boolean shouldShow, DialerCall call) {
Eric Erfanianccca3152017-02-22 16:32:36 -08001729 this.shouldShow = shouldShow;
1730 this.call = call;
1731 }
1732 }
linyuhc3968e62017-11-20 17:40:50 -08001733
1734 private static final class IntentExtraNames {
1735 static final String FOR_FULL_SCREEN = "InCallActivity.for_full_screen_intent";
1736 static final String NEW_OUTGOING_CALL = "InCallActivity.new_outgoing_call";
1737 static final String SHOW_DIALPAD = "InCallActivity.show_dialpad";
1738 }
1739
1740 private static final class KeysForSavedInstance {
1741 static final String DIALPAD_TEXT = "InCallActivity.dialpad_text";
1742 static final String DID_SHOW_ANSWER_SCREEN = "did_show_answer_screen";
1743 static final String DID_SHOW_IN_CALL_SCREEN = "did_show_in_call_screen";
1744 static final String DID_SHOW_VIDEO_CALL_SCREEN = "did_show_video_call_screen";
wangqi153af2f2018-02-15 16:21:49 -08001745 static final String DID_SHOW_RTT_CALL_SCREEN = "did_show_rtt_call_screen";
erfaniand05d8992018-03-20 19:42:26 -07001746 static final String DID_SHOW_SPEAK_EASY_SCREEN = "did_show_speak_easy_screen";
linyuhc3968e62017-11-20 17:40:50 -08001747 }
1748
1749 /** Request codes for pending intents. */
1750 public static final class PendingIntentRequestCodes {
1751 static final int NON_FULL_SCREEN = 0;
1752 static final int FULL_SCREEN = 1;
1753 static final int BUBBLE = 2;
1754 }
1755
1756 private static final class Tags {
1757 static final String ANSWER_SCREEN = "tag_answer_screen";
1758 static final String DIALPAD_FRAGMENT = "tag_dialpad_fragment";
1759 static final String IN_CALL_SCREEN = "tag_in_call_screen";
1760 static final String INTERNATIONAL_CALL_ON_WIFI = "tag_international_call_on_wifi";
1761 static final String SELECT_ACCOUNT_FRAGMENT = "tag_select_account_fragment";
1762 static final String VIDEO_CALL_SCREEN = "tag_video_call_screen";
wangqi219b8702018-02-13 09:34:41 -08001763 static final String RTT_CALL_SCREEN = "tag_rtt_call_screen";
linyuhc3968e62017-11-20 17:40:50 -08001764 static final String POST_CHAR_DIALOG_FRAGMENT = "tag_post_char_dialog_fragment";
erfaniand05d8992018-03-20 19:42:26 -07001765 static final String SPEAK_EASY_SCREEN = "tag_speak_easy_screen";
linyuhc3968e62017-11-20 17:40:50 -08001766 }
1767
1768 private static final class ConfigNames {
1769 static final String ANSWER_AND_RELEASE_ENABLED = "answer_and_release_enabled";
1770 }
1771
1772 private static final class InternationalCallOnWifiCallback
1773 implements InternationalCallOnWifiDialogFragment.Callback {
1774 private static final String TAG = InternationalCallOnWifiCallback.class.getCanonicalName();
1775
1776 @Override
1777 public void continueCall(@NonNull String callId) {
1778 LogUtil.i(TAG, "Continuing call with ID: %s", callId);
1779 }
1780
1781 @Override
1782 public void cancelCall(@NonNull String callId) {
1783 DialerCall call = CallList.getInstance().getCallById(callId);
1784 if (call == null) {
1785 LogUtil.i(TAG, "Call destroyed before the dialog is closed");
1786 return;
1787 }
1788
1789 LogUtil.i(TAG, "Disconnecting international call on WiFi");
1790 call.disconnect();
1791 }
1792 }
1793
1794 private static final class SelectPhoneAccountListener
1795 extends SelectPhoneAccountDialogFragment.SelectPhoneAccountListener {
1796 private static final String TAG = SelectPhoneAccountListener.class.getCanonicalName();
1797
twyen73a74c32018-03-07 12:12:24 -08001798 private final Context appContext;
1799
1800 SelectPhoneAccountListener(Context appContext) {
1801 this.appContext = appContext;
1802 }
1803
linyuhc3968e62017-11-20 17:40:50 -08001804 @Override
1805 public void onPhoneAccountSelected(
1806 PhoneAccountHandle selectedAccountHandle, boolean setDefault, String callId) {
1807 DialerCall call = CallList.getInstance().getCallById(callId);
1808 LogUtil.i(TAG, "Phone account select with call:\n%s", call);
1809
1810 if (call != null) {
twyen73a74c32018-03-07 12:12:24 -08001811 call.phoneAccountSelected(selectedAccountHandle, false);
1812 if (call.getPreferredAccountRecorder() != null) {
1813 call.getPreferredAccountRecorder().record(appContext, selectedAccountHandle, setDefault);
1814 }
linyuhc3968e62017-11-20 17:40:50 -08001815 }
1816 }
1817
1818 @Override
1819 public void onDialogDismissed(String callId) {
1820 DialerCall call = CallList.getInstance().getCallById(callId);
1821 LogUtil.i(TAG, "Disconnecting call:\n%s" + call);
1822
1823 if (call != null) {
1824 call.disconnect();
1825 }
1826 }
1827 }
Eric Erfanianccca3152017-02-22 16:32:36 -08001828}