blob: 2ec17308fe78865f6bb847ee869444fe37ec57e2 [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;
twyena1723252018-04-24 17:02:57 -070064import com.android.dialer.common.concurrent.UiListener;
Eric Erfanian2ca43182017-08-31 06:57:16 -070065import com.android.dialer.configprovider.ConfigProviderBindings;
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;
twyena1723252018-04-24 17:02:57 -070072import com.android.dialer.preferredsim.PreferredAccountWorker.Result;
twyen56f79ba2018-04-30 14:25:46 -070073import com.android.dialer.preferredsim.PreferredSimComponent;
linyuhc3968e62017-11-20 17:40:50 -080074import com.android.dialer.util.ViewUtil;
Eric Erfanianccca3152017-02-22 16:32:36 -080075import com.android.incallui.answer.bindings.AnswerBindings;
76import com.android.incallui.answer.protocol.AnswerScreen;
77import com.android.incallui.answer.protocol.AnswerScreenDelegate;
78import com.android.incallui.answer.protocol.AnswerScreenDelegateFactory;
79import com.android.incallui.answerproximitysensor.PseudoScreenState;
linyuh57b093b2017-11-17 14:32:32 -080080import com.android.incallui.audiomode.AudioModeProvider;
Eric Erfanianccca3152017-02-22 16:32:36 -080081import com.android.incallui.call.CallList;
82import com.android.incallui.call.DialerCall;
linyuh57b093b2017-11-17 14:32:32 -080083import com.android.incallui.call.TelecomAdapter;
wangqibb94ca62018-04-27 14:34:04 -070084import com.android.incallui.call.state.DialerCallState;
Eric Erfanian2ca43182017-08-31 06:57:16 -070085import com.android.incallui.callpending.CallPendingActivity;
86import com.android.incallui.disconnectdialog.DisconnectMessage;
Eric Erfanianccca3152017-02-22 16:32:36 -080087import com.android.incallui.incall.bindings.InCallBindings;
88import com.android.incallui.incall.protocol.InCallButtonUiDelegate;
89import com.android.incallui.incall.protocol.InCallButtonUiDelegateFactory;
90import com.android.incallui.incall.protocol.InCallScreen;
91import com.android.incallui.incall.protocol.InCallScreenDelegate;
92import com.android.incallui.incall.protocol.InCallScreenDelegateFactory;
linyuh7b86f562017-11-16 11:24:09 -080093import com.android.incallui.incalluilock.InCallUiLock;
wangqi219b8702018-02-13 09:34:41 -080094import com.android.incallui.rtt.bindings.RttBindings;
95import com.android.incallui.rtt.protocol.RttCallScreen;
96import com.android.incallui.rtt.protocol.RttCallScreenDelegate;
97import com.android.incallui.rtt.protocol.RttCallScreenDelegateFactory;
erfaniand05d8992018-03-20 19:42:26 -070098import com.android.incallui.speakeasy.SpeakEasyCallManager;
linyuhf99f6302017-11-15 11:23:51 -080099import com.android.incallui.telecomeventui.InternationalCallOnWifiDialogFragment;
Eric Erfanianccca3152017-02-22 16:32:36 -0800100import com.android.incallui.video.bindings.VideoBindings;
101import com.android.incallui.video.protocol.VideoCallScreen;
102import com.android.incallui.video.protocol.VideoCallScreenDelegate;
103import com.android.incallui.video.protocol.VideoCallScreenDelegateFactory;
linyuhc3968e62017-11-20 17:40:50 -0800104import com.google.common.base.Optional;
twyena1723252018-04-24 17:02:57 -0700105import com.google.common.util.concurrent.ListenableFuture;
linyuhc3968e62017-11-20 17:40:50 -0800106import java.lang.annotation.Retention;
107import java.lang.annotation.RetentionPolicy;
108import java.util.ArrayList;
109import java.util.List;
Eric Erfanianccca3152017-02-22 16:32:36 -0800110
111/** Version of {@link InCallActivity} that shows the new UI */
112public class InCallActivity extends TransactionSafeFragmentActivity
113 implements AnswerScreenDelegateFactory,
114 InCallScreenDelegateFactory,
115 InCallButtonUiDelegateFactory,
116 VideoCallScreenDelegateFactory,
wangqi219b8702018-02-13 09:34:41 -0800117 RttCallScreenDelegateFactory,
Eric Erfanianccca3152017-02-22 16:32:36 -0800118 PseudoScreenState.StateChangedListener {
119
linyuhc3968e62017-11-20 17:40:50 -0800120 @Retention(RetentionPolicy.SOURCE)
121 @IntDef({
122 DIALPAD_REQUEST_NONE,
123 DIALPAD_REQUEST_SHOW,
124 DIALPAD_REQUEST_HIDE,
125 })
126 @interface DialpadRequestType {}
Eric Erfanian2ca43182017-08-31 06:57:16 -0700127
linyuhc3968e62017-11-20 17:40:50 -0800128 private static final int DIALPAD_REQUEST_NONE = 1;
129 private static final int DIALPAD_REQUEST_SHOW = 2;
130 private static final int DIALPAD_REQUEST_HIDE = 3;
linyuh57b093b2017-11-17 14:32:32 -0800131
linyuhc3968e62017-11-20 17:40:50 -0800132 private static Optional<Integer> audioRouteForTesting = Optional.absent();
linyuh57b093b2017-11-17 14:32:32 -0800133
twyen73a74c32018-03-07 12:12:24 -0800134 private SelectPhoneAccountListener selectPhoneAccountListener;
twyena1723252018-04-24 17:02:57 -0700135 private UiListener<Result> preferredAccountWorkerResultListener;
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;
linyuhc3968e62017-11-20 17:40:50 -0800145 private boolean allowOrientationChange;
146 private boolean animateDialpadOnShow;
Eric Erfanianccca3152017-02-22 16:32:36 -0800147 private boolean didShowAnswerScreen;
148 private boolean didShowInCallScreen;
149 private boolean didShowVideoCallScreen;
wangqi219b8702018-02-13 09:34:41 -0800150 private boolean didShowRttCallScreen;
erfaniand05d8992018-03-20 19:42:26 -0700151 private boolean didShowSpeakEasyScreen;
erfanian612d13a2018-04-04 15:27:57 -0700152 private String lastShownSpeakEasyScreenUniqueCallid = "";
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 touchDownWhenPseudoScreenOff;
159 private int[] backgroundDrawableColors;
160 @DialpadRequestType private int showDialpadRequest = DIALPAD_REQUEST_NONE;
erfaniand05d8992018-03-20 19:42:26 -0700161 private SpeakEasyCallManager speakEasyCallManager;
Eric Erfanianccca3152017-02-22 16:32:36 -0800162
163 public static Intent getIntent(
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700164 Context context, boolean showDialpad, boolean newOutgoingCall, boolean isForFullScreen) {
Eric Erfanianccca3152017-02-22 16:32:36 -0800165 Intent intent = new Intent(Intent.ACTION_MAIN, null);
166 intent.setFlags(Intent.FLAG_ACTIVITY_NO_USER_ACTION | Intent.FLAG_ACTIVITY_NEW_TASK);
167 intent.setClass(context, InCallActivity.class);
linyuhc3968e62017-11-20 17:40:50 -0800168 if (showDialpad) {
169 intent.putExtra(IntentExtraNames.SHOW_DIALPAD, true);
170 }
171 intent.putExtra(IntentExtraNames.NEW_OUTGOING_CALL, newOutgoingCall);
172 intent.putExtra(IntentExtraNames.FOR_FULL_SCREEN, isForFullScreen);
Eric Erfanianccca3152017-02-22 16:32:36 -0800173 return intent;
174 }
175
176 @Override
177 protected void onResumeFragments() {
178 super.onResumeFragments();
179 if (needDismissPendingDialogs) {
180 dismissPendingDialogs();
181 }
182 }
183
184 @Override
linyuhc3968e62017-11-20 17:40:50 -0800185 protected void onCreate(Bundle bundle) {
Eric Erfanian2ca43182017-08-31 06:57:16 -0700186 Trace.beginSection("InCallActivity.onCreate");
linyuhc3968e62017-11-20 17:40:50 -0800187 super.onCreate(bundle);
Eric Erfanianccca3152017-02-22 16:32:36 -0800188
twyena1723252018-04-24 17:02:57 -0700189 preferredAccountWorkerResultListener =
190 DialerExecutorComponent.get(this)
191 .createUiListener(getFragmentManager(), "preferredAccountWorkerResultListener");
192
twyen73a74c32018-03-07 12:12:24 -0800193 selectPhoneAccountListener = new SelectPhoneAccountListener(getApplicationContext());
194
linyuhc3968e62017-11-20 17:40:50 -0800195 if (bundle != null) {
196 didShowAnswerScreen = bundle.getBoolean(KeysForSavedInstance.DID_SHOW_ANSWER_SCREEN);
197 didShowInCallScreen = bundle.getBoolean(KeysForSavedInstance.DID_SHOW_IN_CALL_SCREEN);
198 didShowVideoCallScreen = bundle.getBoolean(KeysForSavedInstance.DID_SHOW_VIDEO_CALL_SCREEN);
wangqi153af2f2018-02-15 16:21:49 -0800199 didShowRttCallScreen = bundle.getBoolean(KeysForSavedInstance.DID_SHOW_RTT_CALL_SCREEN);
wangqic46cfd22018-05-22 15:10:05 -0700200 didShowSpeakEasyScreen = bundle.getBoolean(KeysForSavedInstance.DID_SHOW_SPEAK_EASY_SCREEN);
Eric Erfanianccca3152017-02-22 16:32:36 -0800201 }
202
linyuhc3968e62017-11-20 17:40:50 -0800203 setWindowFlags();
204 setContentView(R.layout.incall_screen);
205 internalResolveIntent(getIntent());
206
207 boolean isLandscape =
208 getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE;
209 boolean isRtl = ViewUtil.isRtl();
210 if (isLandscape) {
211 dialpadSlideInAnimation =
212 AnimationUtils.loadAnimation(
213 this, isRtl ? R.anim.dialpad_slide_in_left : R.anim.dialpad_slide_in_right);
214 dialpadSlideOutAnimation =
215 AnimationUtils.loadAnimation(
216 this, isRtl ? R.anim.dialpad_slide_out_left : R.anim.dialpad_slide_out_right);
217 } else {
218 dialpadSlideInAnimation = AnimationUtils.loadAnimation(this, R.anim.dialpad_slide_in_bottom);
219 dialpadSlideOutAnimation =
220 AnimationUtils.loadAnimation(this, R.anim.dialpad_slide_out_bottom);
221 }
222 dialpadSlideInAnimation.setInterpolator(AnimUtils.EASE_IN);
223 dialpadSlideOutAnimation.setInterpolator(AnimUtils.EASE_OUT);
224 dialpadSlideOutAnimation.setAnimationListener(
225 new AnimationListenerAdapter() {
226 @Override
227 public void onAnimationEnd(Animation animation) {
228 hideDialpadFragment();
229 }
230 });
231
232 if (bundle != null && showDialpadRequest == DIALPAD_REQUEST_NONE) {
233 // If the dialpad was shown before, set related variables so that it can be shown and
234 // populated with the previous DTMF text during onResume().
235 if (bundle.containsKey(IntentExtraNames.SHOW_DIALPAD)) {
236 boolean showDialpad = bundle.getBoolean(IntentExtraNames.SHOW_DIALPAD);
237 showDialpadRequest = showDialpad ? DIALPAD_REQUEST_SHOW : DIALPAD_REQUEST_HIDE;
238 animateDialpadOnShow = false;
239 }
240 dtmfTextToPrepopulate = bundle.getString(KeysForSavedInstance.DIALPAD_TEXT);
241
242 SelectPhoneAccountDialogFragment selectPhoneAccountDialogFragment =
243 (SelectPhoneAccountDialogFragment)
244 getFragmentManager().findFragmentByTag(Tags.SELECT_ACCOUNT_FRAGMENT);
245 if (selectPhoneAccountDialogFragment != null) {
246 selectPhoneAccountDialogFragment.setListener(selectPhoneAccountListener);
247 }
248 }
249
linyuh69a25062017-11-15 16:18:51 -0800250 inCallOrientationEventListener = new InCallOrientationEventListener(this);
Eric Erfanianccca3152017-02-22 16:32:36 -0800251
252 getWindow()
253 .getDecorView()
254 .setSystemUiVisibility(
255 View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
256
257 pseudoBlackScreenOverlay = findViewById(R.id.psuedo_black_screen_overlay);
Eric Erfanian2ca43182017-08-31 06:57:16 -0700258 sendBroadcast(CallPendingActivity.getFinishBroadcast());
259 Trace.endSection();
zachh7a96dc72018-02-20 22:16:03 -0800260 MetricsComponent.get(this)
261 .metrics()
262 .stopTimer(Metrics.ON_CALL_ADDED_TO_ON_INCALL_UI_SHOWN_INCOMING);
263 MetricsComponent.get(this)
264 .metrics()
265 .stopTimer(Metrics.ON_CALL_ADDED_TO_ON_INCALL_UI_SHOWN_OUTGOING);
Eric Erfanianccca3152017-02-22 16:32:36 -0800266 }
267
linyuhc3968e62017-11-20 17:40:50 -0800268 private void setWindowFlags() {
269 // Allow the activity to be shown when the screen is locked and filter out touch events that are
270 // "too fat".
271 int flags =
272 WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
273 | WindowManager.LayoutParams.FLAG_IGNORE_CHEEK_PRESSES;
274
linyuhf79d1cb2017-12-15 17:49:56 -0800275 // When the audio stream is not via Bluetooth, turn on the screen once the activity is shown.
276 // When the audio stream is via Bluetooth, turn on the screen only for an incoming call.
linyuhc3968e62017-11-20 17:40:50 -0800277 final int audioRoute = getAudioRoute();
linyuhf79d1cb2017-12-15 17:49:56 -0800278 if (audioRoute != CallAudioState.ROUTE_BLUETOOTH
279 || CallList.getInstance().getIncomingCall() != null) {
linyuhc3968e62017-11-20 17:40:50 -0800280 flags |= WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON;
281 }
282
283 getWindow().addFlags(flags);
284 }
285
286 private static int getAudioRoute() {
287 if (audioRouteForTesting.isPresent()) {
288 return audioRouteForTesting.get();
289 }
290
291 return AudioModeProvider.getInstance().getAudioState().getRoute();
292 }
293
294 @VisibleForTesting(otherwise = VisibleForTesting.NONE)
295 public static void setAudioRouteForTesting(int audioRoute) {
296 audioRouteForTesting = Optional.of(audioRoute);
297 }
298
299 private void internalResolveIntent(Intent intent) {
300 if (!intent.getAction().equals(Intent.ACTION_MAIN)) {
301 return;
302 }
303
304 if (intent.hasExtra(IntentExtraNames.SHOW_DIALPAD)) {
305 // IntentExtraNames.SHOW_DIALPAD can be used to specify whether the DTMF dialpad should be
306 // initially visible. If the extra is absent, leave the dialpad in its previous state.
307 boolean showDialpad = intent.getBooleanExtra(IntentExtraNames.SHOW_DIALPAD, false);
308 relaunchedFromDialer(showDialpad);
309 }
310
311 DialerCall outgoingCall = CallList.getInstance().getOutgoingCall();
312 if (outgoingCall == null) {
313 outgoingCall = CallList.getInstance().getPendingOutgoingCall();
314 }
315 if (intent.getBooleanExtra(IntentExtraNames.NEW_OUTGOING_CALL, false)) {
316 intent.removeExtra(IntentExtraNames.NEW_OUTGOING_CALL);
317
318 // InCallActivity is responsible for disconnecting a new outgoing call if there is no way of
319 // making it (i.e. no valid call capable accounts).
linyuh122fb0b2018-03-26 13:35:32 -0700320 if (InCallPresenter.isCallWithNoValidAccounts(outgoingCall)) {
linyuhc3968e62017-11-20 17:40:50 -0800321 LogUtil.i(
322 "InCallActivity.internalResolveIntent", "Call with no valid accounts, disconnecting");
323 outgoingCall.disconnect();
324 }
325
326 dismissKeyguard(true);
327 }
328
329 if (showPhoneAccountSelectionDialog()) {
330 hideMainInCallFragment();
331 }
332 }
333
334 /**
335 * When relaunching from the dialer app, {@code showDialpad} indicates whether the dialpad should
336 * be shown on launch.
337 *
338 * @param showDialpad {@code true} to indicate the dialpad should be shown on launch, and {@code
339 * false} to indicate no change should be made to the dialpad visibility.
340 */
341 private void relaunchedFromDialer(boolean showDialpad) {
342 showDialpadRequest = showDialpad ? DIALPAD_REQUEST_SHOW : DIALPAD_REQUEST_NONE;
343 animateDialpadOnShow = true;
344
345 if (showDialpadRequest == DIALPAD_REQUEST_SHOW) {
346 // If there's only one line in use, AND it's on hold, then we're sure the user
347 // wants to use the dialpad toward the exact line, so un-hold the holding line.
348 DialerCall call = CallList.getInstance().getActiveOrBackgroundCall();
wangqibb94ca62018-04-27 14:34:04 -0700349 if (call != null && call.getState() == DialerCallState.ONHOLD) {
linyuhc3968e62017-11-20 17:40:50 -0800350 call.unhold();
351 }
352 }
353 }
354
355 /**
356 * Show a phone account selection dialog if there is a call waiting for phone account selection.
357 *
358 * @return true if the dialog was shown.
359 */
360 private boolean showPhoneAccountSelectionDialog() {
361 DialerCall waitingForAccountCall = CallList.getInstance().getWaitingForAccountCall();
362 if (waitingForAccountCall == null) {
363 return false;
364 }
365
twyen56f79ba2018-04-30 14:25:46 -0700366 PreferredAccountWorker preferredAccountWorker =
367 PreferredSimComponent.get(this).preferredAccountWorker();
linyuhc3968e62017-11-20 17:40:50 -0800368
twyen56f79ba2018-04-30 14:25:46 -0700369 Bundle extras = waitingForAccountCall.getIntentExtras();
370 List<PhoneAccountHandle> phoneAccountHandles =
371 extras == null
372 ? new ArrayList<>()
373 : extras.getParcelableArrayList(Call.AVAILABLE_PHONE_ACCOUNTS);
374
375 ListenableFuture<PreferredAccountWorker.Result> preferredAccountFuture =
376 preferredAccountWorker.selectAccount(
377 waitingForAccountCall.getNumber(), phoneAccountHandles);
twyena1723252018-04-24 17:02:57 -0700378 preferredAccountWorkerResultListener.listen(
379 this,
380 preferredAccountFuture,
381 result -> {
twyen3b2c7812018-04-30 12:13:06 -0700382 if (!isVisible()) {
383 LogUtil.i(
384 "CallingAccountSelector.showPhoneAccountSelectionDialog",
385 "activity ended before result returned");
386 return;
387 }
twyen56f79ba2018-04-30 14:25:46 -0700388 String callId = waitingForAccountCall.getId();
389 if (result.getSelectedPhoneAccountHandle().isPresent()) {
twyena1723252018-04-24 17:02:57 -0700390 selectPhoneAccountListener.onPhoneAccountSelected(
twyen56f79ba2018-04-30 14:25:46 -0700391 result.getSelectedPhoneAccountHandle().get(), false, callId);
twyena1723252018-04-24 17:02:57 -0700392 return;
393 }
twyen66adad02018-04-24 13:51:08 -0700394
twyena1723252018-04-24 17:02:57 -0700395 waitingForAccountCall.setPreferredAccountRecorder(
396 new PreferredAccountRecorder(
397 waitingForAccountCall.getNumber(),
398 result.getSuggestion().orNull(),
399 result.getDataId().orNull()));
twyena1723252018-04-24 17:02:57 -0700400 selectPhoneAccountDialogFragment =
401 SelectPhoneAccountDialogFragment.newInstance(
twyen56f79ba2018-04-30 14:25:46 -0700402 result.getDialogOptionsBuilder().get().setCallId(callId).build(),
403 selectPhoneAccountListener);
twyena1723252018-04-24 17:02:57 -0700404 selectPhoneAccountDialogFragment.show(getFragmentManager(), Tags.SELECT_ACCOUNT_FRAGMENT);
405 },
406 throwable -> {
407 throw new RuntimeException(throwable);
408 });
twyen73a74c32018-03-07 12:12:24 -0800409
linyuhc3968e62017-11-20 17:40:50 -0800410 return true;
411 }
412
Eric Erfanianccca3152017-02-22 16:32:36 -0800413 @Override
414 protected void onSaveInstanceState(Bundle out) {
linyuh57b093b2017-11-17 14:32:32 -0800415 LogUtil.enterBlock("InCallActivity.onSaveInstanceState");
416
417 // TODO: DialpadFragment should handle this as part of its own state
linyuhc3968e62017-11-20 17:40:50 -0800418 out.putBoolean(IntentExtraNames.SHOW_DIALPAD, isDialpadVisible());
linyuh57b093b2017-11-17 14:32:32 -0800419 DialpadFragment dialpadFragment = getDialpadFragment();
420 if (dialpadFragment != null) {
linyuhc3968e62017-11-20 17:40:50 -0800421 out.putString(KeysForSavedInstance.DIALPAD_TEXT, dialpadFragment.getDtmfText());
linyuh57b093b2017-11-17 14:32:32 -0800422 }
423
linyuhc3968e62017-11-20 17:40:50 -0800424 out.putBoolean(KeysForSavedInstance.DID_SHOW_ANSWER_SCREEN, didShowAnswerScreen);
425 out.putBoolean(KeysForSavedInstance.DID_SHOW_IN_CALL_SCREEN, didShowInCallScreen);
426 out.putBoolean(KeysForSavedInstance.DID_SHOW_VIDEO_CALL_SCREEN, didShowVideoCallScreen);
wangqi153af2f2018-02-15 16:21:49 -0800427 out.putBoolean(KeysForSavedInstance.DID_SHOW_RTT_CALL_SCREEN, didShowRttCallScreen);
erfaniand05d8992018-03-20 19:42:26 -0700428 out.putBoolean(KeysForSavedInstance.DID_SHOW_SPEAK_EASY_SCREEN, didShowSpeakEasyScreen);
linyuh57b093b2017-11-17 14:32:32 -0800429
Eric Erfanianccca3152017-02-22 16:32:36 -0800430 super.onSaveInstanceState(out);
431 isVisible = false;
432 }
433
434 @Override
435 protected void onStart() {
Eric Erfanian2ca43182017-08-31 06:57:16 -0700436 Trace.beginSection("InCallActivity.onStart");
Eric Erfanianccca3152017-02-22 16:32:36 -0800437 super.onStart();
linyuh57b093b2017-11-17 14:32:32 -0800438
Eric Erfanianccca3152017-02-22 16:32:36 -0800439 isVisible = true;
440 showMainInCallFragment();
linyuh57b093b2017-11-17 14:32:32 -0800441
442 InCallPresenter.getInstance().setActivity(this);
443 enableInCallOrientationEventListener(
444 getRequestedOrientation()
445 == InCallOrientationEventListener.ACTIVITY_PREFERENCE_ALLOW_ROTATION);
446 InCallPresenter.getInstance().onActivityStarted();
447
yueg10f6e822018-01-17 15:32:18 -0800448 if (!isRecreating) {
449 InCallPresenter.getInstance().onUiShowing(true);
450 }
451
linyuh437ae952018-03-26 12:46:18 -0700452 if (isInMultiWindowMode() && !getResources().getBoolean(R.bool.incall_dialpad_allowed)) {
Eric Erfanianccca3152017-02-22 16:32:36 -0800453 // Hide the dialpad because there may not be enough room
454 showDialpadFragment(false, false);
455 }
linyuh57b093b2017-11-17 14:32:32 -0800456
Eric Erfanian2ca43182017-08-31 06:57:16 -0700457 Trace.endSection();
Eric Erfanianccca3152017-02-22 16:32:36 -0800458 }
459
460 @Override
461 protected void onResume() {
Eric Erfanian2ca43182017-08-31 06:57:16 -0700462 Trace.beginSection("InCallActivity.onResume");
Eric Erfanianccca3152017-02-22 16:32:36 -0800463 super.onResume();
linyuhc3968e62017-11-20 17:40:50 -0800464
465 if (!InCallPresenter.getInstance().isReadyForTearDown()) {
466 updateTaskDescription();
linyuhc3968e62017-11-20 17:40:50 -0800467 }
468
469 // If there is a pending request to show or hide the dialpad, handle that now.
470 if (showDialpadRequest != DIALPAD_REQUEST_NONE) {
471 if (showDialpadRequest == DIALPAD_REQUEST_SHOW) {
472 // Exit fullscreen so that the user has access to the dialpad hide/show button.
473 // This is important when showing the dialpad from within dialer.
474 InCallPresenter.getInstance().setFullScreen(false /* isFullScreen */, true /* force */);
475
476 showDialpadFragment(true /* show */, animateDialpadOnShow /* animate */);
477 animateDialpadOnShow = false;
478
479 DialpadFragment dialpadFragment = getDialpadFragment();
480 if (dialpadFragment != null) {
481 dialpadFragment.setDtmfText(dtmfTextToPrepopulate);
482 dtmfTextToPrepopulate = null;
483 }
484 } else {
485 LogUtil.i("InCallActivity.onResume", "Force-hide the dialpad");
486 if (getDialpadFragment() != null) {
487 showDialpadFragment(false /* show */, false /* animate */);
488 }
489 }
490 showDialpadRequest = DIALPAD_REQUEST_NONE;
491 }
linyuhc3968e62017-11-20 17:40:50 -0800492
linyuhc3968e62017-11-20 17:40:50 -0800493 CallList.getInstance()
494 .onInCallUiShown(getIntent().getBooleanExtra(IntentExtraNames.FOR_FULL_SCREEN, false));
495
Eric Erfanianccca3152017-02-22 16:32:36 -0800496 PseudoScreenState pseudoScreenState = InCallPresenter.getInstance().getPseudoScreenState();
497 pseudoScreenState.addListener(this);
498 onPseudoScreenStateChanged(pseudoScreenState.isOn());
Eric Erfanian2ca43182017-08-31 06:57:16 -0700499 Trace.endSection();
weijiaxu650e7cc2017-10-31 12:38:54 -0700500 // add 1 sec delay to get memory snapshot so that dialer wont react slowly on resume.
501 ThreadUtil.postDelayedOnUiThread(
weijiaxuc950a9b2017-11-06 16:39:04 -0800502 () ->
zachh7a96dc72018-02-20 22:16:03 -0800503 MetricsComponent.get(this)
504 .metrics()
505 .recordMemory(Metrics.INCALL_ACTIVITY_ON_RESUME_MEMORY_EVENT_NAME),
weijiaxu650e7cc2017-10-31 12:38:54 -0700506 1000);
Eric Erfanianccca3152017-02-22 16:32:36 -0800507 }
508
Eric Erfanianccca3152017-02-22 16:32:36 -0800509 @Override
510 protected void onPause() {
Eric Erfanian2ca43182017-08-31 06:57:16 -0700511 Trace.beginSection("InCallActivity.onPause");
Eric Erfanianccca3152017-02-22 16:32:36 -0800512 super.onPause();
linyuh57b093b2017-11-17 14:32:32 -0800513
514 DialpadFragment dialpadFragment = getDialpadFragment();
515 if (dialpadFragment != null) {
516 dialpadFragment.onDialerKeyUp(null);
517 }
518
Eric Erfanianccca3152017-02-22 16:32:36 -0800519 InCallPresenter.getInstance().getPseudoScreenState().removeListener(this);
Eric Erfanian2ca43182017-08-31 06:57:16 -0700520 Trace.endSection();
Eric Erfanianccca3152017-02-22 16:32:36 -0800521 }
522
523 @Override
524 protected void onStop() {
Eric Erfanian2ca43182017-08-31 06:57:16 -0700525 Trace.beginSection("InCallActivity.onStop");
wangqi4d705e52017-09-28 12:23:35 -0700526 isVisible = false;
Eric Erfanianccca3152017-02-22 16:32:36 -0800527 super.onStop();
linyuh57b093b2017-11-17 14:32:32 -0800528
529 // Disconnects the call waiting for a phone account when the activity is hidden (e.g., after the
530 // user presses the home button).
531 // Without this the pending call will get stuck on phone account selection and new calls can't
532 // be created.
533 // Skip this when the screen is locked since the activity may complete its current life cycle
534 // and restart.
linyuhc3968e62017-11-20 17:40:50 -0800535 if (!isRecreating && !getSystemService(KeyguardManager.class).isKeyguardLocked()) {
linyuh57b093b2017-11-17 14:32:32 -0800536 DialerCall waitingForAccountCall = CallList.getInstance().getWaitingForAccountCall();
537 if (waitingForAccountCall != null) {
538 waitingForAccountCall.disconnect();
539 }
540 }
541
542 enableInCallOrientationEventListener(false);
543 InCallPresenter.getInstance().updateIsChangingConfigurations();
544 InCallPresenter.getInstance().onActivityStopped();
linyuhc3968e62017-11-20 17:40:50 -0800545 if (!isRecreating) {
yueg10f6e822018-01-17 15:32:18 -0800546 InCallPresenter.getInstance().onUiShowing(false);
wangqie6060522018-04-05 11:47:15 -0700547 }
548 if (errorDialog != null) {
549 errorDialog.dismiss();
linyuh57b093b2017-11-17 14:32:32 -0800550 }
551
yueg10f6e822018-01-17 15:32:18 -0800552 if (isFinishing()) {
553 InCallPresenter.getInstance().unsetActivity(this);
554 }
555
Eric Erfanian2ca43182017-08-31 06:57:16 -0700556 Trace.endSection();
Eric Erfanianccca3152017-02-22 16:32:36 -0800557 }
558
559 @Override
560 protected void onDestroy() {
Eric Erfanian2ca43182017-08-31 06:57:16 -0700561 Trace.beginSection("InCallActivity.onDestroy");
Eric Erfanianccca3152017-02-22 16:32:36 -0800562 super.onDestroy();
linyuh57b093b2017-11-17 14:32:32 -0800563
564 InCallPresenter.getInstance().unsetActivity(this);
565 InCallPresenter.getInstance().updateIsChangingConfigurations();
Eric Erfanian2ca43182017-08-31 06:57:16 -0700566 Trace.endSection();
Eric Erfanianccca3152017-02-22 16:32:36 -0800567 }
568
569 @Override
570 public void finish() {
571 if (shouldCloseActivityOnFinish()) {
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700572 // When user select incall ui from recents after the call is disconnected, it tries to launch
573 // a new InCallActivity but InCallPresenter is already teared down at this point, which causes
574 // crash.
575 // By calling finishAndRemoveTask() instead of finish() the task associated with
576 // InCallActivity is cleared completely. So system won't try to create a new InCallActivity in
577 // this case.
578 //
579 // Calling finish won't clear the task and normally when an activity finishes it shouldn't
580 // clear the task since there could be parent activity in the same task that's still alive.
581 // But InCallActivity is special since it's singleInstance which means it's root activity and
582 // only instance of activity in the task. So it should be safe to also remove task when
583 // finishing.
584 // It's also necessary in the sense of it's excluded from recents. So whenever the activity
585 // finishes, the task should also be removed since it doesn't make sense to go back to it in
586 // anyway anymore.
587 super.finishAndRemoveTask();
Eric Erfanianccca3152017-02-22 16:32:36 -0800588 }
589 }
590
591 private boolean shouldCloseActivityOnFinish() {
linyuhc3968e62017-11-20 17:40:50 -0800592 if (!isVisible) {
Eric Erfanianccca3152017-02-22 16:32:36 -0800593 LogUtil.i(
594 "InCallActivity.shouldCloseActivityOnFinish",
595 "allowing activity to be closed because it's not visible");
596 return true;
597 }
598
twyen8efb4952017-10-06 16:35:54 -0700599 if (InCallPresenter.getInstance().isInCallUiLocked()) {
Eric Erfanianccca3152017-02-22 16:32:36 -0800600 LogUtil.i(
601 "InCallActivity.shouldCloseActivityOnFinish",
twyen8efb4952017-10-06 16:35:54 -0700602 "in call ui is locked, not closing activity");
Eric Erfanianccca3152017-02-22 16:32:36 -0800603 return false;
604 }
605
606 LogUtil.i(
607 "InCallActivity.shouldCloseActivityOnFinish",
twyen8efb4952017-10-06 16:35:54 -0700608 "activity is visible and has no locks, allowing activity to close");
Eric Erfanianccca3152017-02-22 16:32:36 -0800609 return true;
610 }
611
612 @Override
613 protected void onNewIntent(Intent intent) {
linyuhc3968e62017-11-20 17:40:50 -0800614 LogUtil.enterBlock("InCallActivity.onNewIntent");
Eric Erfanianccca3152017-02-22 16:32:36 -0800615
616 // If the screen is off, we need to make sure it gets turned on for incoming calls.
617 // This normally works just fine thanks to FLAG_TURN_SCREEN_ON but that only works
618 // when the activity is first created. Therefore, to ensure the screen is turned on
619 // for the call waiting case, we recreate() the current activity. There should be no jank from
620 // this since the screen is already off and will remain so until our new activity is up.
linyuhc3968e62017-11-20 17:40:50 -0800621 if (!isVisible) {
622 onNewIntent(intent, true /* isRecreating */);
Eric Erfanianccca3152017-02-22 16:32:36 -0800623 LogUtil.i("InCallActivity.onNewIntent", "Restarting InCallActivity to force screen on.");
624 recreate();
Eric Erfanian10b34a52017-05-04 08:23:17 -0700625 } else {
linyuhc3968e62017-11-20 17:40:50 -0800626 onNewIntent(intent, false /* isRecreating */);
627 }
628 }
629
yuega3305352018-01-09 11:02:47 -0800630 @VisibleForTesting
631 void onNewIntent(Intent intent, boolean isRecreating) {
linyuhc3968e62017-11-20 17:40:50 -0800632 this.isRecreating = isRecreating;
633
634 // We're being re-launched with a new Intent. Since it's possible for a single InCallActivity
635 // instance to persist indefinitely (even if we finish() ourselves), this sequence can
636 // happen any time the InCallActivity needs to be displayed.
637
638 // Stash away the new intent so that we can get it in the future by calling getIntent().
639 // Otherwise getIntent() will return the original Intent from when we first got created.
640 setIntent(intent);
641
642 // Activities are always paused before receiving a new intent, so we can count on our onResume()
643 // method being called next.
644
645 // Just like in onCreate(), handle the intent.
646 // Skip if InCallActivity is going to be recreated since this will be called in onCreate().
647 if (!isRecreating) {
648 internalResolveIntent(intent);
Eric Erfanianccca3152017-02-22 16:32:36 -0800649 }
650 }
651
652 @Override
653 public void onBackPressed() {
linyuh57b093b2017-11-17 14:32:32 -0800654 LogUtil.enterBlock("InCallActivity.onBackPressed");
655
linyuhc3968e62017-11-20 17:40:50 -0800656 if (!isVisible) {
linyuh57b093b2017-11-17 14:32:32 -0800657 return;
Eric Erfanianccca3152017-02-22 16:32:36 -0800658 }
linyuh57b093b2017-11-17 14:32:32 -0800659
660 if (!getCallCardFragmentVisible()) {
661 return;
662 }
663
664 DialpadFragment dialpadFragment = getDialpadFragment();
665 if (dialpadFragment != null && dialpadFragment.isVisible()) {
666 showDialpadFragment(false /* show */, true /* animate */);
667 return;
668 }
669
670 if (CallList.getInstance().getIncomingCall() != null) {
671 LogUtil.i(
672 "InCallActivity.onBackPressed",
673 "Ignore the press of the back key when an incoming call is ringing");
674 return;
675 }
676
677 // Nothing special to do. Fall back to the default behavior.
678 super.onBackPressed();
Eric Erfanianccca3152017-02-22 16:32:36 -0800679 }
680
681 @Override
682 public boolean onOptionsItemSelected(MenuItem item) {
683 LogUtil.i("InCallActivity.onOptionsItemSelected", "item: " + item);
684 if (item.getItemId() == android.R.id.home) {
685 onBackPressed();
686 return true;
687 }
688 return super.onOptionsItemSelected(item);
689 }
690
691 @Override
692 public boolean onKeyUp(int keyCode, KeyEvent event) {
linyuh57b093b2017-11-17 14:32:32 -0800693 DialpadFragment dialpadFragment = getDialpadFragment();
694 if (dialpadFragment != null
695 && dialpadFragment.isVisible()
696 && dialpadFragment.onDialerKeyUp(event)) {
697 return true;
698 }
699
700 if (keyCode == KeyEvent.KEYCODE_CALL) {
701 // Always consume KEYCODE_CALL to ensure the PhoneWindow won't do anything with it.
702 return true;
703 }
704
705 return super.onKeyUp(keyCode, event);
Eric Erfanianccca3152017-02-22 16:32:36 -0800706 }
707
708 @Override
709 public boolean onKeyDown(int keyCode, KeyEvent event) {
linyuh57b093b2017-11-17 14:32:32 -0800710 switch (keyCode) {
711 case KeyEvent.KEYCODE_CALL:
712 if (!InCallPresenter.getInstance().handleCallKey()) {
713 LogUtil.e(
714 "InCallActivity.onKeyDown",
715 "InCallPresenter should always handle KEYCODE_CALL in onKeyDown");
716 }
717 // Always consume KEYCODE_CALL to ensure the PhoneWindow won't do anything with it.
718 return true;
719
720 // Note that KEYCODE_ENDCALL isn't handled here as the standard system-wide handling of it
721 // is exactly what's needed, namely
722 // (1) "hang up" if there's an active call, or
723 // (2) "don't answer" if there's an incoming call.
724 // (See PhoneWindowManager for implementation details.)
725
726 case KeyEvent.KEYCODE_CAMERA:
727 // Consume KEYCODE_CAMERA since it's easy to accidentally press the camera button.
728 return true;
729
730 case KeyEvent.KEYCODE_VOLUME_UP:
731 case KeyEvent.KEYCODE_VOLUME_DOWN:
732 case KeyEvent.KEYCODE_VOLUME_MUTE:
733 // Ringer silencing handled by PhoneWindowManager.
734 break;
735
736 case KeyEvent.KEYCODE_MUTE:
737 TelecomAdapter.getInstance()
738 .mute(!AudioModeProvider.getInstance().getAudioState().isMuted());
739 return true;
740
741 case KeyEvent.KEYCODE_SLASH:
742 // When verbose logging is enabled, dump the view for debugging/testing purposes.
743 if (LogUtil.isVerboseEnabled()) {
744 View decorView = getWindow().getDecorView();
745 LogUtil.v("InCallActivity.onKeyDown", "View dump:\n%s", decorView);
746 return true;
747 }
748 break;
749
750 case KeyEvent.KEYCODE_EQUALS:
751 break;
752
753 default: // fall out
754 }
755
756 // Pass other key events to DialpadFragment's "onDialerKeyDown" method in case the user types
757 // in DTMF (Dual-tone multi-frequency signaling) code.
758 DialpadFragment dialpadFragment = getDialpadFragment();
759 if (dialpadFragment != null
760 && dialpadFragment.isVisible()
761 && dialpadFragment.onDialerKeyDown(event)) {
762 return true;
763 }
764
765 return super.onKeyDown(keyCode, event);
Eric Erfanianccca3152017-02-22 16:32:36 -0800766 }
767
768 public boolean isInCallScreenAnimating() {
769 return false;
770 }
771
772 public void showConferenceFragment(boolean show) {
773 if (show) {
774 startActivity(new Intent(this, ManageConferenceActivity.class));
775 }
776 }
777
linyuhc3968e62017-11-20 17:40:50 -0800778 public void showDialpadFragment(boolean show, boolean animate) {
779 if (show == isDialpadVisible()) {
780 return;
Eric Erfanianccca3152017-02-22 16:32:36 -0800781 }
linyuhc3968e62017-11-20 17:40:50 -0800782
783 FragmentManager dialpadFragmentManager = getDialpadFragmentManager();
784 if (dialpadFragmentManager == null) {
785 LogUtil.i("InCallActivity.showDialpadFragment", "Unable to obtain a FragmentManager");
786 return;
787 }
788
789 if (!animate) {
790 if (show) {
791 showDialpadFragment();
792 } else {
793 hideDialpadFragment();
794 }
795 } else {
796 if (show) {
797 showDialpadFragment();
798 getDialpadFragment().animateShowDialpad();
799 }
800 getDialpadFragment()
801 .getView()
802 .startAnimation(show ? dialpadSlideInAnimation : dialpadSlideOutAnimation);
803 }
804
805 ProximitySensor sensor = InCallPresenter.getInstance().getProximitySensor();
806 if (sensor != null) {
807 sensor.onDialpadVisible(show);
808 }
809 showDialpadRequest = DIALPAD_REQUEST_NONE;
linyuhc3968e62017-11-20 17:40:50 -0800810 }
811
812 private void showDialpadFragment() {
813 FragmentManager dialpadFragmentManager = getDialpadFragmentManager();
814 if (dialpadFragmentManager == null) {
815 return;
816 }
817
818 FragmentTransaction transaction = dialpadFragmentManager.beginTransaction();
819 DialpadFragment dialpadFragment = getDialpadFragment();
820 if (dialpadFragment == null) {
wangqifd4c9f72018-03-08 18:21:50 -0800821 dialpadFragment = new DialpadFragment();
822 transaction.add(getDialpadContainerId(), dialpadFragment, Tags.DIALPAD_FRAGMENT);
linyuhc3968e62017-11-20 17:40:50 -0800823 } else {
824 transaction.show(dialpadFragment);
calderwoodrad5883872017-12-12 15:29:12 -0800825 dialpadFragment.setUserVisibleHint(true);
linyuhc3968e62017-11-20 17:40:50 -0800826 }
wangqifd4c9f72018-03-08 18:21:50 -0800827 // RTT call screen doesn't show end call button inside dialpad, thus the space reserved for end
828 // call button should be removed.
829 dialpadFragment.setShouldShowEndCallSpace(didShowInCallScreen);
linyuhc3968e62017-11-20 17:40:50 -0800830 transaction.commitAllowingStateLoss();
831 dialpadFragmentManager.executePendingTransactions();
832
833 Logger.get(this).logScreenView(ScreenEvent.Type.INCALL_DIALPAD, this);
wangqi73ed6132018-05-21 15:57:36 -0700834 getInCallOrRttCallScreen().onInCallScreenDialpadVisibilityChange(true);
linyuhc3968e62017-11-20 17:40:50 -0800835 }
836
837 private void hideDialpadFragment() {
838 FragmentManager dialpadFragmentManager = getDialpadFragmentManager();
839 if (dialpadFragmentManager == null) {
840 return;
841 }
842
calderwoodrad5883872017-12-12 15:29:12 -0800843 DialpadFragment dialpadFragment = getDialpadFragment();
linyuhc3968e62017-11-20 17:40:50 -0800844 if (dialpadFragment != null) {
845 FragmentTransaction transaction = dialpadFragmentManager.beginTransaction();
846 transaction.hide(dialpadFragment);
847 transaction.commitAllowingStateLoss();
848 dialpadFragmentManager.executePendingTransactions();
calderwoodrad5883872017-12-12 15:29:12 -0800849 dialpadFragment.setUserVisibleHint(false);
wangqi73ed6132018-05-21 15:57:36 -0700850 getInCallOrRttCallScreen().onInCallScreenDialpadVisibilityChange(false);
linyuhc3968e62017-11-20 17:40:50 -0800851 }
Eric Erfanianccca3152017-02-22 16:32:36 -0800852 }
853
854 public boolean isDialpadVisible() {
linyuh69a25062017-11-15 16:18:51 -0800855 DialpadFragment dialpadFragment = getDialpadFragment();
calderwoodraa584bcd2018-01-24 12:19:56 -0800856 return dialpadFragment != null
857 && dialpadFragment.isAdded()
858 && !dialpadFragment.isHidden()
859 && dialpadFragment.getView() != null
860 && dialpadFragment.getUserVisibleHint();
linyuh69a25062017-11-15 16:18:51 -0800861 }
862
linyuhc3968e62017-11-20 17:40:50 -0800863 /** Returns the {@link DialpadFragment} that's shown by this activity, or {@code null} */
linyuh69a25062017-11-15 16:18:51 -0800864 @Nullable
linyuhc3968e62017-11-20 17:40:50 -0800865 private DialpadFragment getDialpadFragment() {
linyuh69a25062017-11-15 16:18:51 -0800866 FragmentManager fragmentManager = getDialpadFragmentManager();
867 if (fragmentManager == null) {
868 return null;
869 }
linyuhc3968e62017-11-20 17:40:50 -0800870 return (DialpadFragment) fragmentManager.findFragmentByTag(Tags.DIALPAD_FRAGMENT);
Eric Erfanianccca3152017-02-22 16:32:36 -0800871 }
872
873 public void onForegroundCallChanged(DialerCall newForegroundCall) {
linyuh57b093b2017-11-17 14:32:32 -0800874 updateTaskDescription();
875
876 if (newForegroundCall == null || !didShowAnswerScreen) {
Eric Erfanianccca3152017-02-22 16:32:36 -0800877 LogUtil.v("InCallActivity.onForegroundCallChanged", "resetting background color");
linyuh57b093b2017-11-17 14:32:32 -0800878 updateWindowBackgroundColor(0 /* progress */);
Eric Erfanianccca3152017-02-22 16:32:36 -0800879 }
880 }
881
linyuhc3968e62017-11-20 17:40:50 -0800882 private void updateTaskDescription() {
linyuh57b093b2017-11-17 14:32:32 -0800883 int color =
884 getResources().getBoolean(R.bool.is_layout_landscape)
885 ? ResourcesCompat.getColor(
886 getResources(), R.color.statusbar_background_color, getTheme())
887 : InCallPresenter.getInstance().getThemeColorManager().getSecondaryColor();
888 setTaskDescription(
889 new TaskDescription(
890 getResources().getString(R.string.notification_ongoing_call), null /* icon */, color));
891 }
892
Eric Erfanianccca3152017-02-22 16:32:36 -0800893 public void updateWindowBackgroundColor(@FloatRange(from = -1f, to = 1.0f) float progress) {
894 ThemeColorManager themeColorManager = InCallPresenter.getInstance().getThemeColorManager();
895 @ColorInt int top;
896 @ColorInt int middle;
897 @ColorInt int bottom;
898 @ColorInt int gray = 0x66000000;
899
linyuh437ae952018-03-26 12:46:18 -0700900 if (isInMultiWindowMode()) {
Eric Erfanianccca3152017-02-22 16:32:36 -0800901 top = themeColorManager.getBackgroundColorSolid();
902 middle = themeColorManager.getBackgroundColorSolid();
903 bottom = themeColorManager.getBackgroundColorSolid();
904 } else {
905 top = themeColorManager.getBackgroundColorTop();
906 middle = themeColorManager.getBackgroundColorMiddle();
907 bottom = themeColorManager.getBackgroundColorBottom();
908 }
909
910 if (progress < 0) {
911 float correctedProgress = Math.abs(progress);
912 top = ColorUtils.blendARGB(top, gray, correctedProgress);
913 middle = ColorUtils.blendARGB(middle, gray, correctedProgress);
914 bottom = ColorUtils.blendARGB(bottom, gray, correctedProgress);
915 }
916
917 boolean backgroundDirty = false;
918 if (backgroundDrawable == null) {
919 backgroundDrawableColors = new int[] {top, middle, bottom};
920 backgroundDrawable = new GradientDrawable(Orientation.TOP_BOTTOM, backgroundDrawableColors);
921 backgroundDirty = true;
922 } else {
923 if (backgroundDrawableColors[0] != top) {
924 backgroundDrawableColors[0] = top;
925 backgroundDirty = true;
926 }
927 if (backgroundDrawableColors[1] != middle) {
928 backgroundDrawableColors[1] = middle;
929 backgroundDirty = true;
930 }
931 if (backgroundDrawableColors[2] != bottom) {
932 backgroundDrawableColors[2] = bottom;
933 backgroundDirty = true;
934 }
935 if (backgroundDirty) {
936 backgroundDrawable.setColors(backgroundDrawableColors);
937 }
938 }
939
940 if (backgroundDirty) {
941 getWindow().setBackgroundDrawable(backgroundDrawable);
942 }
943 }
944
945 public boolean isVisible() {
946 return isVisible;
947 }
948
949 public boolean getCallCardFragmentVisible() {
erfaniand05d8992018-03-20 19:42:26 -0700950 return didShowInCallScreen
951 || didShowVideoCallScreen
952 || didShowRttCallScreen
953 || didShowSpeakEasyScreen;
Eric Erfanianccca3152017-02-22 16:32:36 -0800954 }
955
956 public void dismissKeyguard(boolean dismiss) {
linyuh9c327da2017-11-14 12:33:48 -0800957 if (dismissKeyguard == dismiss) {
958 return;
959 }
960
961 dismissKeyguard = dismiss;
962 if (dismiss) {
963 getWindow().addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);
964 } else {
965 getWindow().clearFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);
966 }
Eric Erfanianccca3152017-02-22 16:32:36 -0800967 }
968
linyuhc3968e62017-11-20 17:40:50 -0800969 public void showDialogForPostCharWait(String callId, String chars) {
yuega489f512018-04-25 12:01:09 -0700970 PostCharDialogFragment fragment = new PostCharDialogFragment(callId, chars);
971 fragment.show(getSupportFragmentManager(), Tags.POST_CHAR_DIALOG_FRAGMENT);
Eric Erfanianccca3152017-02-22 16:32:36 -0800972 }
973
linyuh7b86f562017-11-16 11:24:09 -0800974 public void showDialogOrToastForDisconnectedCall(DisconnectMessage disconnectMessage) {
975 LogUtil.i(
976 "InCallActivity.showDialogOrToastForDisconnectedCall",
977 "disconnect cause: %s",
978 disconnectMessage);
979
980 if (disconnectMessage.dialog == null || isFinishing()) {
981 return;
982 }
983
984 dismissPendingDialogs();
985
986 // Show a toast if the app is in background when a dialog can't be visible.
987 if (!isVisible()) {
988 Toast.makeText(getApplicationContext(), disconnectMessage.toastMessage, Toast.LENGTH_LONG)
989 .show();
990 return;
991 }
992
993 // Show the dialog.
linyuhc3968e62017-11-20 17:40:50 -0800994 errorDialog = disconnectMessage.dialog;
linyuh7b86f562017-11-16 11:24:09 -0800995 InCallUiLock lock = InCallPresenter.getInstance().acquireInCallUiLock("showErrorDialog");
996 disconnectMessage.dialog.setOnDismissListener(
997 dialogInterface -> {
998 lock.release();
999 onDialogDismissed();
1000 });
1001 disconnectMessage.dialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
1002 disconnectMessage.dialog.show();
1003 }
1004
1005 private void onDialogDismissed() {
linyuhc3968e62017-11-20 17:40:50 -08001006 errorDialog = null;
linyuh7b86f562017-11-16 11:24:09 -08001007 CallList.getInstance().onErrorDialogDismissed();
Eric Erfanianccca3152017-02-22 16:32:36 -08001008 }
1009
1010 public void dismissPendingDialogs() {
linyuhc3968e62017-11-20 17:40:50 -08001011 LogUtil.enterBlock("InCallActivity.dismissPendingDialogs");
linyuhf99f6302017-11-15 11:23:51 -08001012
1013 if (!isVisible) {
1014 // Defer the dismissing action as the activity is not visible and onSaveInstanceState may have
1015 // been called.
Eric Erfanianccca3152017-02-22 16:32:36 -08001016 LogUtil.i(
1017 "InCallActivity.dismissPendingDialogs", "defer actions since activity is not visible");
1018 needDismissPendingDialogs = true;
linyuhf99f6302017-11-15 11:23:51 -08001019 return;
Eric Erfanianccca3152017-02-22 16:32:36 -08001020 }
linyuhf99f6302017-11-15 11:23:51 -08001021
1022 // Dismiss the error dialog
linyuhf99f6302017-11-15 11:23:51 -08001023 if (errorDialog != null) {
1024 errorDialog.dismiss();
linyuhc3968e62017-11-20 17:40:50 -08001025 errorDialog = null;
linyuhf99f6302017-11-15 11:23:51 -08001026 }
1027
1028 // Dismiss the phone account selection dialog
linyuhf99f6302017-11-15 11:23:51 -08001029 if (selectPhoneAccountDialogFragment != null) {
1030 selectPhoneAccountDialogFragment.dismiss();
linyuhc3968e62017-11-20 17:40:50 -08001031 selectPhoneAccountDialogFragment = null;
linyuhf99f6302017-11-15 11:23:51 -08001032 }
1033
1034 // Dismiss the dialog for international call on WiFi
1035 InternationalCallOnWifiDialogFragment internationalCallOnWifiFragment =
1036 (InternationalCallOnWifiDialogFragment)
linyuhc3968e62017-11-20 17:40:50 -08001037 getSupportFragmentManager().findFragmentByTag(Tags.INTERNATIONAL_CALL_ON_WIFI);
linyuhf99f6302017-11-15 11:23:51 -08001038 if (internationalCallOnWifiFragment != null) {
1039 internationalCallOnWifiFragment.dismiss();
1040 }
1041
1042 // Dismiss the answer screen
1043 AnswerScreen answerScreen = getAnswerScreen();
1044 if (answerScreen != null) {
1045 answerScreen.dismissPendingDialogs();
1046 }
1047
1048 needDismissPendingDialogs = false;
Eric Erfanianccca3152017-02-22 16:32:36 -08001049 }
1050
linyuhc3968e62017-11-20 17:40:50 -08001051 private void enableInCallOrientationEventListener(boolean enable) {
linyuh69a25062017-11-15 16:18:51 -08001052 if (enable) {
1053 inCallOrientationEventListener.enable(true /* notifyDeviceOrientationChange */);
1054 } else {
1055 inCallOrientationEventListener.disable();
1056 }
Eric Erfanianccca3152017-02-22 16:32:36 -08001057 }
1058
1059 public void setExcludeFromRecents(boolean exclude) {
linyuhc3968e62017-11-20 17:40:50 -08001060 int taskId = getTaskId();
1061
1062 List<AppTask> tasks = getSystemService(ActivityManager.class).getAppTasks();
1063 for (AppTask task : tasks) {
1064 try {
1065 if (task.getTaskInfo().id == taskId) {
1066 task.setExcludeFromRecents(exclude);
1067 }
1068 } catch (RuntimeException e) {
1069 LogUtil.e("InCallActivity.setExcludeFromRecents", "RuntimeException:\n%s", e);
1070 }
1071 }
Eric Erfanianccca3152017-02-22 16:32:36 -08001072 }
1073
Eric Erfanianccca3152017-02-22 16:32:36 -08001074 @Nullable
1075 public FragmentManager getDialpadFragmentManager() {
wangqifd4c9f72018-03-08 18:21:50 -08001076 InCallScreen inCallScreen = getInCallOrRttCallScreen();
Eric Erfanianccca3152017-02-22 16:32:36 -08001077 if (inCallScreen != null) {
1078 return inCallScreen.getInCallScreenFragment().getChildFragmentManager();
1079 }
1080 return null;
1081 }
1082
1083 public int getDialpadContainerId() {
wangqifd4c9f72018-03-08 18:21:50 -08001084 return getInCallOrRttCallScreen().getAnswerAndDialpadContainerResourceId();
Eric Erfanianccca3152017-02-22 16:32:36 -08001085 }
1086
1087 @Override
1088 public AnswerScreenDelegate newAnswerScreenDelegate(AnswerScreen answerScreen) {
1089 DialerCall call = CallList.getInstance().getCallById(answerScreen.getCallId());
1090 if (call == null) {
1091 // This is a work around for a bug where we attempt to create a new delegate after the call
1092 // has already been removed. An example of when this can happen is:
1093 // 1. incoming video call in landscape mode
1094 // 2. remote party hangs up
1095 // 3. activity switches from landscape to portrait
1096 // At step #3 the answer fragment will try to create a new answer delegate but the call won't
1097 // exist. In this case we'll simply return a stub delegate that does nothing. This is ok
1098 // because this new state is transient and the activity will be destroyed soon.
1099 LogUtil.i("InCallActivity.onPrimaryCallStateChanged", "call doesn't exist, using stub");
1100 return new AnswerScreenPresenterStub();
1101 } else {
1102 return new AnswerScreenPresenter(
1103 this, answerScreen, CallList.getInstance().getCallById(answerScreen.getCallId()));
1104 }
1105 }
1106
1107 @Override
1108 public InCallScreenDelegate newInCallScreenDelegate() {
1109 return new CallCardPresenter(this);
1110 }
1111
1112 @Override
1113 public InCallButtonUiDelegate newInCallButtonUiDelegate() {
1114 return new CallButtonPresenter(this);
1115 }
1116
1117 @Override
Eric Erfanian90508232017-03-24 09:31:16 -07001118 public VideoCallScreenDelegate newVideoCallScreenDelegate(VideoCallScreen videoCallScreen) {
1119 DialerCall dialerCall = CallList.getInstance().getCallById(videoCallScreen.getCallId());
1120 if (dialerCall != null && dialerCall.getVideoTech().shouldUseSurfaceView()) {
1121 return dialerCall.getVideoTech().createVideoCallScreenDelegate(this, videoCallScreen);
1122 }
Eric Erfanianccca3152017-02-22 16:32:36 -08001123 return new VideoCallPresenter();
1124 }
1125
1126 public void onPrimaryCallStateChanged() {
Eric Erfanian2ca43182017-08-31 06:57:16 -07001127 Trace.beginSection("InCallActivity.onPrimaryCallStateChanged");
Eric Erfanianccca3152017-02-22 16:32:36 -08001128 showMainInCallFragment();
Eric Erfanian2ca43182017-08-31 06:57:16 -07001129 Trace.endSection();
Eric Erfanianccca3152017-02-22 16:32:36 -08001130 }
1131
linyuh7b86f562017-11-16 11:24:09 -08001132 public void showDialogOrToastForWifiHandoverFailure(DialerCall call) {
1133 if (call.showWifiHandoverAlertAsToast()) {
1134 Toast.makeText(this, R.string.video_call_lte_to_wifi_failed_message, Toast.LENGTH_SHORT)
1135 .show();
1136 return;
1137 }
1138
1139 dismissPendingDialogs();
1140
1141 AlertDialog.Builder builder =
1142 new AlertDialog.Builder(this).setTitle(R.string.video_call_lte_to_wifi_failed_title);
1143
1144 // This allows us to use the theme of the dialog instead of the activity
1145 View dialogCheckBoxView =
1146 View.inflate(builder.getContext(), R.layout.video_call_lte_to_wifi_failed, null /* root */);
1147 CheckBox wifiHandoverFailureCheckbox =
1148 (CheckBox) dialogCheckBoxView.findViewById(R.id.video_call_lte_to_wifi_failed_checkbox);
1149 wifiHandoverFailureCheckbox.setChecked(false);
1150
1151 InCallUiLock lock = InCallPresenter.getInstance().acquireInCallUiLock("WifiFailedDialog");
linyuhc3968e62017-11-20 17:40:50 -08001152 errorDialog =
linyuh7b86f562017-11-16 11:24:09 -08001153 builder
1154 .setView(dialogCheckBoxView)
1155 .setMessage(R.string.video_call_lte_to_wifi_failed_message)
1156 .setOnCancelListener(dialogInterface -> onDialogDismissed())
1157 .setPositiveButton(
1158 android.R.string.ok,
1159 (dialogInterface, id) -> {
1160 call.setDoNotShowDialogForHandoffToWifiFailure(
1161 wifiHandoverFailureCheckbox.isChecked());
1162 dialogInterface.cancel();
1163 onDialogDismissed();
1164 })
1165 .setOnDismissListener(dialogInterface -> lock.release())
1166 .create();
linyuh7b86f562017-11-16 11:24:09 -08001167 errorDialog.show();
Eric Erfanianccca3152017-02-22 16:32:36 -08001168 }
1169
linyuh7b86f562017-11-16 11:24:09 -08001170 public void showDialogForInternationalCallOnWifi(@NonNull DialerCall call) {
linyuh7b86f562017-11-16 11:24:09 -08001171 InternationalCallOnWifiDialogFragment fragment =
yuegb47528e2018-04-24 12:12:57 -07001172 InternationalCallOnWifiDialogFragment.newInstance(call.getId());
linyuhc3968e62017-11-20 17:40:50 -08001173 fragment.show(getSupportFragmentManager(), Tags.INTERNATIONAL_CALL_ON_WIFI);
Eric Erfanianc857f902017-05-15 14:05:33 -07001174 }
1175
wangqibc28ea72018-04-02 16:23:00 -07001176 public void showDialogForRttRequest(DialerCall call, int rttRequestId) {
1177 LogUtil.enterBlock("InCallActivity.showDialogForRttRequest");
1178 DialogFragment fragment = RttRequestDialogFragment.newInstance(call.getId(), rttRequestId);
1179 fragment.show(getSupportFragmentManager(), Tags.RTT_REQUEST_DIALOG);
1180 }
1181
Eric Erfanianccca3152017-02-22 16:32:36 -08001182 public void setAllowOrientationChange(boolean allowOrientationChange) {
wangqi9982f0d2017-10-11 17:46:07 -07001183 if (this.allowOrientationChange == allowOrientationChange) {
1184 return;
1185 }
1186 this.allowOrientationChange = allowOrientationChange;
Eric Erfanianccca3152017-02-22 16:32:36 -08001187 if (!allowOrientationChange) {
1188 setRequestedOrientation(InCallOrientationEventListener.ACTIVITY_PREFERENCE_DISALLOW_ROTATION);
1189 } else {
1190 setRequestedOrientation(InCallOrientationEventListener.ACTIVITY_PREFERENCE_ALLOW_ROTATION);
1191 }
1192 enableInCallOrientationEventListener(allowOrientationChange);
1193 }
1194
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001195 public void hideMainInCallFragment() {
linyuhc3968e62017-11-20 17:40:50 -08001196 LogUtil.enterBlock("InCallActivity.hideMainInCallFragment");
1197 if (getCallCardFragmentVisible()) {
Eric Erfanianccca3152017-02-22 16:32:36 -08001198 FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
1199 hideInCallScreenFragment(transaction);
1200 hideVideoCallScreenFragment(transaction);
1201 transaction.commitAllowingStateLoss();
1202 getSupportFragmentManager().executePendingTransactions();
1203 }
1204 }
1205
1206 private void showMainInCallFragment() {
Eric Erfanian2ca43182017-08-31 06:57:16 -07001207 Trace.beginSection("InCallActivity.showMainInCallFragment");
Eric Erfanianccca3152017-02-22 16:32:36 -08001208 // If the activity's onStart method hasn't been called yet then defer doing any work.
1209 if (!isVisible) {
1210 LogUtil.i("InCallActivity.showMainInCallFragment", "not visible yet/anymore");
Eric Erfanian2ca43182017-08-31 06:57:16 -07001211 Trace.endSection();
Eric Erfanianccca3152017-02-22 16:32:36 -08001212 return;
1213 }
1214
1215 // Don't let this be reentrant.
1216 if (isInShowMainInCallFragment) {
1217 LogUtil.i("InCallActivity.showMainInCallFragment", "already in method, bailing");
Eric Erfanian2ca43182017-08-31 06:57:16 -07001218 Trace.endSection();
Eric Erfanianccca3152017-02-22 16:32:36 -08001219 return;
1220 }
1221
1222 isInShowMainInCallFragment = true;
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001223 ShouldShowUiResult shouldShowAnswerUi = getShouldShowAnswerUi();
1224 ShouldShowUiResult shouldShowVideoUi = getShouldShowVideoUi();
wangqi219b8702018-02-13 09:34:41 -08001225 ShouldShowUiResult shouldShowRttUi = getShouldShowRttUi();
erfaniand05d8992018-03-20 19:42:26 -07001226 ShouldShowUiResult shouldShowSpeakEasyUi = getShouldShowSpeakEasyUi();
Eric Erfanianccca3152017-02-22 16:32:36 -08001227 LogUtil.i(
1228 "InCallActivity.showMainInCallFragment",
uabdullah56a4cda2018-05-10 16:38:35 -07001229 "shouldShowAnswerUi: %b, shouldShowRttUi: %b, shouldShowVideoUi: %b, "
1230 + "shouldShowSpeakEasyUi: %b, didShowAnswerScreen: %b, didShowInCallScreen: %b, "
1231 + "didShowRttCallScreen: %b, didShowVideoCallScreen: %b, didShowSpeakEasyScreen: %b",
Eric Erfanianccca3152017-02-22 16:32:36 -08001232 shouldShowAnswerUi.shouldShow,
wangqi219b8702018-02-13 09:34:41 -08001233 shouldShowRttUi.shouldShow,
Eric Erfanian10b34a52017-05-04 08:23:17 -07001234 shouldShowVideoUi.shouldShow,
uabdullah56a4cda2018-05-10 16:38:35 -07001235 shouldShowSpeakEasyUi.shouldShow,
Eric Erfanianccca3152017-02-22 16:32:36 -08001236 didShowAnswerScreen,
1237 didShowInCallScreen,
wangqi219b8702018-02-13 09:34:41 -08001238 didShowRttCallScreen,
erfaniand05d8992018-03-20 19:42:26 -07001239 didShowVideoCallScreen,
1240 didShowSpeakEasyScreen);
Eric Erfanianccca3152017-02-22 16:32:36 -08001241 // Only video call ui allows orientation change.
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001242 setAllowOrientationChange(shouldShowVideoUi.shouldShow);
Eric Erfanianccca3152017-02-22 16:32:36 -08001243
1244 FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
wangqi219b8702018-02-13 09:34:41 -08001245 boolean didChange;
Eric Erfanianccca3152017-02-22 16:32:36 -08001246 if (shouldShowAnswerUi.shouldShow) {
wangqi219b8702018-02-13 09:34:41 -08001247 didChange = hideInCallScreenFragment(transaction);
1248 didChange |= hideVideoCallScreenFragment(transaction);
1249 didChange |= hideRttCallScreenFragment(transaction);
erfaniand05d8992018-03-20 19:42:26 -07001250 didChange |= hideSpeakEasyFragment(transaction);
wangqi219b8702018-02-13 09:34:41 -08001251 didChange |= showAnswerScreenFragment(transaction, shouldShowAnswerUi.call);
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001252 } else if (shouldShowVideoUi.shouldShow) {
wangqi219b8702018-02-13 09:34:41 -08001253 didChange = hideInCallScreenFragment(transaction);
1254 didChange |= showVideoCallScreenFragment(transaction, shouldShowVideoUi.call);
1255 didChange |= hideRttCallScreenFragment(transaction);
erfaniand05d8992018-03-20 19:42:26 -07001256 didChange |= hideSpeakEasyFragment(transaction);
wangqi219b8702018-02-13 09:34:41 -08001257 didChange |= hideAnswerScreenFragment(transaction);
1258 } else if (shouldShowRttUi.shouldShow) {
1259 didChange = hideInCallScreenFragment(transaction);
1260 didChange |= hideVideoCallScreenFragment(transaction);
1261 didChange |= hideAnswerScreenFragment(transaction);
erfaniand05d8992018-03-20 19:42:26 -07001262 didChange |= hideSpeakEasyFragment(transaction);
wangqi219b8702018-02-13 09:34:41 -08001263 didChange |= showRttCallScreenFragment(transaction, shouldShowRttUi.call);
erfaniand05d8992018-03-20 19:42:26 -07001264 } else if (shouldShowSpeakEasyUi.shouldShow) {
1265 didChange = hideInCallScreenFragment(transaction);
1266 didChange |= hideVideoCallScreenFragment(transaction);
1267 didChange |= hideAnswerScreenFragment(transaction);
1268 didChange |= hideRttCallScreenFragment(transaction);
1269 didChange |= showSpeakEasyFragment(transaction, shouldShowSpeakEasyUi.call);
Eric Erfanianccca3152017-02-22 16:32:36 -08001270 } else {
wangqi219b8702018-02-13 09:34:41 -08001271 didChange = showInCallScreenFragment(transaction);
1272 didChange |= hideVideoCallScreenFragment(transaction);
1273 didChange |= hideRttCallScreenFragment(transaction);
erfaniand05d8992018-03-20 19:42:26 -07001274 didChange |= hideSpeakEasyFragment(transaction);
wangqi219b8702018-02-13 09:34:41 -08001275 didChange |= hideAnswerScreenFragment(transaction);
Eric Erfanianccca3152017-02-22 16:32:36 -08001276 }
1277
wangqi219b8702018-02-13 09:34:41 -08001278 if (didChange) {
Eric Erfanian2ca43182017-08-31 06:57:16 -07001279 Trace.beginSection("InCallActivity.commitTransaction");
Eric Erfanianccca3152017-02-22 16:32:36 -08001280 transaction.commitNow();
Eric Erfanian2ca43182017-08-31 06:57:16 -07001281 Trace.endSection();
Eric Erfanianccca3152017-02-22 16:32:36 -08001282 Logger.get(this).logScreenView(ScreenEvent.Type.INCALL, this);
1283 }
1284 isInShowMainInCallFragment = false;
Eric Erfanian2ca43182017-08-31 06:57:16 -07001285 Trace.endSection();
Eric Erfanianccca3152017-02-22 16:32:36 -08001286 }
1287
erfaniand05d8992018-03-20 19:42:26 -07001288 private boolean showSpeakEasyFragment(FragmentTransaction transaction, DialerCall call) {
1289
erfaniand05d8992018-03-20 19:42:26 -07001290 if (didShowSpeakEasyScreen) {
erfanian612d13a2018-04-04 15:27:57 -07001291 if (lastShownSpeakEasyScreenUniqueCallid.equals(call.getUniqueCallId())) {
erfanian12243de2018-04-17 12:17:08 -07001292 LogUtil.i("InCallActivity.showSpeakEasyFragment", "found existing fragment");
erfanian612d13a2018-04-04 15:27:57 -07001293 return false;
1294 }
1295 hideSpeakEasyFragment(transaction);
erfanian12243de2018-04-17 12:17:08 -07001296 LogUtil.i("InCallActivity.showSpeakEasyFragment", "hid existing fragment");
erfaniand05d8992018-03-20 19:42:26 -07001297 }
1298
1299 Optional<Fragment> speakEasyFragment = speakEasyCallManager.getSpeakEasyFragment(call);
1300 if (speakEasyFragment.isPresent()) {
1301 transaction.add(R.id.main, speakEasyFragment.get(), Tags.SPEAK_EASY_SCREEN);
1302 didShowSpeakEasyScreen = true;
erfanian612d13a2018-04-04 15:27:57 -07001303 lastShownSpeakEasyScreenUniqueCallid = call.getUniqueCallId();
erfanian12243de2018-04-17 12:17:08 -07001304 LogUtil.i(
1305 "InCallActivity.showSpeakEasyFragment",
1306 "set fragment for call %s",
1307 lastShownSpeakEasyScreenUniqueCallid);
erfaniand05d8992018-03-20 19:42:26 -07001308 return true;
1309 }
1310 return false;
1311 }
1312
1313 private Fragment getSpeakEasyScreen() {
1314 return getSupportFragmentManager().findFragmentByTag(Tags.SPEAK_EASY_SCREEN);
1315 }
1316
1317 private boolean hideSpeakEasyFragment(FragmentTransaction transaction) {
1318 if (!didShowSpeakEasyScreen) {
1319 return false;
1320 }
1321
1322 Fragment speakEasyFragment = getSpeakEasyScreen();
1323
1324 if (speakEasyFragment != null) {
1325 transaction.remove(speakEasyFragment);
1326 didShowSpeakEasyScreen = false;
1327 return true;
1328 }
1329 return false;
1330 }
1331
erfanian12243de2018-04-17 12:17:08 -07001332 @VisibleForTesting
erfaniand05d8992018-03-20 19:42:26 -07001333 public void setSpeakEasyCallManager(SpeakEasyCallManager speakEasyCallManager) {
erfanian87dbb622018-04-04 15:43:00 -07001334 this.speakEasyCallManager = speakEasyCallManager;
erfaniand05d8992018-03-20 19:42:26 -07001335 }
1336
erfanian12243de2018-04-17 12:17:08 -07001337 @Nullable
erfaniand05d8992018-03-20 19:42:26 -07001338 public SpeakEasyCallManager getSpeakEasyCallManager() {
erfanian12243de2018-04-17 12:17:08 -07001339 if (this.speakEasyCallManager == null) {
1340 this.speakEasyCallManager = InCallPresenter.getInstance().getSpeakEasyCallManager();
1341 }
erfaniand05d8992018-03-20 19:42:26 -07001342 return speakEasyCallManager;
1343 }
1344
1345 private ShouldShowUiResult getShouldShowSpeakEasyUi() {
1346 SpeakEasyCallManager speakEasyCallManager = getSpeakEasyCallManager();
1347
1348 if (speakEasyCallManager == null) {
1349 return new ShouldShowUiResult(false, null);
1350 }
1351
erfanian3bb7cb62018-04-11 09:01:15 -07001352 DialerCall call =
1353 CallList.getInstance().getIncomingCall() != null
1354 ? CallList.getInstance().getIncomingCall()
1355 : CallList.getInstance().getActiveCall();
erfaniand05d8992018-03-20 19:42:26 -07001356
1357 if (call == null) {
1358 return new ShouldShowUiResult(false, call);
1359 }
1360
1361 if (!call.isSpeakEasyCall() || !call.isSpeakEasyEligible()) {
1362 return new ShouldShowUiResult(false, call);
1363 }
1364
1365 Optional<Fragment> speakEasyFragment = speakEasyCallManager.getSpeakEasyFragment(call);
1366
1367 if (!speakEasyFragment.isPresent()) {
1368 return new ShouldShowUiResult(false, call);
1369 }
1370 return new ShouldShowUiResult(true, call);
1371 }
1372
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001373 private ShouldShowUiResult getShouldShowAnswerUi() {
Eric Erfanianccca3152017-02-22 16:32:36 -08001374 DialerCall call = CallList.getInstance().getIncomingCall();
erfanian3bb7cb62018-04-11 09:01:15 -07001375 if (call != null && !call.isSpeakEasyCall()) {
Eric Erfanianccca3152017-02-22 16:32:36 -08001376 LogUtil.i("InCallActivity.getShouldShowAnswerUi", "found incoming call");
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001377 return new ShouldShowUiResult(true, call);
Eric Erfanianccca3152017-02-22 16:32:36 -08001378 }
1379
1380 call = CallList.getInstance().getVideoUpgradeRequestCall();
1381 if (call != null) {
1382 LogUtil.i("InCallActivity.getShouldShowAnswerUi", "found video upgrade request");
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001383 return new ShouldShowUiResult(true, call);
Eric Erfanianccca3152017-02-22 16:32:36 -08001384 }
1385
1386 // Check if we're showing the answer screen and the call is disconnected. If this condition is
1387 // true then we won't switch from the answer UI to the in call UI. This prevents flicker when
1388 // the user rejects an incoming call.
1389 call = CallList.getInstance().getFirstCall();
1390 if (call == null) {
1391 call = CallList.getInstance().getBackgroundCall();
1392 }
wangqibb94ca62018-04-27 14:34:04 -07001393 if (didShowAnswerScreen && (call == null || call.getState() == DialerCallState.DISCONNECTED)) {
Eric Erfanianccca3152017-02-22 16:32:36 -08001394 LogUtil.i("InCallActivity.getShouldShowAnswerUi", "found disconnecting incoming call");
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001395 return new ShouldShowUiResult(true, call);
Eric Erfanianccca3152017-02-22 16:32:36 -08001396 }
1397
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001398 return new ShouldShowUiResult(false, null);
Eric Erfanianccca3152017-02-22 16:32:36 -08001399 }
1400
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001401 private static ShouldShowUiResult getShouldShowVideoUi() {
Eric Erfanianccca3152017-02-22 16:32:36 -08001402 DialerCall call = CallList.getInstance().getFirstCall();
1403 if (call == null) {
1404 LogUtil.i("InCallActivity.getShouldShowVideoUi", "null call");
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001405 return new ShouldShowUiResult(false, null);
Eric Erfanianccca3152017-02-22 16:32:36 -08001406 }
1407
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001408 if (call.isVideoCall()) {
Eric Erfanianccca3152017-02-22 16:32:36 -08001409 LogUtil.i("InCallActivity.getShouldShowVideoUi", "found video call");
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001410 return new ShouldShowUiResult(true, call);
Eric Erfanianccca3152017-02-22 16:32:36 -08001411 }
1412
linyuh8fbecce2017-12-18 13:53:09 -08001413 if (call.hasSentVideoUpgradeRequest() || call.hasReceivedVideoUpgradeRequest()) {
Eric Erfanianccca3152017-02-22 16:32:36 -08001414 LogUtil.i("InCallActivity.getShouldShowVideoUi", "upgrading to video");
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001415 return new ShouldShowUiResult(true, call);
Eric Erfanianccca3152017-02-22 16:32:36 -08001416 }
1417
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001418 return new ShouldShowUiResult(false, null);
Eric Erfanianccca3152017-02-22 16:32:36 -08001419 }
1420
wangqi219b8702018-02-13 09:34:41 -08001421 private static ShouldShowUiResult getShouldShowRttUi() {
1422 DialerCall call = CallList.getInstance().getFirstCall();
1423 if (call == null) {
1424 LogUtil.i("InCallActivity.getShouldShowRttUi", "null call");
1425 return new ShouldShowUiResult(false, null);
1426 }
1427
wangqif6be6172018-03-30 15:57:56 -07001428 if (call.isActiveRttCall()) {
wangqi219b8702018-02-13 09:34:41 -08001429 LogUtil.i("InCallActivity.getShouldShowRttUi", "found rtt call");
1430 return new ShouldShowUiResult(true, call);
1431 }
1432
1433 if (call.hasSentRttUpgradeRequest()) {
1434 LogUtil.i("InCallActivity.getShouldShowRttUi", "upgrading to rtt");
1435 return new ShouldShowUiResult(true, call);
1436 }
1437
1438 return new ShouldShowUiResult(false, null);
1439 }
1440
Eric Erfanianccca3152017-02-22 16:32:36 -08001441 private boolean showAnswerScreenFragment(FragmentTransaction transaction, DialerCall call) {
1442 // When rejecting a call the active call can become null in which case we should continue
1443 // showing the answer screen.
1444 if (didShowAnswerScreen && call == null) {
1445 return false;
1446 }
1447
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001448 Assert.checkArgument(call != null, "didShowAnswerScreen was false but call was still null");
1449
1450 boolean isVideoUpgradeRequest = call.hasReceivedVideoUpgradeRequest();
Eric Erfanianccca3152017-02-22 16:32:36 -08001451
1452 // Check if we're already showing an answer screen for this call.
1453 if (didShowAnswerScreen) {
1454 AnswerScreen answerScreen = getAnswerScreen();
1455 if (answerScreen.getCallId().equals(call.getId())
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001456 && answerScreen.isVideoCall() == call.isVideoCall()
Eric Erfanian2ca43182017-08-31 06:57:16 -07001457 && answerScreen.isVideoUpgradeRequest() == isVideoUpgradeRequest
1458 && !answerScreen.isActionTimeout()) {
1459 LogUtil.d(
1460 "InCallActivity.showAnswerScreenFragment",
1461 "answer fragment exists for same call and has NOT been accepted/rejected/timed out");
Eric Erfanianccca3152017-02-22 16:32:36 -08001462 return false;
1463 }
Eric Erfanian2ca43182017-08-31 06:57:16 -07001464 if (answerScreen.isActionTimeout()) {
1465 LogUtil.i(
1466 "InCallActivity.showAnswerScreenFragment",
1467 "answer fragment exists but has been accepted/rejected and timed out");
1468 } else {
1469 LogUtil.i(
1470 "InCallActivity.showAnswerScreenFragment",
1471 "answer fragment exists but arguments do not match");
1472 }
Eric Erfanianccca3152017-02-22 16:32:36 -08001473 hideAnswerScreenFragment(transaction);
1474 }
1475
1476 // Show a new answer screen.
1477 AnswerScreen answerScreen =
Eric Erfanianfc37b022017-03-21 10:11:17 -07001478 AnswerBindings.createAnswerScreen(
1479 call.getId(),
wangqif6be6172018-03-30 15:57:56 -07001480 call.isActiveRttCall(),
Eric Erfanianfc37b022017-03-21 10:11:17 -07001481 call.isVideoCall(),
1482 isVideoUpgradeRequest,
Eric Erfanian90508232017-03-24 09:31:16 -07001483 call.getVideoTech().isSelfManagedCamera(),
1484 shouldAllowAnswerAndRelease(call),
erfaniand05d8992018-03-20 19:42:26 -07001485 CallList.getInstance().getBackgroundCall() != null,
erfanian89e3d1b2018-05-02 18:50:59 -07001486 getSpeakEasyCallManager().isAvailable(getApplicationContext())
1487 && call.isSpeakEasyEligible());
linyuhc3968e62017-11-20 17:40:50 -08001488 transaction.add(R.id.main, answerScreen.getAnswerScreenFragment(), Tags.ANSWER_SCREEN);
Eric Erfanianccca3152017-02-22 16:32:36 -08001489
1490 Logger.get(this).logScreenView(ScreenEvent.Type.INCOMING_CALL, this);
1491 didShowAnswerScreen = true;
1492 return true;
1493 }
1494
Eric Erfanian90508232017-03-24 09:31:16 -07001495 private boolean shouldAllowAnswerAndRelease(DialerCall call) {
1496 if (CallList.getInstance().getActiveCall() == null) {
1497 LogUtil.i("InCallActivity.shouldAllowAnswerAndRelease", "no active call");
1498 return false;
1499 }
1500 if (getSystemService(TelephonyManager.class).getPhoneType()
1501 == TelephonyManager.PHONE_TYPE_CDMA) {
1502 LogUtil.i("InCallActivity.shouldAllowAnswerAndRelease", "PHONE_TYPE_CDMA not supported");
1503 return false;
1504 }
1505 if (call.isVideoCall() || call.hasReceivedVideoUpgradeRequest()) {
1506 LogUtil.i("InCallActivity.shouldAllowAnswerAndRelease", "video call");
1507 return false;
1508 }
linyuhc3968e62017-11-20 17:40:50 -08001509 if (!ConfigProviderBindings.get(this)
1510 .getBoolean(ConfigNames.ANSWER_AND_RELEASE_ENABLED, true)) {
Eric Erfanian90508232017-03-24 09:31:16 -07001511 LogUtil.i("InCallActivity.shouldAllowAnswerAndRelease", "disabled by config");
1512 return false;
1513 }
1514
1515 return true;
1516 }
1517
Eric Erfanianccca3152017-02-22 16:32:36 -08001518 private boolean hideAnswerScreenFragment(FragmentTransaction transaction) {
1519 if (!didShowAnswerScreen) {
1520 return false;
1521 }
1522 AnswerScreen answerScreen = getAnswerScreen();
1523 if (answerScreen != null) {
1524 transaction.remove(answerScreen.getAnswerScreenFragment());
1525 }
1526
1527 didShowAnswerScreen = false;
1528 return true;
1529 }
1530
1531 private boolean showInCallScreenFragment(FragmentTransaction transaction) {
1532 if (didShowInCallScreen) {
1533 return false;
1534 }
Eric Erfanian2ca43182017-08-31 06:57:16 -07001535 InCallScreen inCallScreen = InCallBindings.createInCallScreen();
linyuhc3968e62017-11-20 17:40:50 -08001536 transaction.add(R.id.main, inCallScreen.getInCallScreenFragment(), Tags.IN_CALL_SCREEN);
Eric Erfanianccca3152017-02-22 16:32:36 -08001537 Logger.get(this).logScreenView(ScreenEvent.Type.INCALL, this);
1538 didShowInCallScreen = true;
1539 return true;
1540 }
1541
1542 private boolean hideInCallScreenFragment(FragmentTransaction transaction) {
1543 if (!didShowInCallScreen) {
1544 return false;
1545 }
1546 InCallScreen inCallScreen = getInCallScreen();
1547 if (inCallScreen != null) {
Eric Erfanian2ca43182017-08-31 06:57:16 -07001548 transaction.remove(inCallScreen.getInCallScreenFragment());
Eric Erfanianccca3152017-02-22 16:32:36 -08001549 }
1550 didShowInCallScreen = false;
1551 return true;
1552 }
1553
wangqi219b8702018-02-13 09:34:41 -08001554 private boolean showRttCallScreenFragment(FragmentTransaction transaction, DialerCall call) {
1555 if (didShowRttCallScreen) {
1556 // This shouldn't happen since only one RTT call is allow at same time.
1557 if (!getRttCallScreen().getCallId().equals(call.getId())) {
1558 LogUtil.e("InCallActivity.showRttCallScreenFragment", "RTT call id doesn't match");
1559 }
1560 return false;
1561 }
1562 RttCallScreen rttCallScreen = RttBindings.createRttCallScreen(call.getId());
1563 transaction.add(R.id.main, rttCallScreen.getRttCallScreenFragment(), Tags.RTT_CALL_SCREEN);
1564 Logger.get(this).logScreenView(ScreenEvent.Type.INCALL, this);
1565 didShowRttCallScreen = true;
1566 return true;
1567 }
1568
1569 private boolean hideRttCallScreenFragment(FragmentTransaction transaction) {
1570 if (!didShowRttCallScreen) {
1571 return false;
1572 }
1573 RttCallScreen rttCallScreen = getRttCallScreen();
1574 if (rttCallScreen != null) {
1575 transaction.remove(rttCallScreen.getRttCallScreenFragment());
1576 }
1577 didShowRttCallScreen = false;
1578 return true;
1579 }
1580
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001581 private boolean showVideoCallScreenFragment(FragmentTransaction transaction, DialerCall call) {
Eric Erfanianccca3152017-02-22 16:32:36 -08001582 if (didShowVideoCallScreen) {
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001583 VideoCallScreen videoCallScreen = getVideoCallScreen();
1584 if (videoCallScreen.getCallId().equals(call.getId())) {
1585 return false;
1586 }
1587 LogUtil.i(
1588 "InCallActivity.showVideoCallScreenFragment",
1589 "video call fragment exists but arguments do not match");
1590 hideVideoCallScreenFragment(transaction);
Eric Erfanianccca3152017-02-22 16:32:36 -08001591 }
1592
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001593 LogUtil.i("InCallActivity.showVideoCallScreenFragment", "call: %s", call);
1594
Eric Erfanian90508232017-03-24 09:31:16 -07001595 VideoCallScreen videoCallScreen =
1596 VideoBindings.createVideoCallScreen(
1597 call.getId(), call.getVideoTech().shouldUseSurfaceView());
linyuhc3968e62017-11-20 17:40:50 -08001598 transaction.add(
1599 R.id.main, videoCallScreen.getVideoCallScreenFragment(), Tags.VIDEO_CALL_SCREEN);
Eric Erfanianccca3152017-02-22 16:32:36 -08001600
1601 Logger.get(this).logScreenView(ScreenEvent.Type.INCALL, this);
1602 didShowVideoCallScreen = true;
1603 return true;
1604 }
1605
1606 private boolean hideVideoCallScreenFragment(FragmentTransaction transaction) {
1607 if (!didShowVideoCallScreen) {
1608 return false;
1609 }
1610 VideoCallScreen videoCallScreen = getVideoCallScreen();
1611 if (videoCallScreen != null) {
1612 transaction.remove(videoCallScreen.getVideoCallScreenFragment());
1613 }
1614 didShowVideoCallScreen = false;
1615 return true;
1616 }
1617
linyuhc3968e62017-11-20 17:40:50 -08001618 private AnswerScreen getAnswerScreen() {
1619 return (AnswerScreen) getSupportFragmentManager().findFragmentByTag(Tags.ANSWER_SCREEN);
Eric Erfanianccca3152017-02-22 16:32:36 -08001620 }
1621
linyuhc3968e62017-11-20 17:40:50 -08001622 private InCallScreen getInCallScreen() {
1623 return (InCallScreen) getSupportFragmentManager().findFragmentByTag(Tags.IN_CALL_SCREEN);
Eric Erfanianccca3152017-02-22 16:32:36 -08001624 }
1625
linyuhc3968e62017-11-20 17:40:50 -08001626 private VideoCallScreen getVideoCallScreen() {
1627 return (VideoCallScreen) getSupportFragmentManager().findFragmentByTag(Tags.VIDEO_CALL_SCREEN);
Eric Erfanianccca3152017-02-22 16:32:36 -08001628 }
1629
wangqi219b8702018-02-13 09:34:41 -08001630 private RttCallScreen getRttCallScreen() {
1631 return (RttCallScreen) getSupportFragmentManager().findFragmentByTag(Tags.RTT_CALL_SCREEN);
1632 }
1633
wangqifd4c9f72018-03-08 18:21:50 -08001634 private InCallScreen getInCallOrRttCallScreen() {
1635 InCallScreen inCallScreen = null;
1636 if (didShowInCallScreen) {
1637 inCallScreen = getInCallScreen();
1638 }
1639 if (didShowRttCallScreen) {
1640 inCallScreen = getRttCallScreen();
1641 }
1642 return inCallScreen;
1643 }
1644
Eric Erfanianccca3152017-02-22 16:32:36 -08001645 @Override
1646 public void onPseudoScreenStateChanged(boolean isOn) {
1647 LogUtil.i("InCallActivity.onPseudoScreenStateChanged", "isOn: " + isOn);
1648 pseudoBlackScreenOverlay.setVisibility(isOn ? View.GONE : View.VISIBLE);
1649 }
1650
1651 /**
1652 * For some touch related issue, turning off the screen can be faked by drawing a black view over
1653 * the activity. All touch events started when the screen is "off" is rejected.
1654 *
1655 * @see PseudoScreenState
1656 */
1657 @Override
1658 public boolean dispatchTouchEvent(MotionEvent event) {
1659 // Reject any gesture that started when the screen is in the fake off state.
1660 if (touchDownWhenPseudoScreenOff) {
1661 if (event.getAction() == MotionEvent.ACTION_UP) {
1662 touchDownWhenPseudoScreenOff = false;
1663 }
1664 return true;
1665 }
1666 // Reject all touch event when the screen is in the fake off state.
1667 if (!InCallPresenter.getInstance().getPseudoScreenState().isOn()) {
1668 if (event.getAction() == MotionEvent.ACTION_DOWN) {
1669 touchDownWhenPseudoScreenOff = true;
1670 LogUtil.i("InCallActivity.dispatchTouchEvent", "touchDownWhenPseudoScreenOff");
1671 }
1672 return true;
1673 }
1674 return super.dispatchTouchEvent(event);
1675 }
1676
wangqi219b8702018-02-13 09:34:41 -08001677 @Override
1678 public RttCallScreenDelegate newRttCallScreenDelegate(RttCallScreen videoCallScreen) {
1679 return new RttCallPresenter();
1680 }
1681
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001682 private static class ShouldShowUiResult {
Eric Erfanianccca3152017-02-22 16:32:36 -08001683 public final boolean shouldShow;
1684 public final DialerCall call;
1685
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001686 ShouldShowUiResult(boolean shouldShow, DialerCall call) {
Eric Erfanianccca3152017-02-22 16:32:36 -08001687 this.shouldShow = shouldShow;
1688 this.call = call;
1689 }
1690 }
linyuhc3968e62017-11-20 17:40:50 -08001691
1692 private static final class IntentExtraNames {
1693 static final String FOR_FULL_SCREEN = "InCallActivity.for_full_screen_intent";
1694 static final String NEW_OUTGOING_CALL = "InCallActivity.new_outgoing_call";
1695 static final String SHOW_DIALPAD = "InCallActivity.show_dialpad";
1696 }
1697
1698 private static final class KeysForSavedInstance {
1699 static final String DIALPAD_TEXT = "InCallActivity.dialpad_text";
1700 static final String DID_SHOW_ANSWER_SCREEN = "did_show_answer_screen";
1701 static final String DID_SHOW_IN_CALL_SCREEN = "did_show_in_call_screen";
1702 static final String DID_SHOW_VIDEO_CALL_SCREEN = "did_show_video_call_screen";
wangqi153af2f2018-02-15 16:21:49 -08001703 static final String DID_SHOW_RTT_CALL_SCREEN = "did_show_rtt_call_screen";
erfaniand05d8992018-03-20 19:42:26 -07001704 static final String DID_SHOW_SPEAK_EASY_SCREEN = "did_show_speak_easy_screen";
linyuhc3968e62017-11-20 17:40:50 -08001705 }
1706
1707 /** Request codes for pending intents. */
1708 public static final class PendingIntentRequestCodes {
1709 static final int NON_FULL_SCREEN = 0;
1710 static final int FULL_SCREEN = 1;
1711 static final int BUBBLE = 2;
1712 }
1713
1714 private static final class Tags {
1715 static final String ANSWER_SCREEN = "tag_answer_screen";
1716 static final String DIALPAD_FRAGMENT = "tag_dialpad_fragment";
1717 static final String IN_CALL_SCREEN = "tag_in_call_screen";
1718 static final String INTERNATIONAL_CALL_ON_WIFI = "tag_international_call_on_wifi";
1719 static final String SELECT_ACCOUNT_FRAGMENT = "tag_select_account_fragment";
1720 static final String VIDEO_CALL_SCREEN = "tag_video_call_screen";
wangqi219b8702018-02-13 09:34:41 -08001721 static final String RTT_CALL_SCREEN = "tag_rtt_call_screen";
linyuhc3968e62017-11-20 17:40:50 -08001722 static final String POST_CHAR_DIALOG_FRAGMENT = "tag_post_char_dialog_fragment";
erfaniand05d8992018-03-20 19:42:26 -07001723 static final String SPEAK_EASY_SCREEN = "tag_speak_easy_screen";
wangqibc28ea72018-04-02 16:23:00 -07001724 static final String RTT_REQUEST_DIALOG = "tag_rtt_request_dialog";
linyuhc3968e62017-11-20 17:40:50 -08001725 }
1726
1727 private static final class ConfigNames {
1728 static final String ANSWER_AND_RELEASE_ENABLED = "answer_and_release_enabled";
1729 }
1730
linyuhc3968e62017-11-20 17:40:50 -08001731 private static final class SelectPhoneAccountListener
1732 extends SelectPhoneAccountDialogFragment.SelectPhoneAccountListener {
1733 private static final String TAG = SelectPhoneAccountListener.class.getCanonicalName();
1734
twyen73a74c32018-03-07 12:12:24 -08001735 private final Context appContext;
1736
1737 SelectPhoneAccountListener(Context appContext) {
1738 this.appContext = appContext;
1739 }
1740
linyuhc3968e62017-11-20 17:40:50 -08001741 @Override
1742 public void onPhoneAccountSelected(
1743 PhoneAccountHandle selectedAccountHandle, boolean setDefault, String callId) {
1744 DialerCall call = CallList.getInstance().getCallById(callId);
1745 LogUtil.i(TAG, "Phone account select with call:\n%s", call);
1746
1747 if (call != null) {
twyen73a74c32018-03-07 12:12:24 -08001748 call.phoneAccountSelected(selectedAccountHandle, false);
1749 if (call.getPreferredAccountRecorder() != null) {
1750 call.getPreferredAccountRecorder().record(appContext, selectedAccountHandle, setDefault);
1751 }
linyuhc3968e62017-11-20 17:40:50 -08001752 }
1753 }
1754
1755 @Override
1756 public void onDialogDismissed(String callId) {
1757 DialerCall call = CallList.getInstance().getCallById(callId);
1758 LogUtil.i(TAG, "Disconnecting call:\n%s" + call);
1759
1760 if (call != null) {
1761 call.disconnect();
1762 }
1763 }
1764 }
Eric Erfanianccca3152017-02-22 16:32:36 -08001765}