blob: 65ef323fe4ee3ae868e9c7475381ab534915e6c3 [file] [log] [blame]
Eric Erfanianccca3152017-02-22 16:32:36 -08001/*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.incallui;
18
linyuhc3968e62017-11-20 17:40:50 -080019import android.app.ActivityManager;
20import android.app.ActivityManager.AppTask;
linyuh57b093b2017-11-17 14:32:32 -080021import android.app.ActivityManager.TaskDescription;
linyuh7b86f562017-11-16 11:24:09 -080022import android.app.AlertDialog;
linyuhf99f6302017-11-15 11:23:51 -080023import android.app.Dialog;
linyuh57b093b2017-11-17 14:32:32 -080024import android.app.KeyguardManager;
Eric Erfanianccca3152017-02-22 16:32:36 -080025import android.content.Context;
26import android.content.Intent;
linyuhc3968e62017-11-20 17:40:50 -080027import android.content.res.Configuration;
Eric Erfanianccca3152017-02-22 16:32:36 -080028import android.graphics.drawable.GradientDrawable;
29import android.graphics.drawable.GradientDrawable.Orientation;
30import android.os.Bundle;
Eric Erfanian2ca43182017-08-31 06:57:16 -070031import android.os.Trace;
Eric Erfanianccca3152017-02-22 16:32:36 -080032import android.support.annotation.ColorInt;
33import android.support.annotation.FloatRange;
linyuhc3968e62017-11-20 17:40:50 -080034import android.support.annotation.IntDef;
Eric Erfanianc857f902017-05-15 14:05:33 -070035import android.support.annotation.NonNull;
Eric Erfanianccca3152017-02-22 16:32:36 -080036import android.support.annotation.Nullable;
linyuhc3968e62017-11-20 17:40:50 -080037import android.support.annotation.VisibleForTesting;
wangqibc28ea72018-04-02 16:23:00 -070038import android.support.v4.app.DialogFragment;
erfaniand05d8992018-03-20 19:42:26 -070039import android.support.v4.app.Fragment;
Eric Erfanianccca3152017-02-22 16:32:36 -080040import android.support.v4.app.FragmentManager;
41import android.support.v4.app.FragmentTransaction;
linyuh57b093b2017-11-17 14:32:32 -080042import android.support.v4.content.res.ResourcesCompat;
Eric Erfanianccca3152017-02-22 16:32:36 -080043import android.support.v4.graphics.ColorUtils;
twyen73a74c32018-03-07 12:12:24 -080044import android.telecom.Call;
linyuhc3968e62017-11-20 17:40:50 -080045import android.telecom.CallAudioState;
46import android.telecom.PhoneAccountHandle;
Eric Erfanian90508232017-03-24 09:31:16 -070047import android.telephony.TelephonyManager;
Eric Erfanianccca3152017-02-22 16:32:36 -080048import android.view.KeyEvent;
49import android.view.MenuItem;
50import android.view.MotionEvent;
51import android.view.View;
linyuh9c327da2017-11-14 12:33:48 -080052import android.view.WindowManager;
linyuhc3968e62017-11-20 17:40:50 -080053import android.view.animation.Animation;
54import android.view.animation.AnimationUtils;
linyuh7b86f562017-11-16 11:24:09 -080055import android.widget.CheckBox;
56import android.widget.Toast;
linyuhf99f6302017-11-15 11:23:51 -080057import com.android.contacts.common.widget.SelectPhoneAccountDialogFragment;
linyuhc3968e62017-11-20 17:40:50 -080058import com.android.dialer.animation.AnimUtils;
59import com.android.dialer.animation.AnimationListenerAdapter;
Eric Erfaniand5e47f62017-03-15 14:41:07 -070060import com.android.dialer.common.Assert;
Eric Erfanianccca3152017-02-22 16:32:36 -080061import com.android.dialer.common.LogUtil;
twyen73a74c32018-03-07 12:12:24 -080062import com.android.dialer.common.concurrent.DialerExecutorComponent;
weijiaxu650e7cc2017-10-31 12:38:54 -070063import com.android.dialer.common.concurrent.ThreadUtil;
Eric Erfanian2ca43182017-08-31 06:57:16 -070064import com.android.dialer.configprovider.ConfigProviderBindings;
twyen73a74c32018-03-07 12:12:24 -080065import com.android.dialer.logging.DialerImpression.Type;
Eric Erfanianccca3152017-02-22 16:32:36 -080066import com.android.dialer.logging.Logger;
Eric Erfanian8369df02017-05-03 10:27:13 -070067import com.android.dialer.logging.ScreenEvent;
zachh7a96dc72018-02-20 22:16:03 -080068import com.android.dialer.metrics.Metrics;
69import com.android.dialer.metrics.MetricsComponent;
twyen73a74c32018-03-07 12:12:24 -080070import com.android.dialer.preferredsim.PreferredAccountRecorder;
71import com.android.dialer.preferredsim.PreferredAccountWorker;
72import com.android.dialer.preferredsim.suggestion.SuggestionProvider;
linyuhc3968e62017-11-20 17:40:50 -080073import com.android.dialer.util.ViewUtil;
Eric Erfanianccca3152017-02-22 16:32:36 -080074import com.android.incallui.answer.bindings.AnswerBindings;
75import com.android.incallui.answer.protocol.AnswerScreen;
76import com.android.incallui.answer.protocol.AnswerScreenDelegate;
77import com.android.incallui.answer.protocol.AnswerScreenDelegateFactory;
78import com.android.incallui.answerproximitysensor.PseudoScreenState;
linyuh57b093b2017-11-17 14:32:32 -080079import com.android.incallui.audiomode.AudioModeProvider;
Eric Erfanianccca3152017-02-22 16:32:36 -080080import com.android.incallui.call.CallList;
81import com.android.incallui.call.DialerCall;
82import com.android.incallui.call.DialerCall.State;
linyuh57b093b2017-11-17 14:32:32 -080083import com.android.incallui.call.TelecomAdapter;
Eric Erfanian2ca43182017-08-31 06:57:16 -070084import com.android.incallui.callpending.CallPendingActivity;
85import com.android.incallui.disconnectdialog.DisconnectMessage;
Eric Erfanianccca3152017-02-22 16:32:36 -080086import com.android.incallui.incall.bindings.InCallBindings;
87import com.android.incallui.incall.protocol.InCallButtonUiDelegate;
88import com.android.incallui.incall.protocol.InCallButtonUiDelegateFactory;
89import com.android.incallui.incall.protocol.InCallScreen;
90import com.android.incallui.incall.protocol.InCallScreenDelegate;
91import com.android.incallui.incall.protocol.InCallScreenDelegateFactory;
linyuh7b86f562017-11-16 11:24:09 -080092import com.android.incallui.incalluilock.InCallUiLock;
wangqi219b8702018-02-13 09:34:41 -080093import com.android.incallui.rtt.bindings.RttBindings;
94import com.android.incallui.rtt.protocol.RttCallScreen;
95import com.android.incallui.rtt.protocol.RttCallScreenDelegate;
96import com.android.incallui.rtt.protocol.RttCallScreenDelegateFactory;
erfaniand05d8992018-03-20 19:42:26 -070097import com.android.incallui.speakeasy.SpeakEasyCallManager;
linyuhf99f6302017-11-15 11:23:51 -080098import com.android.incallui.telecomeventui.InternationalCallOnWifiDialogFragment;
Eric Erfanianccca3152017-02-22 16:32:36 -080099import com.android.incallui.video.bindings.VideoBindings;
100import com.android.incallui.video.protocol.VideoCallScreen;
101import com.android.incallui.video.protocol.VideoCallScreenDelegate;
102import com.android.incallui.video.protocol.VideoCallScreenDelegateFactory;
linyuhc3968e62017-11-20 17:40:50 -0800103import com.google.common.base.Optional;
104import java.lang.annotation.Retention;
105import java.lang.annotation.RetentionPolicy;
106import java.util.ArrayList;
107import java.util.List;
Eric Erfanianccca3152017-02-22 16:32:36 -0800108
109/** Version of {@link InCallActivity} that shows the new UI */
110public class InCallActivity extends TransactionSafeFragmentActivity
111 implements AnswerScreenDelegateFactory,
112 InCallScreenDelegateFactory,
113 InCallButtonUiDelegateFactory,
114 VideoCallScreenDelegateFactory,
wangqi219b8702018-02-13 09:34:41 -0800115 RttCallScreenDelegateFactory,
Eric Erfanianccca3152017-02-22 16:32:36 -0800116 PseudoScreenState.StateChangedListener {
117
linyuhc3968e62017-11-20 17:40:50 -0800118 @Retention(RetentionPolicy.SOURCE)
119 @IntDef({
120 DIALPAD_REQUEST_NONE,
121 DIALPAD_REQUEST_SHOW,
122 DIALPAD_REQUEST_HIDE,
123 })
124 @interface DialpadRequestType {}
Eric Erfanian2ca43182017-08-31 06:57:16 -0700125
linyuhc3968e62017-11-20 17:40:50 -0800126 private static final int DIALPAD_REQUEST_NONE = 1;
127 private static final int DIALPAD_REQUEST_SHOW = 2;
128 private static final int DIALPAD_REQUEST_HIDE = 3;
linyuh57b093b2017-11-17 14:32:32 -0800129
linyuhc3968e62017-11-20 17:40:50 -0800130 private static Optional<Integer> audioRouteForTesting = Optional.absent();
linyuh57b093b2017-11-17 14:32:32 -0800131
linyuhc3968e62017-11-20 17:40:50 -0800132 private final InternationalCallOnWifiCallback internationalCallOnWifiCallback =
133 new InternationalCallOnWifiCallback();
twyen73a74c32018-03-07 12:12:24 -0800134
135 private SelectPhoneAccountListener selectPhoneAccountListener;
Eric Erfanianccca3152017-02-22 16:32:36 -0800136
linyuhc3968e62017-11-20 17:40:50 -0800137 private Animation dialpadSlideInAnimation;
138 private Animation dialpadSlideOutAnimation;
139 private Dialog errorDialog;
140 private GradientDrawable backgroundDrawable;
linyuh69a25062017-11-15 16:18:51 -0800141 private InCallOrientationEventListener inCallOrientationEventListener;
linyuhc3968e62017-11-20 17:40:50 -0800142 private View pseudoBlackScreenOverlay;
143 private SelectPhoneAccountDialogFragment selectPhoneAccountDialogFragment;
144 private String dtmfTextToPrepopulate;
145 private String showPostCharWaitDialogCallId;
146 private String showPostCharWaitDialogChars;
147 private boolean allowOrientationChange;
148 private boolean animateDialpadOnShow;
Eric Erfanianccca3152017-02-22 16:32:36 -0800149 private boolean didShowAnswerScreen;
150 private boolean didShowInCallScreen;
151 private boolean didShowVideoCallScreen;
wangqi219b8702018-02-13 09:34:41 -0800152 private boolean didShowRttCallScreen;
erfaniand05d8992018-03-20 19:42:26 -0700153 private boolean didShowSpeakEasyScreen;
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
247 InternationalCallOnWifiDialogFragment existingInternationalCallOnWifiDialogFragment =
248 (InternationalCallOnWifiDialogFragment)
249 getSupportFragmentManager().findFragmentByTag(Tags.INTERNATIONAL_CALL_ON_WIFI);
250 if (existingInternationalCallOnWifiDialogFragment != null) {
251 existingInternationalCallOnWifiDialogFragment.setCallback(internationalCallOnWifiCallback);
252 }
253
linyuh69a25062017-11-15 16:18:51 -0800254 inCallOrientationEventListener = new InCallOrientationEventListener(this);
Eric Erfanianccca3152017-02-22 16:32:36 -0800255
256 getWindow()
257 .getDecorView()
258 .setSystemUiVisibility(
259 View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
260
261 pseudoBlackScreenOverlay = findViewById(R.id.psuedo_black_screen_overlay);
Eric Erfanian2ca43182017-08-31 06:57:16 -0700262 sendBroadcast(CallPendingActivity.getFinishBroadcast());
263 Trace.endSection();
zachh7a96dc72018-02-20 22:16:03 -0800264 MetricsComponent.get(this)
265 .metrics()
266 .stopTimer(Metrics.ON_CALL_ADDED_TO_ON_INCALL_UI_SHOWN_INCOMING);
267 MetricsComponent.get(this)
268 .metrics()
269 .stopTimer(Metrics.ON_CALL_ADDED_TO_ON_INCALL_UI_SHOWN_OUTGOING);
Eric Erfanianccca3152017-02-22 16:32:36 -0800270 }
271
linyuhc3968e62017-11-20 17:40:50 -0800272 private void setWindowFlags() {
273 // Allow the activity to be shown when the screen is locked and filter out touch events that are
274 // "too fat".
275 int flags =
276 WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
277 | WindowManager.LayoutParams.FLAG_IGNORE_CHEEK_PRESSES;
278
linyuhf79d1cb2017-12-15 17:49:56 -0800279 // When the audio stream is not via Bluetooth, turn on the screen once the activity is shown.
280 // When the audio stream is via Bluetooth, turn on the screen only for an incoming call.
linyuhc3968e62017-11-20 17:40:50 -0800281 final int audioRoute = getAudioRoute();
linyuhf79d1cb2017-12-15 17:49:56 -0800282 if (audioRoute != CallAudioState.ROUTE_BLUETOOTH
283 || CallList.getInstance().getIncomingCall() != null) {
linyuhc3968e62017-11-20 17:40:50 -0800284 flags |= WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON;
285 }
286
287 getWindow().addFlags(flags);
288 }
289
290 private static int getAudioRoute() {
291 if (audioRouteForTesting.isPresent()) {
292 return audioRouteForTesting.get();
293 }
294
295 return AudioModeProvider.getInstance().getAudioState().getRoute();
296 }
297
298 @VisibleForTesting(otherwise = VisibleForTesting.NONE)
299 public static void setAudioRouteForTesting(int audioRoute) {
300 audioRouteForTesting = Optional.of(audioRoute);
301 }
302
303 private void internalResolveIntent(Intent intent) {
304 if (!intent.getAction().equals(Intent.ACTION_MAIN)) {
305 return;
306 }
307
308 if (intent.hasExtra(IntentExtraNames.SHOW_DIALPAD)) {
309 // IntentExtraNames.SHOW_DIALPAD can be used to specify whether the DTMF dialpad should be
310 // initially visible. If the extra is absent, leave the dialpad in its previous state.
311 boolean showDialpad = intent.getBooleanExtra(IntentExtraNames.SHOW_DIALPAD, false);
312 relaunchedFromDialer(showDialpad);
313 }
314
315 DialerCall outgoingCall = CallList.getInstance().getOutgoingCall();
316 if (outgoingCall == null) {
317 outgoingCall = CallList.getInstance().getPendingOutgoingCall();
318 }
319 if (intent.getBooleanExtra(IntentExtraNames.NEW_OUTGOING_CALL, false)) {
320 intent.removeExtra(IntentExtraNames.NEW_OUTGOING_CALL);
321
322 // InCallActivity is responsible for disconnecting a new outgoing call if there is no way of
323 // making it (i.e. no valid call capable accounts).
linyuh122fb0b2018-03-26 13:35:32 -0700324 if (InCallPresenter.isCallWithNoValidAccounts(outgoingCall)) {
linyuhc3968e62017-11-20 17:40:50 -0800325 LogUtil.i(
326 "InCallActivity.internalResolveIntent", "Call with no valid accounts, disconnecting");
327 outgoingCall.disconnect();
328 }
329
330 dismissKeyguard(true);
331 }
332
333 if (showPhoneAccountSelectionDialog()) {
334 hideMainInCallFragment();
335 }
336 }
337
338 /**
339 * When relaunching from the dialer app, {@code showDialpad} indicates whether the dialpad should
340 * be shown on launch.
341 *
342 * @param showDialpad {@code true} to indicate the dialpad should be shown on launch, and {@code
343 * false} to indicate no change should be made to the dialpad visibility.
344 */
345 private void relaunchedFromDialer(boolean showDialpad) {
346 showDialpadRequest = showDialpad ? DIALPAD_REQUEST_SHOW : DIALPAD_REQUEST_NONE;
347 animateDialpadOnShow = true;
348
349 if (showDialpadRequest == DIALPAD_REQUEST_SHOW) {
350 // If there's only one line in use, AND it's on hold, then we're sure the user
351 // wants to use the dialpad toward the exact line, so un-hold the holding line.
352 DialerCall call = CallList.getInstance().getActiveOrBackgroundCall();
353 if (call != null && call.getState() == State.ONHOLD) {
354 call.unhold();
355 }
356 }
357 }
358
359 /**
360 * Show a phone account selection dialog if there is a call waiting for phone account selection.
361 *
362 * @return true if the dialog was shown.
363 */
364 private boolean showPhoneAccountSelectionDialog() {
365 DialerCall waitingForAccountCall = CallList.getInstance().getWaitingForAccountCall();
366 if (waitingForAccountCall == null) {
367 return false;
368 }
369
twyen73a74c32018-03-07 12:12:24 -0800370 DialerExecutorComponent.get(this)
371 .dialerExecutorFactory()
372 .createNonUiTaskBuilder(new PreferredAccountWorker(waitingForAccountCall.getNumber()))
373 .onSuccess(
374 (result -> {
375 if (result.getPhoneAccountHandle().isPresent()) {
376 Logger.get(this).logImpression(Type.DUAL_SIM_SELECTION_PREFERRED_USED);
377 selectPhoneAccountListener.onPhoneAccountSelected(
378 result.getPhoneAccountHandle().get(), false, waitingForAccountCall.getId());
379 return;
380 }
381 if (result.getSuggestion().isPresent()) {
382 LogUtil.i(
383 "CallingAccountSelector.processPreferredAccount",
384 "SIM suggested: " + result.getSuggestion().get().reason);
385 if (result.getSuggestion().get().shouldAutoSelect) {
386 Logger.get(this).logImpression(Type.DUAL_SIM_SELECTION_SUGGESTION_AUTO_SELECTED);
387 LogUtil.i(
388 "CallingAccountSelector.processPreferredAccount", "Auto selected suggestion");
389 selectPhoneAccountListener.onPhoneAccountSelected(
390 result.getSuggestion().get().phoneAccountHandle,
391 false,
392 waitingForAccountCall.getId());
393 return;
394 }
395 }
396 Bundle extras = waitingForAccountCall.getIntentExtras();
397 List<PhoneAccountHandle> phoneAccountHandles =
398 extras == null
399 ? new ArrayList<>()
400 : extras.getParcelableArrayList(Call.AVAILABLE_PHONE_ACCOUNTS);
linyuhc3968e62017-11-20 17:40:50 -0800401
twyen73a74c32018-03-07 12:12:24 -0800402 waitingForAccountCall.setPreferredAccountRecorder(
403 new PreferredAccountRecorder(
404 waitingForAccountCall.getNumber(),
405 result.getSuggestion().orNull(),
406 result.getDataId().orNull()));
407 selectPhoneAccountDialogFragment =
408 SelectPhoneAccountDialogFragment.newInstance(
409 R.string.select_phone_account_for_calls,
410 result.getDataId().isPresent() /* canSetDefault */,
411 R.string.select_phone_account_for_calls_remember /* setDefaultResId */,
412 phoneAccountHandles,
413 selectPhoneAccountListener,
414 waitingForAccountCall.getId(),
415 SuggestionProvider.buildHint(
416 this, phoneAccountHandles, result.getSuggestion().orNull() /* hints */));
417 selectPhoneAccountDialogFragment.show(
418 getFragmentManager(), Tags.SELECT_ACCOUNT_FRAGMENT);
419 }))
420 .build()
421 .executeParallel(this);
422
linyuhc3968e62017-11-20 17:40:50 -0800423 return true;
424 }
425
Eric Erfanianccca3152017-02-22 16:32:36 -0800426 @Override
427 protected void onSaveInstanceState(Bundle out) {
linyuh57b093b2017-11-17 14:32:32 -0800428 LogUtil.enterBlock("InCallActivity.onSaveInstanceState");
429
430 // TODO: DialpadFragment should handle this as part of its own state
linyuhc3968e62017-11-20 17:40:50 -0800431 out.putBoolean(IntentExtraNames.SHOW_DIALPAD, isDialpadVisible());
linyuh57b093b2017-11-17 14:32:32 -0800432 DialpadFragment dialpadFragment = getDialpadFragment();
433 if (dialpadFragment != null) {
linyuhc3968e62017-11-20 17:40:50 -0800434 out.putString(KeysForSavedInstance.DIALPAD_TEXT, dialpadFragment.getDtmfText());
linyuh57b093b2017-11-17 14:32:32 -0800435 }
436
linyuhc3968e62017-11-20 17:40:50 -0800437 out.putBoolean(KeysForSavedInstance.DID_SHOW_ANSWER_SCREEN, didShowAnswerScreen);
438 out.putBoolean(KeysForSavedInstance.DID_SHOW_IN_CALL_SCREEN, didShowInCallScreen);
439 out.putBoolean(KeysForSavedInstance.DID_SHOW_VIDEO_CALL_SCREEN, didShowVideoCallScreen);
wangqi153af2f2018-02-15 16:21:49 -0800440 out.putBoolean(KeysForSavedInstance.DID_SHOW_RTT_CALL_SCREEN, didShowRttCallScreen);
erfaniand05d8992018-03-20 19:42:26 -0700441 out.putBoolean(KeysForSavedInstance.DID_SHOW_SPEAK_EASY_SCREEN, didShowSpeakEasyScreen);
linyuh57b093b2017-11-17 14:32:32 -0800442
Eric Erfanianccca3152017-02-22 16:32:36 -0800443 super.onSaveInstanceState(out);
444 isVisible = false;
445 }
446
447 @Override
448 protected void onStart() {
Eric Erfanian2ca43182017-08-31 06:57:16 -0700449 Trace.beginSection("InCallActivity.onStart");
Eric Erfanianccca3152017-02-22 16:32:36 -0800450 super.onStart();
linyuh57b093b2017-11-17 14:32:32 -0800451
Eric Erfanianccca3152017-02-22 16:32:36 -0800452 isVisible = true;
453 showMainInCallFragment();
linyuh57b093b2017-11-17 14:32:32 -0800454
455 InCallPresenter.getInstance().setActivity(this);
456 enableInCallOrientationEventListener(
457 getRequestedOrientation()
458 == InCallOrientationEventListener.ACTIVITY_PREFERENCE_ALLOW_ROTATION);
459 InCallPresenter.getInstance().onActivityStarted();
460
yueg10f6e822018-01-17 15:32:18 -0800461 if (!isRecreating) {
462 InCallPresenter.getInstance().onUiShowing(true);
463 }
464
linyuh437ae952018-03-26 12:46:18 -0700465 if (isInMultiWindowMode() && !getResources().getBoolean(R.bool.incall_dialpad_allowed)) {
Eric Erfanianccca3152017-02-22 16:32:36 -0800466 // Hide the dialpad because there may not be enough room
467 showDialpadFragment(false, false);
468 }
linyuh57b093b2017-11-17 14:32:32 -0800469
Eric Erfanian2ca43182017-08-31 06:57:16 -0700470 Trace.endSection();
Eric Erfanianccca3152017-02-22 16:32:36 -0800471 }
472
473 @Override
474 protected void onResume() {
Eric Erfanian2ca43182017-08-31 06:57:16 -0700475 Trace.beginSection("InCallActivity.onResume");
Eric Erfanianccca3152017-02-22 16:32:36 -0800476 super.onResume();
linyuhc3968e62017-11-20 17:40:50 -0800477
478 if (!InCallPresenter.getInstance().isReadyForTearDown()) {
479 updateTaskDescription();
linyuhc3968e62017-11-20 17:40:50 -0800480 }
481
482 // If there is a pending request to show or hide the dialpad, handle that now.
483 if (showDialpadRequest != DIALPAD_REQUEST_NONE) {
484 if (showDialpadRequest == DIALPAD_REQUEST_SHOW) {
485 // Exit fullscreen so that the user has access to the dialpad hide/show button.
486 // This is important when showing the dialpad from within dialer.
487 InCallPresenter.getInstance().setFullScreen(false /* isFullScreen */, true /* force */);
488
489 showDialpadFragment(true /* show */, animateDialpadOnShow /* animate */);
490 animateDialpadOnShow = false;
491
492 DialpadFragment dialpadFragment = getDialpadFragment();
493 if (dialpadFragment != null) {
494 dialpadFragment.setDtmfText(dtmfTextToPrepopulate);
495 dtmfTextToPrepopulate = null;
496 }
497 } else {
498 LogUtil.i("InCallActivity.onResume", "Force-hide the dialpad");
499 if (getDialpadFragment() != null) {
500 showDialpadFragment(false /* show */, false /* animate */);
501 }
502 }
503 showDialpadRequest = DIALPAD_REQUEST_NONE;
504 }
505 updateNavigationBar(isDialpadVisible());
506
507 if (showPostCharWaitDialogOnResume) {
508 showDialogForPostCharWait(showPostCharWaitDialogCallId, showPostCharWaitDialogChars);
509 }
510
511 CallList.getInstance()
512 .onInCallUiShown(getIntent().getBooleanExtra(IntentExtraNames.FOR_FULL_SCREEN, false));
513
Eric Erfanianccca3152017-02-22 16:32:36 -0800514 PseudoScreenState pseudoScreenState = InCallPresenter.getInstance().getPseudoScreenState();
515 pseudoScreenState.addListener(this);
516 onPseudoScreenStateChanged(pseudoScreenState.isOn());
Eric Erfanian2ca43182017-08-31 06:57:16 -0700517 Trace.endSection();
weijiaxu650e7cc2017-10-31 12:38:54 -0700518 // add 1 sec delay to get memory snapshot so that dialer wont react slowly on resume.
519 ThreadUtil.postDelayedOnUiThread(
weijiaxuc950a9b2017-11-06 16:39:04 -0800520 () ->
zachh7a96dc72018-02-20 22:16:03 -0800521 MetricsComponent.get(this)
522 .metrics()
523 .recordMemory(Metrics.INCALL_ACTIVITY_ON_RESUME_MEMORY_EVENT_NAME),
weijiaxu650e7cc2017-10-31 12:38:54 -0700524 1000);
Eric Erfanianccca3152017-02-22 16:32:36 -0800525 }
526
Eric Erfanianccca3152017-02-22 16:32:36 -0800527 @Override
528 protected void onPause() {
Eric Erfanian2ca43182017-08-31 06:57:16 -0700529 Trace.beginSection("InCallActivity.onPause");
Eric Erfanianccca3152017-02-22 16:32:36 -0800530 super.onPause();
linyuh57b093b2017-11-17 14:32:32 -0800531
532 DialpadFragment dialpadFragment = getDialpadFragment();
533 if (dialpadFragment != null) {
534 dialpadFragment.onDialerKeyUp(null);
535 }
536
Eric Erfanianccca3152017-02-22 16:32:36 -0800537 InCallPresenter.getInstance().getPseudoScreenState().removeListener(this);
Eric Erfanian2ca43182017-08-31 06:57:16 -0700538 Trace.endSection();
Eric Erfanianccca3152017-02-22 16:32:36 -0800539 }
540
541 @Override
542 protected void onStop() {
Eric Erfanian2ca43182017-08-31 06:57:16 -0700543 Trace.beginSection("InCallActivity.onStop");
wangqi4d705e52017-09-28 12:23:35 -0700544 isVisible = false;
Eric Erfanianccca3152017-02-22 16:32:36 -0800545 super.onStop();
linyuh57b093b2017-11-17 14:32:32 -0800546
547 // Disconnects the call waiting for a phone account when the activity is hidden (e.g., after the
548 // user presses the home button).
549 // Without this the pending call will get stuck on phone account selection and new calls can't
550 // be created.
551 // Skip this when the screen is locked since the activity may complete its current life cycle
552 // and restart.
linyuhc3968e62017-11-20 17:40:50 -0800553 if (!isRecreating && !getSystemService(KeyguardManager.class).isKeyguardLocked()) {
linyuh57b093b2017-11-17 14:32:32 -0800554 DialerCall waitingForAccountCall = CallList.getInstance().getWaitingForAccountCall();
555 if (waitingForAccountCall != null) {
556 waitingForAccountCall.disconnect();
557 }
558 }
559
560 enableInCallOrientationEventListener(false);
561 InCallPresenter.getInstance().updateIsChangingConfigurations();
562 InCallPresenter.getInstance().onActivityStopped();
linyuhc3968e62017-11-20 17:40:50 -0800563 if (!isRecreating) {
yueg10f6e822018-01-17 15:32:18 -0800564 InCallPresenter.getInstance().onUiShowing(false);
linyuh57b093b2017-11-17 14:32:32 -0800565 if (errorDialog != null) {
566 errorDialog.dismiss();
567 }
568 }
569
yueg10f6e822018-01-17 15:32:18 -0800570 if (isFinishing()) {
571 InCallPresenter.getInstance().unsetActivity(this);
572 }
573
Eric Erfanian2ca43182017-08-31 06:57:16 -0700574 Trace.endSection();
Eric Erfanianccca3152017-02-22 16:32:36 -0800575 }
576
577 @Override
578 protected void onDestroy() {
Eric Erfanian2ca43182017-08-31 06:57:16 -0700579 Trace.beginSection("InCallActivity.onDestroy");
Eric Erfanianccca3152017-02-22 16:32:36 -0800580 super.onDestroy();
linyuh57b093b2017-11-17 14:32:32 -0800581
582 InCallPresenter.getInstance().unsetActivity(this);
583 InCallPresenter.getInstance().updateIsChangingConfigurations();
Eric Erfanian2ca43182017-08-31 06:57:16 -0700584 Trace.endSection();
Eric Erfanianccca3152017-02-22 16:32:36 -0800585 }
586
587 @Override
588 public void finish() {
589 if (shouldCloseActivityOnFinish()) {
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700590 // When user select incall ui from recents after the call is disconnected, it tries to launch
591 // a new InCallActivity but InCallPresenter is already teared down at this point, which causes
592 // crash.
593 // By calling finishAndRemoveTask() instead of finish() the task associated with
594 // InCallActivity is cleared completely. So system won't try to create a new InCallActivity in
595 // this case.
596 //
597 // Calling finish won't clear the task and normally when an activity finishes it shouldn't
598 // clear the task since there could be parent activity in the same task that's still alive.
599 // But InCallActivity is special since it's singleInstance which means it's root activity and
600 // only instance of activity in the task. So it should be safe to also remove task when
601 // finishing.
602 // It's also necessary in the sense of it's excluded from recents. So whenever the activity
603 // finishes, the task should also be removed since it doesn't make sense to go back to it in
604 // anyway anymore.
605 super.finishAndRemoveTask();
Eric Erfanianccca3152017-02-22 16:32:36 -0800606 }
607 }
608
609 private boolean shouldCloseActivityOnFinish() {
linyuhc3968e62017-11-20 17:40:50 -0800610 if (!isVisible) {
Eric Erfanianccca3152017-02-22 16:32:36 -0800611 LogUtil.i(
612 "InCallActivity.shouldCloseActivityOnFinish",
613 "allowing activity to be closed because it's not visible");
614 return true;
615 }
616
twyen8efb4952017-10-06 16:35:54 -0700617 if (InCallPresenter.getInstance().isInCallUiLocked()) {
Eric Erfanianccca3152017-02-22 16:32:36 -0800618 LogUtil.i(
619 "InCallActivity.shouldCloseActivityOnFinish",
twyen8efb4952017-10-06 16:35:54 -0700620 "in call ui is locked, not closing activity");
Eric Erfanianccca3152017-02-22 16:32:36 -0800621 return false;
622 }
623
624 LogUtil.i(
625 "InCallActivity.shouldCloseActivityOnFinish",
twyen8efb4952017-10-06 16:35:54 -0700626 "activity is visible and has no locks, allowing activity to close");
Eric Erfanianccca3152017-02-22 16:32:36 -0800627 return true;
628 }
629
630 @Override
631 protected void onNewIntent(Intent intent) {
linyuhc3968e62017-11-20 17:40:50 -0800632 LogUtil.enterBlock("InCallActivity.onNewIntent");
Eric Erfanianccca3152017-02-22 16:32:36 -0800633
634 // If the screen is off, we need to make sure it gets turned on for incoming calls.
635 // This normally works just fine thanks to FLAG_TURN_SCREEN_ON but that only works
636 // when the activity is first created. Therefore, to ensure the screen is turned on
637 // for the call waiting case, we recreate() the current activity. There should be no jank from
638 // this since the screen is already off and will remain so until our new activity is up.
linyuhc3968e62017-11-20 17:40:50 -0800639 if (!isVisible) {
640 onNewIntent(intent, true /* isRecreating */);
Eric Erfanianccca3152017-02-22 16:32:36 -0800641 LogUtil.i("InCallActivity.onNewIntent", "Restarting InCallActivity to force screen on.");
642 recreate();
Eric Erfanian10b34a52017-05-04 08:23:17 -0700643 } else {
linyuhc3968e62017-11-20 17:40:50 -0800644 onNewIntent(intent, false /* isRecreating */);
645 }
646 }
647
yuega3305352018-01-09 11:02:47 -0800648 @VisibleForTesting
649 void onNewIntent(Intent intent, boolean isRecreating) {
linyuhc3968e62017-11-20 17:40:50 -0800650 this.isRecreating = isRecreating;
651
652 // We're being re-launched with a new Intent. Since it's possible for a single InCallActivity
653 // instance to persist indefinitely (even if we finish() ourselves), this sequence can
654 // happen any time the InCallActivity needs to be displayed.
655
656 // Stash away the new intent so that we can get it in the future by calling getIntent().
657 // Otherwise getIntent() will return the original Intent from when we first got created.
658 setIntent(intent);
659
660 // Activities are always paused before receiving a new intent, so we can count on our onResume()
661 // method being called next.
662
663 // Just like in onCreate(), handle the intent.
664 // Skip if InCallActivity is going to be recreated since this will be called in onCreate().
665 if (!isRecreating) {
666 internalResolveIntent(intent);
Eric Erfanianccca3152017-02-22 16:32:36 -0800667 }
668 }
669
670 @Override
671 public void onBackPressed() {
linyuh57b093b2017-11-17 14:32:32 -0800672 LogUtil.enterBlock("InCallActivity.onBackPressed");
673
linyuhc3968e62017-11-20 17:40:50 -0800674 if (!isVisible) {
linyuh57b093b2017-11-17 14:32:32 -0800675 return;
Eric Erfanianccca3152017-02-22 16:32:36 -0800676 }
linyuh57b093b2017-11-17 14:32:32 -0800677
678 if (!getCallCardFragmentVisible()) {
679 return;
680 }
681
682 DialpadFragment dialpadFragment = getDialpadFragment();
683 if (dialpadFragment != null && dialpadFragment.isVisible()) {
684 showDialpadFragment(false /* show */, true /* animate */);
685 return;
686 }
687
688 if (CallList.getInstance().getIncomingCall() != null) {
689 LogUtil.i(
690 "InCallActivity.onBackPressed",
691 "Ignore the press of the back key when an incoming call is ringing");
692 return;
693 }
694
695 // Nothing special to do. Fall back to the default behavior.
696 super.onBackPressed();
Eric Erfanianccca3152017-02-22 16:32:36 -0800697 }
698
699 @Override
700 public boolean onOptionsItemSelected(MenuItem item) {
701 LogUtil.i("InCallActivity.onOptionsItemSelected", "item: " + item);
702 if (item.getItemId() == android.R.id.home) {
703 onBackPressed();
704 return true;
705 }
706 return super.onOptionsItemSelected(item);
707 }
708
709 @Override
710 public boolean onKeyUp(int keyCode, KeyEvent event) {
linyuh57b093b2017-11-17 14:32:32 -0800711 DialpadFragment dialpadFragment = getDialpadFragment();
712 if (dialpadFragment != null
713 && dialpadFragment.isVisible()
714 && dialpadFragment.onDialerKeyUp(event)) {
715 return true;
716 }
717
718 if (keyCode == KeyEvent.KEYCODE_CALL) {
719 // Always consume KEYCODE_CALL to ensure the PhoneWindow won't do anything with it.
720 return true;
721 }
722
723 return super.onKeyUp(keyCode, event);
Eric Erfanianccca3152017-02-22 16:32:36 -0800724 }
725
726 @Override
727 public boolean onKeyDown(int keyCode, KeyEvent event) {
linyuh57b093b2017-11-17 14:32:32 -0800728 switch (keyCode) {
729 case KeyEvent.KEYCODE_CALL:
730 if (!InCallPresenter.getInstance().handleCallKey()) {
731 LogUtil.e(
732 "InCallActivity.onKeyDown",
733 "InCallPresenter should always handle KEYCODE_CALL in onKeyDown");
734 }
735 // Always consume KEYCODE_CALL to ensure the PhoneWindow won't do anything with it.
736 return true;
737
738 // Note that KEYCODE_ENDCALL isn't handled here as the standard system-wide handling of it
739 // is exactly what's needed, namely
740 // (1) "hang up" if there's an active call, or
741 // (2) "don't answer" if there's an incoming call.
742 // (See PhoneWindowManager for implementation details.)
743
744 case KeyEvent.KEYCODE_CAMERA:
745 // Consume KEYCODE_CAMERA since it's easy to accidentally press the camera button.
746 return true;
747
748 case KeyEvent.KEYCODE_VOLUME_UP:
749 case KeyEvent.KEYCODE_VOLUME_DOWN:
750 case KeyEvent.KEYCODE_VOLUME_MUTE:
751 // Ringer silencing handled by PhoneWindowManager.
752 break;
753
754 case KeyEvent.KEYCODE_MUTE:
755 TelecomAdapter.getInstance()
756 .mute(!AudioModeProvider.getInstance().getAudioState().isMuted());
757 return true;
758
759 case KeyEvent.KEYCODE_SLASH:
760 // When verbose logging is enabled, dump the view for debugging/testing purposes.
761 if (LogUtil.isVerboseEnabled()) {
762 View decorView = getWindow().getDecorView();
763 LogUtil.v("InCallActivity.onKeyDown", "View dump:\n%s", decorView);
764 return true;
765 }
766 break;
767
768 case KeyEvent.KEYCODE_EQUALS:
769 break;
770
771 default: // fall out
772 }
773
774 // Pass other key events to DialpadFragment's "onDialerKeyDown" method in case the user types
775 // in DTMF (Dual-tone multi-frequency signaling) code.
776 DialpadFragment dialpadFragment = getDialpadFragment();
777 if (dialpadFragment != null
778 && dialpadFragment.isVisible()
779 && dialpadFragment.onDialerKeyDown(event)) {
780 return true;
781 }
782
783 return super.onKeyDown(keyCode, event);
Eric Erfanianccca3152017-02-22 16:32:36 -0800784 }
785
786 public boolean isInCallScreenAnimating() {
787 return false;
788 }
789
790 public void showConferenceFragment(boolean show) {
791 if (show) {
792 startActivity(new Intent(this, ManageConferenceActivity.class));
793 }
794 }
795
linyuhc3968e62017-11-20 17:40:50 -0800796 public void showDialpadFragment(boolean show, boolean animate) {
797 if (show == isDialpadVisible()) {
798 return;
Eric Erfanianccca3152017-02-22 16:32:36 -0800799 }
linyuhc3968e62017-11-20 17:40:50 -0800800
801 FragmentManager dialpadFragmentManager = getDialpadFragmentManager();
802 if (dialpadFragmentManager == null) {
803 LogUtil.i("InCallActivity.showDialpadFragment", "Unable to obtain a FragmentManager");
804 return;
805 }
806
807 if (!animate) {
808 if (show) {
809 showDialpadFragment();
810 } else {
811 hideDialpadFragment();
812 }
813 } else {
814 if (show) {
815 showDialpadFragment();
816 getDialpadFragment().animateShowDialpad();
817 }
818 getDialpadFragment()
819 .getView()
820 .startAnimation(show ? dialpadSlideInAnimation : dialpadSlideOutAnimation);
821 }
822
823 ProximitySensor sensor = InCallPresenter.getInstance().getProximitySensor();
824 if (sensor != null) {
825 sensor.onDialpadVisible(show);
826 }
827 showDialpadRequest = DIALPAD_REQUEST_NONE;
828
829 // Note: onInCallScreenDialpadVisibilityChange is called here to ensure that the dialpad FAB
830 // repositions itself.
wangqifd4c9f72018-03-08 18:21:50 -0800831 getInCallOrRttCallScreen().onInCallScreenDialpadVisibilityChange(show);
linyuhc3968e62017-11-20 17:40:50 -0800832 }
833
834 private void showDialpadFragment() {
835 FragmentManager dialpadFragmentManager = getDialpadFragmentManager();
836 if (dialpadFragmentManager == null) {
837 return;
838 }
839
840 FragmentTransaction transaction = dialpadFragmentManager.beginTransaction();
841 DialpadFragment dialpadFragment = getDialpadFragment();
842 if (dialpadFragment == null) {
wangqifd4c9f72018-03-08 18:21:50 -0800843 dialpadFragment = new DialpadFragment();
844 transaction.add(getDialpadContainerId(), dialpadFragment, Tags.DIALPAD_FRAGMENT);
linyuhc3968e62017-11-20 17:40:50 -0800845 } else {
846 transaction.show(dialpadFragment);
calderwoodrad5883872017-12-12 15:29:12 -0800847 dialpadFragment.setUserVisibleHint(true);
linyuhc3968e62017-11-20 17:40:50 -0800848 }
wangqifd4c9f72018-03-08 18:21:50 -0800849 // RTT call screen doesn't show end call button inside dialpad, thus the space reserved for end
850 // call button should be removed.
851 dialpadFragment.setShouldShowEndCallSpace(didShowInCallScreen);
linyuhc3968e62017-11-20 17:40:50 -0800852 transaction.commitAllowingStateLoss();
853 dialpadFragmentManager.executePendingTransactions();
854
855 Logger.get(this).logScreenView(ScreenEvent.Type.INCALL_DIALPAD, this);
856 updateNavigationBar(true /* isDialpadVisible */);
857 }
858
859 private void hideDialpadFragment() {
860 FragmentManager dialpadFragmentManager = getDialpadFragmentManager();
861 if (dialpadFragmentManager == null) {
862 return;
863 }
864
calderwoodrad5883872017-12-12 15:29:12 -0800865 DialpadFragment dialpadFragment = getDialpadFragment();
linyuhc3968e62017-11-20 17:40:50 -0800866 if (dialpadFragment != null) {
867 FragmentTransaction transaction = dialpadFragmentManager.beginTransaction();
868 transaction.hide(dialpadFragment);
869 transaction.commitAllowingStateLoss();
870 dialpadFragmentManager.executePendingTransactions();
calderwoodrad5883872017-12-12 15:29:12 -0800871 dialpadFragment.setUserVisibleHint(false);
linyuhc3968e62017-11-20 17:40:50 -0800872 }
873 updateNavigationBar(false /* isDialpadVisible */);
Eric Erfanianccca3152017-02-22 16:32:36 -0800874 }
875
876 public boolean isDialpadVisible() {
linyuh69a25062017-11-15 16:18:51 -0800877 DialpadFragment dialpadFragment = getDialpadFragment();
calderwoodraa584bcd2018-01-24 12:19:56 -0800878 return dialpadFragment != null
879 && dialpadFragment.isAdded()
880 && !dialpadFragment.isHidden()
881 && dialpadFragment.getView() != null
882 && dialpadFragment.getUserVisibleHint();
linyuh69a25062017-11-15 16:18:51 -0800883 }
884
linyuhc3968e62017-11-20 17:40:50 -0800885 /** Returns the {@link DialpadFragment} that's shown by this activity, or {@code null} */
linyuh69a25062017-11-15 16:18:51 -0800886 @Nullable
linyuhc3968e62017-11-20 17:40:50 -0800887 private DialpadFragment getDialpadFragment() {
linyuh69a25062017-11-15 16:18:51 -0800888 FragmentManager fragmentManager = getDialpadFragmentManager();
889 if (fragmentManager == null) {
890 return null;
891 }
linyuhc3968e62017-11-20 17:40:50 -0800892 return (DialpadFragment) fragmentManager.findFragmentByTag(Tags.DIALPAD_FRAGMENT);
Eric Erfanianccca3152017-02-22 16:32:36 -0800893 }
894
895 public void onForegroundCallChanged(DialerCall newForegroundCall) {
linyuh57b093b2017-11-17 14:32:32 -0800896 updateTaskDescription();
897
898 if (newForegroundCall == null || !didShowAnswerScreen) {
Eric Erfanianccca3152017-02-22 16:32:36 -0800899 LogUtil.v("InCallActivity.onForegroundCallChanged", "resetting background color");
linyuh57b093b2017-11-17 14:32:32 -0800900 updateWindowBackgroundColor(0 /* progress */);
Eric Erfanianccca3152017-02-22 16:32:36 -0800901 }
902 }
903
linyuhc3968e62017-11-20 17:40:50 -0800904 private void updateTaskDescription() {
linyuh57b093b2017-11-17 14:32:32 -0800905 int color =
906 getResources().getBoolean(R.bool.is_layout_landscape)
907 ? ResourcesCompat.getColor(
908 getResources(), R.color.statusbar_background_color, getTheme())
909 : InCallPresenter.getInstance().getThemeColorManager().getSecondaryColor();
910 setTaskDescription(
911 new TaskDescription(
912 getResources().getString(R.string.notification_ongoing_call), null /* icon */, color));
913 }
914
Eric Erfanianccca3152017-02-22 16:32:36 -0800915 public void updateWindowBackgroundColor(@FloatRange(from = -1f, to = 1.0f) float progress) {
916 ThemeColorManager themeColorManager = InCallPresenter.getInstance().getThemeColorManager();
917 @ColorInt int top;
918 @ColorInt int middle;
919 @ColorInt int bottom;
920 @ColorInt int gray = 0x66000000;
921
linyuh437ae952018-03-26 12:46:18 -0700922 if (isInMultiWindowMode()) {
Eric Erfanianccca3152017-02-22 16:32:36 -0800923 top = themeColorManager.getBackgroundColorSolid();
924 middle = themeColorManager.getBackgroundColorSolid();
925 bottom = themeColorManager.getBackgroundColorSolid();
926 } else {
927 top = themeColorManager.getBackgroundColorTop();
928 middle = themeColorManager.getBackgroundColorMiddle();
929 bottom = themeColorManager.getBackgroundColorBottom();
930 }
931
932 if (progress < 0) {
933 float correctedProgress = Math.abs(progress);
934 top = ColorUtils.blendARGB(top, gray, correctedProgress);
935 middle = ColorUtils.blendARGB(middle, gray, correctedProgress);
936 bottom = ColorUtils.blendARGB(bottom, gray, correctedProgress);
937 }
938
939 boolean backgroundDirty = false;
940 if (backgroundDrawable == null) {
941 backgroundDrawableColors = new int[] {top, middle, bottom};
942 backgroundDrawable = new GradientDrawable(Orientation.TOP_BOTTOM, backgroundDrawableColors);
943 backgroundDirty = true;
944 } else {
945 if (backgroundDrawableColors[0] != top) {
946 backgroundDrawableColors[0] = top;
947 backgroundDirty = true;
948 }
949 if (backgroundDrawableColors[1] != middle) {
950 backgroundDrawableColors[1] = middle;
951 backgroundDirty = true;
952 }
953 if (backgroundDrawableColors[2] != bottom) {
954 backgroundDrawableColors[2] = bottom;
955 backgroundDirty = true;
956 }
957 if (backgroundDirty) {
958 backgroundDrawable.setColors(backgroundDrawableColors);
959 }
960 }
961
962 if (backgroundDirty) {
963 getWindow().setBackgroundDrawable(backgroundDrawable);
964 }
965 }
966
967 public boolean isVisible() {
968 return isVisible;
969 }
970
971 public boolean getCallCardFragmentVisible() {
erfaniand05d8992018-03-20 19:42:26 -0700972 return didShowInCallScreen
973 || didShowVideoCallScreen
974 || didShowRttCallScreen
975 || didShowSpeakEasyScreen;
Eric Erfanianccca3152017-02-22 16:32:36 -0800976 }
977
978 public void dismissKeyguard(boolean dismiss) {
linyuh9c327da2017-11-14 12:33:48 -0800979 if (dismissKeyguard == dismiss) {
980 return;
981 }
982
983 dismissKeyguard = dismiss;
984 if (dismiss) {
985 getWindow().addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);
986 } else {
987 getWindow().clearFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);
988 }
Eric Erfanianccca3152017-02-22 16:32:36 -0800989 }
990
linyuhc3968e62017-11-20 17:40:50 -0800991 public void showDialogForPostCharWait(String callId, String chars) {
992 if (isVisible) {
993 PostCharDialogFragment fragment = new PostCharDialogFragment(callId, chars);
994 fragment.show(getSupportFragmentManager(), Tags.POST_CHAR_DIALOG_FRAGMENT);
995
996 showPostCharWaitDialogOnResume = false;
997 showPostCharWaitDialogCallId = null;
998 showPostCharWaitDialogChars = null;
999 } else {
1000 showPostCharWaitDialogOnResume = true;
1001 showPostCharWaitDialogCallId = callId;
1002 showPostCharWaitDialogChars = chars;
1003 }
Eric Erfanianccca3152017-02-22 16:32:36 -08001004 }
1005
linyuh7b86f562017-11-16 11:24:09 -08001006 public void showDialogOrToastForDisconnectedCall(DisconnectMessage disconnectMessage) {
1007 LogUtil.i(
1008 "InCallActivity.showDialogOrToastForDisconnectedCall",
1009 "disconnect cause: %s",
1010 disconnectMessage);
1011
1012 if (disconnectMessage.dialog == null || isFinishing()) {
1013 return;
1014 }
1015
1016 dismissPendingDialogs();
1017
1018 // Show a toast if the app is in background when a dialog can't be visible.
1019 if (!isVisible()) {
1020 Toast.makeText(getApplicationContext(), disconnectMessage.toastMessage, Toast.LENGTH_LONG)
1021 .show();
1022 return;
1023 }
1024
1025 // Show the dialog.
linyuhc3968e62017-11-20 17:40:50 -08001026 errorDialog = disconnectMessage.dialog;
linyuh7b86f562017-11-16 11:24:09 -08001027 InCallUiLock lock = InCallPresenter.getInstance().acquireInCallUiLock("showErrorDialog");
1028 disconnectMessage.dialog.setOnDismissListener(
1029 dialogInterface -> {
1030 lock.release();
1031 onDialogDismissed();
1032 });
1033 disconnectMessage.dialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
1034 disconnectMessage.dialog.show();
1035 }
1036
1037 private void onDialogDismissed() {
linyuhc3968e62017-11-20 17:40:50 -08001038 errorDialog = null;
linyuh7b86f562017-11-16 11:24:09 -08001039 CallList.getInstance().onErrorDialogDismissed();
Eric Erfanianccca3152017-02-22 16:32:36 -08001040 }
1041
1042 public void dismissPendingDialogs() {
linyuhc3968e62017-11-20 17:40:50 -08001043 LogUtil.enterBlock("InCallActivity.dismissPendingDialogs");
linyuhf99f6302017-11-15 11:23:51 -08001044
1045 if (!isVisible) {
1046 // Defer the dismissing action as the activity is not visible and onSaveInstanceState may have
1047 // been called.
Eric Erfanianccca3152017-02-22 16:32:36 -08001048 LogUtil.i(
1049 "InCallActivity.dismissPendingDialogs", "defer actions since activity is not visible");
1050 needDismissPendingDialogs = true;
linyuhf99f6302017-11-15 11:23:51 -08001051 return;
Eric Erfanianccca3152017-02-22 16:32:36 -08001052 }
linyuhf99f6302017-11-15 11:23:51 -08001053
1054 // Dismiss the error dialog
linyuhf99f6302017-11-15 11:23:51 -08001055 if (errorDialog != null) {
1056 errorDialog.dismiss();
linyuhc3968e62017-11-20 17:40:50 -08001057 errorDialog = null;
linyuhf99f6302017-11-15 11:23:51 -08001058 }
1059
1060 // Dismiss the phone account selection dialog
linyuhf99f6302017-11-15 11:23:51 -08001061 if (selectPhoneAccountDialogFragment != null) {
1062 selectPhoneAccountDialogFragment.dismiss();
linyuhc3968e62017-11-20 17:40:50 -08001063 selectPhoneAccountDialogFragment = null;
linyuhf99f6302017-11-15 11:23:51 -08001064 }
1065
1066 // Dismiss the dialog for international call on WiFi
1067 InternationalCallOnWifiDialogFragment internationalCallOnWifiFragment =
1068 (InternationalCallOnWifiDialogFragment)
linyuhc3968e62017-11-20 17:40:50 -08001069 getSupportFragmentManager().findFragmentByTag(Tags.INTERNATIONAL_CALL_ON_WIFI);
linyuhf99f6302017-11-15 11:23:51 -08001070 if (internationalCallOnWifiFragment != null) {
1071 internationalCallOnWifiFragment.dismiss();
1072 }
1073
1074 // Dismiss the answer screen
1075 AnswerScreen answerScreen = getAnswerScreen();
1076 if (answerScreen != null) {
1077 answerScreen.dismissPendingDialogs();
1078 }
1079
1080 needDismissPendingDialogs = false;
Eric Erfanianccca3152017-02-22 16:32:36 -08001081 }
1082
linyuhc3968e62017-11-20 17:40:50 -08001083 private void enableInCallOrientationEventListener(boolean enable) {
linyuh69a25062017-11-15 16:18:51 -08001084 if (enable) {
1085 inCallOrientationEventListener.enable(true /* notifyDeviceOrientationChange */);
1086 } else {
1087 inCallOrientationEventListener.disable();
1088 }
Eric Erfanianccca3152017-02-22 16:32:36 -08001089 }
1090
1091 public void setExcludeFromRecents(boolean exclude) {
linyuhc3968e62017-11-20 17:40:50 -08001092 int taskId = getTaskId();
1093
1094 List<AppTask> tasks = getSystemService(ActivityManager.class).getAppTasks();
1095 for (AppTask task : tasks) {
1096 try {
1097 if (task.getTaskInfo().id == taskId) {
1098 task.setExcludeFromRecents(exclude);
1099 }
1100 } catch (RuntimeException e) {
1101 LogUtil.e("InCallActivity.setExcludeFromRecents", "RuntimeException:\n%s", e);
1102 }
1103 }
Eric Erfanianccca3152017-02-22 16:32:36 -08001104 }
1105
Eric Erfanianccca3152017-02-22 16:32:36 -08001106 @Nullable
1107 public FragmentManager getDialpadFragmentManager() {
wangqifd4c9f72018-03-08 18:21:50 -08001108 InCallScreen inCallScreen = getInCallOrRttCallScreen();
Eric Erfanianccca3152017-02-22 16:32:36 -08001109 if (inCallScreen != null) {
1110 return inCallScreen.getInCallScreenFragment().getChildFragmentManager();
1111 }
1112 return null;
1113 }
1114
1115 public int getDialpadContainerId() {
wangqifd4c9f72018-03-08 18:21:50 -08001116 return getInCallOrRttCallScreen().getAnswerAndDialpadContainerResourceId();
Eric Erfanianccca3152017-02-22 16:32:36 -08001117 }
1118
1119 @Override
1120 public AnswerScreenDelegate newAnswerScreenDelegate(AnswerScreen answerScreen) {
1121 DialerCall call = CallList.getInstance().getCallById(answerScreen.getCallId());
1122 if (call == null) {
1123 // This is a work around for a bug where we attempt to create a new delegate after the call
1124 // has already been removed. An example of when this can happen is:
1125 // 1. incoming video call in landscape mode
1126 // 2. remote party hangs up
1127 // 3. activity switches from landscape to portrait
1128 // At step #3 the answer fragment will try to create a new answer delegate but the call won't
1129 // exist. In this case we'll simply return a stub delegate that does nothing. This is ok
1130 // because this new state is transient and the activity will be destroyed soon.
1131 LogUtil.i("InCallActivity.onPrimaryCallStateChanged", "call doesn't exist, using stub");
1132 return new AnswerScreenPresenterStub();
1133 } else {
1134 return new AnswerScreenPresenter(
1135 this, answerScreen, CallList.getInstance().getCallById(answerScreen.getCallId()));
1136 }
1137 }
1138
1139 @Override
1140 public InCallScreenDelegate newInCallScreenDelegate() {
1141 return new CallCardPresenter(this);
1142 }
1143
1144 @Override
1145 public InCallButtonUiDelegate newInCallButtonUiDelegate() {
1146 return new CallButtonPresenter(this);
1147 }
1148
1149 @Override
Eric Erfanian90508232017-03-24 09:31:16 -07001150 public VideoCallScreenDelegate newVideoCallScreenDelegate(VideoCallScreen videoCallScreen) {
1151 DialerCall dialerCall = CallList.getInstance().getCallById(videoCallScreen.getCallId());
1152 if (dialerCall != null && dialerCall.getVideoTech().shouldUseSurfaceView()) {
1153 return dialerCall.getVideoTech().createVideoCallScreenDelegate(this, videoCallScreen);
1154 }
Eric Erfanianccca3152017-02-22 16:32:36 -08001155 return new VideoCallPresenter();
1156 }
1157
1158 public void onPrimaryCallStateChanged() {
Eric Erfanian2ca43182017-08-31 06:57:16 -07001159 Trace.beginSection("InCallActivity.onPrimaryCallStateChanged");
Eric Erfanianccca3152017-02-22 16:32:36 -08001160 showMainInCallFragment();
Eric Erfanian2ca43182017-08-31 06:57:16 -07001161 Trace.endSection();
Eric Erfanianccca3152017-02-22 16:32:36 -08001162 }
1163
linyuh7b86f562017-11-16 11:24:09 -08001164 public void showToastForWiFiToLteHandover(DialerCall call) {
1165 if (call.hasShownWiFiToLteHandoverToast()) {
1166 return;
1167 }
1168
1169 Toast.makeText(this, R.string.video_call_wifi_to_lte_handover_toast, Toast.LENGTH_LONG).show();
1170 call.setHasShownWiFiToLteHandoverToast();
Eric Erfanianccca3152017-02-22 16:32:36 -08001171 }
1172
linyuh7b86f562017-11-16 11:24:09 -08001173 public void showDialogOrToastForWifiHandoverFailure(DialerCall call) {
1174 if (call.showWifiHandoverAlertAsToast()) {
1175 Toast.makeText(this, R.string.video_call_lte_to_wifi_failed_message, Toast.LENGTH_SHORT)
1176 .show();
1177 return;
1178 }
1179
1180 dismissPendingDialogs();
1181
1182 AlertDialog.Builder builder =
1183 new AlertDialog.Builder(this).setTitle(R.string.video_call_lte_to_wifi_failed_title);
1184
1185 // This allows us to use the theme of the dialog instead of the activity
1186 View dialogCheckBoxView =
1187 View.inflate(builder.getContext(), R.layout.video_call_lte_to_wifi_failed, null /* root */);
1188 CheckBox wifiHandoverFailureCheckbox =
1189 (CheckBox) dialogCheckBoxView.findViewById(R.id.video_call_lte_to_wifi_failed_checkbox);
1190 wifiHandoverFailureCheckbox.setChecked(false);
1191
1192 InCallUiLock lock = InCallPresenter.getInstance().acquireInCallUiLock("WifiFailedDialog");
linyuhc3968e62017-11-20 17:40:50 -08001193 errorDialog =
linyuh7b86f562017-11-16 11:24:09 -08001194 builder
1195 .setView(dialogCheckBoxView)
1196 .setMessage(R.string.video_call_lte_to_wifi_failed_message)
1197 .setOnCancelListener(dialogInterface -> onDialogDismissed())
1198 .setPositiveButton(
1199 android.R.string.ok,
1200 (dialogInterface, id) -> {
1201 call.setDoNotShowDialogForHandoffToWifiFailure(
1202 wifiHandoverFailureCheckbox.isChecked());
1203 dialogInterface.cancel();
1204 onDialogDismissed();
1205 })
1206 .setOnDismissListener(dialogInterface -> lock.release())
1207 .create();
linyuh7b86f562017-11-16 11:24:09 -08001208 errorDialog.show();
Eric Erfanianccca3152017-02-22 16:32:36 -08001209 }
1210
linyuh7b86f562017-11-16 11:24:09 -08001211 public void showDialogForInternationalCallOnWifi(@NonNull DialerCall call) {
1212 if (!InternationalCallOnWifiDialogFragment.shouldShow(this)) {
1213 LogUtil.i(
1214 "InCallActivity.showDialogForInternationalCallOnWifi",
1215 "InternationalCallOnWifiDialogFragment.shouldShow returned false");
1216 return;
1217 }
1218
1219 InternationalCallOnWifiDialogFragment fragment =
1220 InternationalCallOnWifiDialogFragment.newInstance(
linyuhc3968e62017-11-20 17:40:50 -08001221 call.getId(), internationalCallOnWifiCallback);
1222 fragment.show(getSupportFragmentManager(), Tags.INTERNATIONAL_CALL_ON_WIFI);
Eric Erfanianc857f902017-05-15 14:05:33 -07001223 }
1224
wangqibc28ea72018-04-02 16:23:00 -07001225 public void showDialogForRttRequest(DialerCall call, int rttRequestId) {
1226 LogUtil.enterBlock("InCallActivity.showDialogForRttRequest");
1227 DialogFragment fragment = RttRequestDialogFragment.newInstance(call.getId(), rttRequestId);
1228 fragment.show(getSupportFragmentManager(), Tags.RTT_REQUEST_DIALOG);
1229 }
1230
Eric Erfanian938468d2017-10-24 14:05:52 -07001231 @Override
1232 public void onMultiWindowModeChanged(boolean isInMultiWindowMode) {
1233 super.onMultiWindowModeChanged(isInMultiWindowMode);
linyuh57b093b2017-11-17 14:32:32 -08001234 updateNavigationBar(isDialpadVisible());
1235 }
1236
linyuhc3968e62017-11-20 17:40:50 -08001237 private void updateNavigationBar(boolean isDialpadVisible) {
linyuh437ae952018-03-26 12:46:18 -07001238 if (isInMultiWindowMode()) {
linyuh57b093b2017-11-17 14:32:32 -08001239 return;
1240 }
1241
1242 View navigationBarBackground = getWindow().findViewById(R.id.navigation_bar_background);
1243 if (navigationBarBackground != null) {
1244 navigationBarBackground.setVisibility(isDialpadVisible ? View.VISIBLE : View.GONE);
Eric Erfanian938468d2017-10-24 14:05:52 -07001245 }
1246 }
1247
Eric Erfanianccca3152017-02-22 16:32:36 -08001248 public void setAllowOrientationChange(boolean allowOrientationChange) {
wangqi9982f0d2017-10-11 17:46:07 -07001249 if (this.allowOrientationChange == allowOrientationChange) {
1250 return;
1251 }
1252 this.allowOrientationChange = allowOrientationChange;
Eric Erfanianccca3152017-02-22 16:32:36 -08001253 if (!allowOrientationChange) {
1254 setRequestedOrientation(InCallOrientationEventListener.ACTIVITY_PREFERENCE_DISALLOW_ROTATION);
1255 } else {
1256 setRequestedOrientation(InCallOrientationEventListener.ACTIVITY_PREFERENCE_ALLOW_ROTATION);
1257 }
1258 enableInCallOrientationEventListener(allowOrientationChange);
1259 }
1260
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001261 public void hideMainInCallFragment() {
linyuhc3968e62017-11-20 17:40:50 -08001262 LogUtil.enterBlock("InCallActivity.hideMainInCallFragment");
1263 if (getCallCardFragmentVisible()) {
Eric Erfanianccca3152017-02-22 16:32:36 -08001264 FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
1265 hideInCallScreenFragment(transaction);
1266 hideVideoCallScreenFragment(transaction);
1267 transaction.commitAllowingStateLoss();
1268 getSupportFragmentManager().executePendingTransactions();
1269 }
1270 }
1271
1272 private void showMainInCallFragment() {
Eric Erfanian2ca43182017-08-31 06:57:16 -07001273 Trace.beginSection("InCallActivity.showMainInCallFragment");
Eric Erfanianccca3152017-02-22 16:32:36 -08001274 // If the activity's onStart method hasn't been called yet then defer doing any work.
1275 if (!isVisible) {
1276 LogUtil.i("InCallActivity.showMainInCallFragment", "not visible yet/anymore");
Eric Erfanian2ca43182017-08-31 06:57:16 -07001277 Trace.endSection();
Eric Erfanianccca3152017-02-22 16:32:36 -08001278 return;
1279 }
1280
1281 // Don't let this be reentrant.
1282 if (isInShowMainInCallFragment) {
1283 LogUtil.i("InCallActivity.showMainInCallFragment", "already in method, bailing");
Eric Erfanian2ca43182017-08-31 06:57:16 -07001284 Trace.endSection();
Eric Erfanianccca3152017-02-22 16:32:36 -08001285 return;
1286 }
1287
1288 isInShowMainInCallFragment = true;
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001289 ShouldShowUiResult shouldShowAnswerUi = getShouldShowAnswerUi();
1290 ShouldShowUiResult shouldShowVideoUi = getShouldShowVideoUi();
wangqi219b8702018-02-13 09:34:41 -08001291 ShouldShowUiResult shouldShowRttUi = getShouldShowRttUi();
erfaniand05d8992018-03-20 19:42:26 -07001292 ShouldShowUiResult shouldShowSpeakEasyUi = getShouldShowSpeakEasyUi();
Eric Erfanianccca3152017-02-22 16:32:36 -08001293 LogUtil.i(
1294 "InCallActivity.showMainInCallFragment",
wangqi219b8702018-02-13 09:34:41 -08001295 "shouldShowAnswerUi: %b, shouldShowRttUi: %b, shouldShowVideoUi: %b "
1296 + "didShowAnswerScreen: %b, didShowInCallScreen: %b, didShowRttCallScreen: %b, "
erfaniand05d8992018-03-20 19:42:26 -07001297 + "didShowVideoCallScreen: %b"
1298 + "didShowSpeakEasyScreen: %b",
Eric Erfanianccca3152017-02-22 16:32:36 -08001299 shouldShowAnswerUi.shouldShow,
wangqi219b8702018-02-13 09:34:41 -08001300 shouldShowRttUi.shouldShow,
Eric Erfanian10b34a52017-05-04 08:23:17 -07001301 shouldShowVideoUi.shouldShow,
Eric Erfanianccca3152017-02-22 16:32:36 -08001302 didShowAnswerScreen,
1303 didShowInCallScreen,
wangqi219b8702018-02-13 09:34:41 -08001304 didShowRttCallScreen,
erfaniand05d8992018-03-20 19:42:26 -07001305 didShowVideoCallScreen,
1306 didShowSpeakEasyScreen);
Eric Erfanianccca3152017-02-22 16:32:36 -08001307 // Only video call ui allows orientation change.
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001308 setAllowOrientationChange(shouldShowVideoUi.shouldShow);
Eric Erfanianccca3152017-02-22 16:32:36 -08001309
1310 FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
wangqi219b8702018-02-13 09:34:41 -08001311 boolean didChange;
Eric Erfanianccca3152017-02-22 16:32:36 -08001312 if (shouldShowAnswerUi.shouldShow) {
wangqi219b8702018-02-13 09:34:41 -08001313 didChange = hideInCallScreenFragment(transaction);
1314 didChange |= hideVideoCallScreenFragment(transaction);
1315 didChange |= hideRttCallScreenFragment(transaction);
erfaniand05d8992018-03-20 19:42:26 -07001316 didChange |= hideSpeakEasyFragment(transaction);
wangqi219b8702018-02-13 09:34:41 -08001317 didChange |= showAnswerScreenFragment(transaction, shouldShowAnswerUi.call);
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001318 } else if (shouldShowVideoUi.shouldShow) {
wangqi219b8702018-02-13 09:34:41 -08001319 didChange = hideInCallScreenFragment(transaction);
1320 didChange |= showVideoCallScreenFragment(transaction, shouldShowVideoUi.call);
1321 didChange |= hideRttCallScreenFragment(transaction);
erfaniand05d8992018-03-20 19:42:26 -07001322 didChange |= hideSpeakEasyFragment(transaction);
wangqi219b8702018-02-13 09:34:41 -08001323 didChange |= hideAnswerScreenFragment(transaction);
1324 } else if (shouldShowRttUi.shouldShow) {
1325 didChange = hideInCallScreenFragment(transaction);
1326 didChange |= hideVideoCallScreenFragment(transaction);
1327 didChange |= hideAnswerScreenFragment(transaction);
erfaniand05d8992018-03-20 19:42:26 -07001328 didChange |= hideSpeakEasyFragment(transaction);
wangqi219b8702018-02-13 09:34:41 -08001329 didChange |= showRttCallScreenFragment(transaction, shouldShowRttUi.call);
erfaniand05d8992018-03-20 19:42:26 -07001330 } else if (shouldShowSpeakEasyUi.shouldShow) {
1331 didChange = hideInCallScreenFragment(transaction);
1332 didChange |= hideVideoCallScreenFragment(transaction);
1333 didChange |= hideAnswerScreenFragment(transaction);
1334 didChange |= hideRttCallScreenFragment(transaction);
1335 didChange |= showSpeakEasyFragment(transaction, shouldShowSpeakEasyUi.call);
Eric Erfanianccca3152017-02-22 16:32:36 -08001336 } else {
wangqi219b8702018-02-13 09:34:41 -08001337 didChange = showInCallScreenFragment(transaction);
1338 didChange |= hideVideoCallScreenFragment(transaction);
1339 didChange |= hideRttCallScreenFragment(transaction);
erfaniand05d8992018-03-20 19:42:26 -07001340 didChange |= hideSpeakEasyFragment(transaction);
wangqi219b8702018-02-13 09:34:41 -08001341 didChange |= hideAnswerScreenFragment(transaction);
Eric Erfanianccca3152017-02-22 16:32:36 -08001342 }
1343
wangqi219b8702018-02-13 09:34:41 -08001344 if (didChange) {
Eric Erfanian2ca43182017-08-31 06:57:16 -07001345 Trace.beginSection("InCallActivity.commitTransaction");
Eric Erfanianccca3152017-02-22 16:32:36 -08001346 transaction.commitNow();
Eric Erfanian2ca43182017-08-31 06:57:16 -07001347 Trace.endSection();
Eric Erfanianccca3152017-02-22 16:32:36 -08001348 Logger.get(this).logScreenView(ScreenEvent.Type.INCALL, this);
1349 }
1350 isInShowMainInCallFragment = false;
Eric Erfanian2ca43182017-08-31 06:57:16 -07001351 Trace.endSection();
Eric Erfanianccca3152017-02-22 16:32:36 -08001352 }
1353
erfaniand05d8992018-03-20 19:42:26 -07001354 private boolean showSpeakEasyFragment(FragmentTransaction transaction, DialerCall call) {
1355
1356 // TODO(erfanian): Support multiple speakeasy screens.
1357 if (didShowSpeakEasyScreen) {
1358 return false;
1359 }
1360
1361 Optional<Fragment> speakEasyFragment = speakEasyCallManager.getSpeakEasyFragment(call);
1362 if (speakEasyFragment.isPresent()) {
1363 transaction.add(R.id.main, speakEasyFragment.get(), Tags.SPEAK_EASY_SCREEN);
1364 didShowSpeakEasyScreen = true;
1365 return true;
1366 }
1367 return false;
1368 }
1369
1370 private Fragment getSpeakEasyScreen() {
1371 return getSupportFragmentManager().findFragmentByTag(Tags.SPEAK_EASY_SCREEN);
1372 }
1373
1374 private boolean hideSpeakEasyFragment(FragmentTransaction transaction) {
1375 if (!didShowSpeakEasyScreen) {
1376 return false;
1377 }
1378
1379 Fragment speakEasyFragment = getSpeakEasyScreen();
1380
1381 if (speakEasyFragment != null) {
1382 transaction.remove(speakEasyFragment);
1383 didShowSpeakEasyScreen = false;
1384 return true;
1385 }
1386 return false;
1387 }
1388
1389 public void setSpeakEasyCallManager(SpeakEasyCallManager speakEasyCallManager) {
1390 this.speakEasyCallManager = Assert.isNotNull(speakEasyCallManager);
1391 }
1392
1393 public SpeakEasyCallManager getSpeakEasyCallManager() {
1394 return speakEasyCallManager;
1395 }
1396
1397 private ShouldShowUiResult getShouldShowSpeakEasyUi() {
1398 SpeakEasyCallManager speakEasyCallManager = getSpeakEasyCallManager();
1399
1400 if (speakEasyCallManager == null) {
1401 return new ShouldShowUiResult(false, null);
1402 }
1403
1404 // TODO(erfanian): Get a better call?
1405 DialerCall call = CallList.getInstance().getActiveCall();
1406
1407 if (call == null) {
1408 return new ShouldShowUiResult(false, call);
1409 }
1410
1411 if (!call.isSpeakEasyCall() || !call.isSpeakEasyEligible()) {
1412 return new ShouldShowUiResult(false, call);
1413 }
1414
1415 Optional<Fragment> speakEasyFragment = speakEasyCallManager.getSpeakEasyFragment(call);
1416
1417 if (!speakEasyFragment.isPresent()) {
1418 return new ShouldShowUiResult(false, call);
1419 }
1420 return new ShouldShowUiResult(true, call);
1421 }
1422
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001423 private ShouldShowUiResult getShouldShowAnswerUi() {
Eric Erfanianccca3152017-02-22 16:32:36 -08001424 DialerCall call = CallList.getInstance().getIncomingCall();
1425 if (call != null) {
1426 LogUtil.i("InCallActivity.getShouldShowAnswerUi", "found incoming call");
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001427 return new ShouldShowUiResult(true, call);
Eric Erfanianccca3152017-02-22 16:32:36 -08001428 }
1429
1430 call = CallList.getInstance().getVideoUpgradeRequestCall();
1431 if (call != null) {
1432 LogUtil.i("InCallActivity.getShouldShowAnswerUi", "found video upgrade request");
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001433 return new ShouldShowUiResult(true, call);
Eric Erfanianccca3152017-02-22 16:32:36 -08001434 }
1435
1436 // Check if we're showing the answer screen and the call is disconnected. If this condition is
1437 // true then we won't switch from the answer UI to the in call UI. This prevents flicker when
1438 // the user rejects an incoming call.
1439 call = CallList.getInstance().getFirstCall();
1440 if (call == null) {
1441 call = CallList.getInstance().getBackgroundCall();
1442 }
1443 if (didShowAnswerScreen && (call == null || call.getState() == State.DISCONNECTED)) {
1444 LogUtil.i("InCallActivity.getShouldShowAnswerUi", "found disconnecting incoming call");
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001445 return new ShouldShowUiResult(true, call);
Eric Erfanianccca3152017-02-22 16:32:36 -08001446 }
1447
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 private static ShouldShowUiResult getShouldShowVideoUi() {
Eric Erfanianccca3152017-02-22 16:32:36 -08001452 DialerCall call = CallList.getInstance().getFirstCall();
1453 if (call == null) {
1454 LogUtil.i("InCallActivity.getShouldShowVideoUi", "null call");
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001455 return new ShouldShowUiResult(false, null);
Eric Erfanianccca3152017-02-22 16:32:36 -08001456 }
1457
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001458 if (call.isVideoCall()) {
Eric Erfanianccca3152017-02-22 16:32:36 -08001459 LogUtil.i("InCallActivity.getShouldShowVideoUi", "found video call");
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001460 return new ShouldShowUiResult(true, call);
Eric Erfanianccca3152017-02-22 16:32:36 -08001461 }
1462
linyuh8fbecce2017-12-18 13:53:09 -08001463 if (call.hasSentVideoUpgradeRequest() || call.hasReceivedVideoUpgradeRequest()) {
Eric Erfanianccca3152017-02-22 16:32:36 -08001464 LogUtil.i("InCallActivity.getShouldShowVideoUi", "upgrading to video");
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001465 return new ShouldShowUiResult(true, call);
Eric Erfanianccca3152017-02-22 16:32:36 -08001466 }
1467
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001468 return new ShouldShowUiResult(false, null);
Eric Erfanianccca3152017-02-22 16:32:36 -08001469 }
1470
wangqi219b8702018-02-13 09:34:41 -08001471 private static ShouldShowUiResult getShouldShowRttUi() {
1472 DialerCall call = CallList.getInstance().getFirstCall();
1473 if (call == null) {
1474 LogUtil.i("InCallActivity.getShouldShowRttUi", "null call");
1475 return new ShouldShowUiResult(false, null);
1476 }
1477
wangqif6be6172018-03-30 15:57:56 -07001478 if (call.isActiveRttCall()) {
wangqi219b8702018-02-13 09:34:41 -08001479 LogUtil.i("InCallActivity.getShouldShowRttUi", "found rtt call");
1480 return new ShouldShowUiResult(true, call);
1481 }
1482
1483 if (call.hasSentRttUpgradeRequest()) {
1484 LogUtil.i("InCallActivity.getShouldShowRttUi", "upgrading to rtt");
1485 return new ShouldShowUiResult(true, call);
1486 }
1487
1488 return new ShouldShowUiResult(false, null);
1489 }
1490
Eric Erfanianccca3152017-02-22 16:32:36 -08001491 private boolean showAnswerScreenFragment(FragmentTransaction transaction, DialerCall call) {
1492 // When rejecting a call the active call can become null in which case we should continue
1493 // showing the answer screen.
1494 if (didShowAnswerScreen && call == null) {
1495 return false;
1496 }
1497
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001498 Assert.checkArgument(call != null, "didShowAnswerScreen was false but call was still null");
1499
1500 boolean isVideoUpgradeRequest = call.hasReceivedVideoUpgradeRequest();
Eric Erfanianccca3152017-02-22 16:32:36 -08001501
1502 // Check if we're already showing an answer screen for this call.
1503 if (didShowAnswerScreen) {
1504 AnswerScreen answerScreen = getAnswerScreen();
1505 if (answerScreen.getCallId().equals(call.getId())
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001506 && answerScreen.isVideoCall() == call.isVideoCall()
Eric Erfanian2ca43182017-08-31 06:57:16 -07001507 && answerScreen.isVideoUpgradeRequest() == isVideoUpgradeRequest
1508 && !answerScreen.isActionTimeout()) {
1509 LogUtil.d(
1510 "InCallActivity.showAnswerScreenFragment",
1511 "answer fragment exists for same call and has NOT been accepted/rejected/timed out");
Eric Erfanianccca3152017-02-22 16:32:36 -08001512 return false;
1513 }
Eric Erfanian2ca43182017-08-31 06:57:16 -07001514 if (answerScreen.isActionTimeout()) {
1515 LogUtil.i(
1516 "InCallActivity.showAnswerScreenFragment",
1517 "answer fragment exists but has been accepted/rejected and timed out");
1518 } else {
1519 LogUtil.i(
1520 "InCallActivity.showAnswerScreenFragment",
1521 "answer fragment exists but arguments do not match");
1522 }
Eric Erfanianccca3152017-02-22 16:32:36 -08001523 hideAnswerScreenFragment(transaction);
1524 }
1525
1526 // Show a new answer screen.
1527 AnswerScreen answerScreen =
Eric Erfanianfc37b022017-03-21 10:11:17 -07001528 AnswerBindings.createAnswerScreen(
1529 call.getId(),
wangqif6be6172018-03-30 15:57:56 -07001530 call.isActiveRttCall(),
Eric Erfanianfc37b022017-03-21 10:11:17 -07001531 call.isVideoCall(),
1532 isVideoUpgradeRequest,
Eric Erfanian90508232017-03-24 09:31:16 -07001533 call.getVideoTech().isSelfManagedCamera(),
1534 shouldAllowAnswerAndRelease(call),
erfaniand05d8992018-03-20 19:42:26 -07001535 CallList.getInstance().getBackgroundCall() != null,
1536 call.isSpeakEasyEligible());
linyuhc3968e62017-11-20 17:40:50 -08001537 transaction.add(R.id.main, answerScreen.getAnswerScreenFragment(), Tags.ANSWER_SCREEN);
Eric Erfanianccca3152017-02-22 16:32:36 -08001538
1539 Logger.get(this).logScreenView(ScreenEvent.Type.INCOMING_CALL, this);
1540 didShowAnswerScreen = true;
1541 return true;
1542 }
1543
Eric Erfanian90508232017-03-24 09:31:16 -07001544 private boolean shouldAllowAnswerAndRelease(DialerCall call) {
1545 if (CallList.getInstance().getActiveCall() == null) {
1546 LogUtil.i("InCallActivity.shouldAllowAnswerAndRelease", "no active call");
1547 return false;
1548 }
1549 if (getSystemService(TelephonyManager.class).getPhoneType()
1550 == TelephonyManager.PHONE_TYPE_CDMA) {
1551 LogUtil.i("InCallActivity.shouldAllowAnswerAndRelease", "PHONE_TYPE_CDMA not supported");
1552 return false;
1553 }
1554 if (call.isVideoCall() || call.hasReceivedVideoUpgradeRequest()) {
1555 LogUtil.i("InCallActivity.shouldAllowAnswerAndRelease", "video call");
1556 return false;
1557 }
linyuhc3968e62017-11-20 17:40:50 -08001558 if (!ConfigProviderBindings.get(this)
1559 .getBoolean(ConfigNames.ANSWER_AND_RELEASE_ENABLED, true)) {
Eric Erfanian90508232017-03-24 09:31:16 -07001560 LogUtil.i("InCallActivity.shouldAllowAnswerAndRelease", "disabled by config");
1561 return false;
1562 }
1563
1564 return true;
1565 }
1566
Eric Erfanianccca3152017-02-22 16:32:36 -08001567 private boolean hideAnswerScreenFragment(FragmentTransaction transaction) {
1568 if (!didShowAnswerScreen) {
1569 return false;
1570 }
1571 AnswerScreen answerScreen = getAnswerScreen();
1572 if (answerScreen != null) {
1573 transaction.remove(answerScreen.getAnswerScreenFragment());
1574 }
1575
1576 didShowAnswerScreen = false;
1577 return true;
1578 }
1579
1580 private boolean showInCallScreenFragment(FragmentTransaction transaction) {
1581 if (didShowInCallScreen) {
1582 return false;
1583 }
Eric Erfanian2ca43182017-08-31 06:57:16 -07001584 InCallScreen inCallScreen = InCallBindings.createInCallScreen();
linyuhc3968e62017-11-20 17:40:50 -08001585 transaction.add(R.id.main, inCallScreen.getInCallScreenFragment(), Tags.IN_CALL_SCREEN);
Eric Erfanianccca3152017-02-22 16:32:36 -08001586 Logger.get(this).logScreenView(ScreenEvent.Type.INCALL, this);
1587 didShowInCallScreen = true;
1588 return true;
1589 }
1590
1591 private boolean hideInCallScreenFragment(FragmentTransaction transaction) {
1592 if (!didShowInCallScreen) {
1593 return false;
1594 }
1595 InCallScreen inCallScreen = getInCallScreen();
1596 if (inCallScreen != null) {
Eric Erfanian2ca43182017-08-31 06:57:16 -07001597 transaction.remove(inCallScreen.getInCallScreenFragment());
Eric Erfanianccca3152017-02-22 16:32:36 -08001598 }
1599 didShowInCallScreen = false;
1600 return true;
1601 }
1602
wangqi219b8702018-02-13 09:34:41 -08001603 private boolean showRttCallScreenFragment(FragmentTransaction transaction, DialerCall call) {
1604 if (didShowRttCallScreen) {
1605 // This shouldn't happen since only one RTT call is allow at same time.
1606 if (!getRttCallScreen().getCallId().equals(call.getId())) {
1607 LogUtil.e("InCallActivity.showRttCallScreenFragment", "RTT call id doesn't match");
1608 }
1609 return false;
1610 }
1611 RttCallScreen rttCallScreen = RttBindings.createRttCallScreen(call.getId());
1612 transaction.add(R.id.main, rttCallScreen.getRttCallScreenFragment(), Tags.RTT_CALL_SCREEN);
1613 Logger.get(this).logScreenView(ScreenEvent.Type.INCALL, this);
1614 didShowRttCallScreen = true;
1615 return true;
1616 }
1617
1618 private boolean hideRttCallScreenFragment(FragmentTransaction transaction) {
1619 if (!didShowRttCallScreen) {
1620 return false;
1621 }
1622 RttCallScreen rttCallScreen = getRttCallScreen();
1623 if (rttCallScreen != null) {
1624 transaction.remove(rttCallScreen.getRttCallScreenFragment());
1625 }
1626 didShowRttCallScreen = false;
1627 return true;
1628 }
1629
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001630 private boolean showVideoCallScreenFragment(FragmentTransaction transaction, DialerCall call) {
Eric Erfanianccca3152017-02-22 16:32:36 -08001631 if (didShowVideoCallScreen) {
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001632 VideoCallScreen videoCallScreen = getVideoCallScreen();
1633 if (videoCallScreen.getCallId().equals(call.getId())) {
1634 return false;
1635 }
1636 LogUtil.i(
1637 "InCallActivity.showVideoCallScreenFragment",
1638 "video call fragment exists but arguments do not match");
1639 hideVideoCallScreenFragment(transaction);
Eric Erfanianccca3152017-02-22 16:32:36 -08001640 }
1641
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001642 LogUtil.i("InCallActivity.showVideoCallScreenFragment", "call: %s", call);
1643
Eric Erfanian90508232017-03-24 09:31:16 -07001644 VideoCallScreen videoCallScreen =
1645 VideoBindings.createVideoCallScreen(
1646 call.getId(), call.getVideoTech().shouldUseSurfaceView());
linyuhc3968e62017-11-20 17:40:50 -08001647 transaction.add(
1648 R.id.main, videoCallScreen.getVideoCallScreenFragment(), Tags.VIDEO_CALL_SCREEN);
Eric Erfanianccca3152017-02-22 16:32:36 -08001649
1650 Logger.get(this).logScreenView(ScreenEvent.Type.INCALL, this);
1651 didShowVideoCallScreen = true;
1652 return true;
1653 }
1654
1655 private boolean hideVideoCallScreenFragment(FragmentTransaction transaction) {
1656 if (!didShowVideoCallScreen) {
1657 return false;
1658 }
1659 VideoCallScreen videoCallScreen = getVideoCallScreen();
1660 if (videoCallScreen != null) {
1661 transaction.remove(videoCallScreen.getVideoCallScreenFragment());
1662 }
1663 didShowVideoCallScreen = false;
1664 return true;
1665 }
1666
linyuhc3968e62017-11-20 17:40:50 -08001667 private AnswerScreen getAnswerScreen() {
1668 return (AnswerScreen) getSupportFragmentManager().findFragmentByTag(Tags.ANSWER_SCREEN);
Eric Erfanianccca3152017-02-22 16:32:36 -08001669 }
1670
linyuhc3968e62017-11-20 17:40:50 -08001671 private InCallScreen getInCallScreen() {
1672 return (InCallScreen) getSupportFragmentManager().findFragmentByTag(Tags.IN_CALL_SCREEN);
Eric Erfanianccca3152017-02-22 16:32:36 -08001673 }
1674
linyuhc3968e62017-11-20 17:40:50 -08001675 private VideoCallScreen getVideoCallScreen() {
1676 return (VideoCallScreen) getSupportFragmentManager().findFragmentByTag(Tags.VIDEO_CALL_SCREEN);
Eric Erfanianccca3152017-02-22 16:32:36 -08001677 }
1678
wangqi219b8702018-02-13 09:34:41 -08001679 private RttCallScreen getRttCallScreen() {
1680 return (RttCallScreen) getSupportFragmentManager().findFragmentByTag(Tags.RTT_CALL_SCREEN);
1681 }
1682
wangqifd4c9f72018-03-08 18:21:50 -08001683 private InCallScreen getInCallOrRttCallScreen() {
1684 InCallScreen inCallScreen = null;
1685 if (didShowInCallScreen) {
1686 inCallScreen = getInCallScreen();
1687 }
1688 if (didShowRttCallScreen) {
1689 inCallScreen = getRttCallScreen();
1690 }
1691 return inCallScreen;
1692 }
1693
Eric Erfanianccca3152017-02-22 16:32:36 -08001694 @Override
1695 public void onPseudoScreenStateChanged(boolean isOn) {
1696 LogUtil.i("InCallActivity.onPseudoScreenStateChanged", "isOn: " + isOn);
1697 pseudoBlackScreenOverlay.setVisibility(isOn ? View.GONE : View.VISIBLE);
1698 }
1699
1700 /**
1701 * For some touch related issue, turning off the screen can be faked by drawing a black view over
1702 * the activity. All touch events started when the screen is "off" is rejected.
1703 *
1704 * @see PseudoScreenState
1705 */
1706 @Override
1707 public boolean dispatchTouchEvent(MotionEvent event) {
1708 // Reject any gesture that started when the screen is in the fake off state.
1709 if (touchDownWhenPseudoScreenOff) {
1710 if (event.getAction() == MotionEvent.ACTION_UP) {
1711 touchDownWhenPseudoScreenOff = false;
1712 }
1713 return true;
1714 }
1715 // Reject all touch event when the screen is in the fake off state.
1716 if (!InCallPresenter.getInstance().getPseudoScreenState().isOn()) {
1717 if (event.getAction() == MotionEvent.ACTION_DOWN) {
1718 touchDownWhenPseudoScreenOff = true;
1719 LogUtil.i("InCallActivity.dispatchTouchEvent", "touchDownWhenPseudoScreenOff");
1720 }
1721 return true;
1722 }
1723 return super.dispatchTouchEvent(event);
1724 }
1725
wangqi219b8702018-02-13 09:34:41 -08001726 @Override
1727 public RttCallScreenDelegate newRttCallScreenDelegate(RttCallScreen videoCallScreen) {
1728 return new RttCallPresenter();
1729 }
1730
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001731 private static class ShouldShowUiResult {
Eric Erfanianccca3152017-02-22 16:32:36 -08001732 public final boolean shouldShow;
1733 public final DialerCall call;
1734
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001735 ShouldShowUiResult(boolean shouldShow, DialerCall call) {
Eric Erfanianccca3152017-02-22 16:32:36 -08001736 this.shouldShow = shouldShow;
1737 this.call = call;
1738 }
1739 }
linyuhc3968e62017-11-20 17:40:50 -08001740
1741 private static final class IntentExtraNames {
1742 static final String FOR_FULL_SCREEN = "InCallActivity.for_full_screen_intent";
1743 static final String NEW_OUTGOING_CALL = "InCallActivity.new_outgoing_call";
1744 static final String SHOW_DIALPAD = "InCallActivity.show_dialpad";
1745 }
1746
1747 private static final class KeysForSavedInstance {
1748 static final String DIALPAD_TEXT = "InCallActivity.dialpad_text";
1749 static final String DID_SHOW_ANSWER_SCREEN = "did_show_answer_screen";
1750 static final String DID_SHOW_IN_CALL_SCREEN = "did_show_in_call_screen";
1751 static final String DID_SHOW_VIDEO_CALL_SCREEN = "did_show_video_call_screen";
wangqi153af2f2018-02-15 16:21:49 -08001752 static final String DID_SHOW_RTT_CALL_SCREEN = "did_show_rtt_call_screen";
erfaniand05d8992018-03-20 19:42:26 -07001753 static final String DID_SHOW_SPEAK_EASY_SCREEN = "did_show_speak_easy_screen";
linyuhc3968e62017-11-20 17:40:50 -08001754 }
1755
1756 /** Request codes for pending intents. */
1757 public static final class PendingIntentRequestCodes {
1758 static final int NON_FULL_SCREEN = 0;
1759 static final int FULL_SCREEN = 1;
1760 static final int BUBBLE = 2;
1761 }
1762
1763 private static final class Tags {
1764 static final String ANSWER_SCREEN = "tag_answer_screen";
1765 static final String DIALPAD_FRAGMENT = "tag_dialpad_fragment";
1766 static final String IN_CALL_SCREEN = "tag_in_call_screen";
1767 static final String INTERNATIONAL_CALL_ON_WIFI = "tag_international_call_on_wifi";
1768 static final String SELECT_ACCOUNT_FRAGMENT = "tag_select_account_fragment";
1769 static final String VIDEO_CALL_SCREEN = "tag_video_call_screen";
wangqi219b8702018-02-13 09:34:41 -08001770 static final String RTT_CALL_SCREEN = "tag_rtt_call_screen";
linyuhc3968e62017-11-20 17:40:50 -08001771 static final String POST_CHAR_DIALOG_FRAGMENT = "tag_post_char_dialog_fragment";
erfaniand05d8992018-03-20 19:42:26 -07001772 static final String SPEAK_EASY_SCREEN = "tag_speak_easy_screen";
wangqibc28ea72018-04-02 16:23:00 -07001773 static final String RTT_REQUEST_DIALOG = "tag_rtt_request_dialog";
linyuhc3968e62017-11-20 17:40:50 -08001774 }
1775
1776 private static final class ConfigNames {
1777 static final String ANSWER_AND_RELEASE_ENABLED = "answer_and_release_enabled";
1778 }
1779
1780 private static final class InternationalCallOnWifiCallback
1781 implements InternationalCallOnWifiDialogFragment.Callback {
1782 private static final String TAG = InternationalCallOnWifiCallback.class.getCanonicalName();
1783
1784 @Override
1785 public void continueCall(@NonNull String callId) {
1786 LogUtil.i(TAG, "Continuing call with ID: %s", callId);
1787 }
1788
1789 @Override
1790 public void cancelCall(@NonNull String callId) {
1791 DialerCall call = CallList.getInstance().getCallById(callId);
1792 if (call == null) {
1793 LogUtil.i(TAG, "Call destroyed before the dialog is closed");
1794 return;
1795 }
1796
1797 LogUtil.i(TAG, "Disconnecting international call on WiFi");
1798 call.disconnect();
1799 }
1800 }
1801
1802 private static final class SelectPhoneAccountListener
1803 extends SelectPhoneAccountDialogFragment.SelectPhoneAccountListener {
1804 private static final String TAG = SelectPhoneAccountListener.class.getCanonicalName();
1805
twyen73a74c32018-03-07 12:12:24 -08001806 private final Context appContext;
1807
1808 SelectPhoneAccountListener(Context appContext) {
1809 this.appContext = appContext;
1810 }
1811
linyuhc3968e62017-11-20 17:40:50 -08001812 @Override
1813 public void onPhoneAccountSelected(
1814 PhoneAccountHandle selectedAccountHandle, boolean setDefault, String callId) {
1815 DialerCall call = CallList.getInstance().getCallById(callId);
1816 LogUtil.i(TAG, "Phone account select with call:\n%s", call);
1817
1818 if (call != null) {
twyen73a74c32018-03-07 12:12:24 -08001819 call.phoneAccountSelected(selectedAccountHandle, false);
1820 if (call.getPreferredAccountRecorder() != null) {
1821 call.getPreferredAccountRecorder().record(appContext, selectedAccountHandle, setDefault);
1822 }
linyuhc3968e62017-11-20 17:40:50 -08001823 }
1824 }
1825
1826 @Override
1827 public void onDialogDismissed(String callId) {
1828 DialerCall call = CallList.getInstance().getCallById(callId);
1829 LogUtil.i(TAG, "Disconnecting call:\n%s" + call);
1830
1831 if (call != null) {
1832 call.disconnect();
1833 }
1834 }
1835 }
Eric Erfanianccca3152017-02-22 16:32:36 -08001836}