blob: 2fe38c0aa40c8b481f4ccd8063542334f7e6860a [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);
Eric Erfanianccca3152017-02-22 16:32:36 -0800200 }
201
linyuhc3968e62017-11-20 17:40:50 -0800202 setWindowFlags();
203 setContentView(R.layout.incall_screen);
204 internalResolveIntent(getIntent());
205
206 boolean isLandscape =
207 getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE;
208 boolean isRtl = ViewUtil.isRtl();
209 if (isLandscape) {
210 dialpadSlideInAnimation =
211 AnimationUtils.loadAnimation(
212 this, isRtl ? R.anim.dialpad_slide_in_left : R.anim.dialpad_slide_in_right);
213 dialpadSlideOutAnimation =
214 AnimationUtils.loadAnimation(
215 this, isRtl ? R.anim.dialpad_slide_out_left : R.anim.dialpad_slide_out_right);
216 } else {
217 dialpadSlideInAnimation = AnimationUtils.loadAnimation(this, R.anim.dialpad_slide_in_bottom);
218 dialpadSlideOutAnimation =
219 AnimationUtils.loadAnimation(this, R.anim.dialpad_slide_out_bottom);
220 }
221 dialpadSlideInAnimation.setInterpolator(AnimUtils.EASE_IN);
222 dialpadSlideOutAnimation.setInterpolator(AnimUtils.EASE_OUT);
223 dialpadSlideOutAnimation.setAnimationListener(
224 new AnimationListenerAdapter() {
225 @Override
226 public void onAnimationEnd(Animation animation) {
227 hideDialpadFragment();
228 }
229 });
230
231 if (bundle != null && showDialpadRequest == DIALPAD_REQUEST_NONE) {
232 // If the dialpad was shown before, set related variables so that it can be shown and
233 // populated with the previous DTMF text during onResume().
234 if (bundle.containsKey(IntentExtraNames.SHOW_DIALPAD)) {
235 boolean showDialpad = bundle.getBoolean(IntentExtraNames.SHOW_DIALPAD);
236 showDialpadRequest = showDialpad ? DIALPAD_REQUEST_SHOW : DIALPAD_REQUEST_HIDE;
237 animateDialpadOnShow = false;
238 }
239 dtmfTextToPrepopulate = bundle.getString(KeysForSavedInstance.DIALPAD_TEXT);
240
241 SelectPhoneAccountDialogFragment selectPhoneAccountDialogFragment =
242 (SelectPhoneAccountDialogFragment)
243 getFragmentManager().findFragmentByTag(Tags.SELECT_ACCOUNT_FRAGMENT);
244 if (selectPhoneAccountDialogFragment != null) {
245 selectPhoneAccountDialogFragment.setListener(selectPhoneAccountListener);
246 }
247 }
248
linyuh69a25062017-11-15 16:18:51 -0800249 inCallOrientationEventListener = new InCallOrientationEventListener(this);
Eric Erfanianccca3152017-02-22 16:32:36 -0800250
251 getWindow()
252 .getDecorView()
253 .setSystemUiVisibility(
254 View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
255
256 pseudoBlackScreenOverlay = findViewById(R.id.psuedo_black_screen_overlay);
Eric Erfanian2ca43182017-08-31 06:57:16 -0700257 sendBroadcast(CallPendingActivity.getFinishBroadcast());
258 Trace.endSection();
zachh7a96dc72018-02-20 22:16:03 -0800259 MetricsComponent.get(this)
260 .metrics()
261 .stopTimer(Metrics.ON_CALL_ADDED_TO_ON_INCALL_UI_SHOWN_INCOMING);
262 MetricsComponent.get(this)
263 .metrics()
264 .stopTimer(Metrics.ON_CALL_ADDED_TO_ON_INCALL_UI_SHOWN_OUTGOING);
Eric Erfanianccca3152017-02-22 16:32:36 -0800265 }
266
linyuhc3968e62017-11-20 17:40:50 -0800267 private void setWindowFlags() {
268 // Allow the activity to be shown when the screen is locked and filter out touch events that are
269 // "too fat".
270 int flags =
271 WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
272 | WindowManager.LayoutParams.FLAG_IGNORE_CHEEK_PRESSES;
273
linyuhf79d1cb2017-12-15 17:49:56 -0800274 // When the audio stream is not via Bluetooth, turn on the screen once the activity is shown.
275 // When the audio stream is via Bluetooth, turn on the screen only for an incoming call.
linyuhc3968e62017-11-20 17:40:50 -0800276 final int audioRoute = getAudioRoute();
linyuhf79d1cb2017-12-15 17:49:56 -0800277 if (audioRoute != CallAudioState.ROUTE_BLUETOOTH
278 || CallList.getInstance().getIncomingCall() != null) {
linyuhc3968e62017-11-20 17:40:50 -0800279 flags |= WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON;
280 }
281
282 getWindow().addFlags(flags);
283 }
284
285 private static int getAudioRoute() {
286 if (audioRouteForTesting.isPresent()) {
287 return audioRouteForTesting.get();
288 }
289
290 return AudioModeProvider.getInstance().getAudioState().getRoute();
291 }
292
293 @VisibleForTesting(otherwise = VisibleForTesting.NONE)
294 public static void setAudioRouteForTesting(int audioRoute) {
295 audioRouteForTesting = Optional.of(audioRoute);
296 }
297
298 private void internalResolveIntent(Intent intent) {
299 if (!intent.getAction().equals(Intent.ACTION_MAIN)) {
300 return;
301 }
302
303 if (intent.hasExtra(IntentExtraNames.SHOW_DIALPAD)) {
304 // IntentExtraNames.SHOW_DIALPAD can be used to specify whether the DTMF dialpad should be
305 // initially visible. If the extra is absent, leave the dialpad in its previous state.
306 boolean showDialpad = intent.getBooleanExtra(IntentExtraNames.SHOW_DIALPAD, false);
307 relaunchedFromDialer(showDialpad);
308 }
309
310 DialerCall outgoingCall = CallList.getInstance().getOutgoingCall();
311 if (outgoingCall == null) {
312 outgoingCall = CallList.getInstance().getPendingOutgoingCall();
313 }
314 if (intent.getBooleanExtra(IntentExtraNames.NEW_OUTGOING_CALL, false)) {
315 intent.removeExtra(IntentExtraNames.NEW_OUTGOING_CALL);
316
317 // InCallActivity is responsible for disconnecting a new outgoing call if there is no way of
318 // making it (i.e. no valid call capable accounts).
linyuh122fb0b2018-03-26 13:35:32 -0700319 if (InCallPresenter.isCallWithNoValidAccounts(outgoingCall)) {
linyuhc3968e62017-11-20 17:40:50 -0800320 LogUtil.i(
321 "InCallActivity.internalResolveIntent", "Call with no valid accounts, disconnecting");
322 outgoingCall.disconnect();
323 }
324
325 dismissKeyguard(true);
326 }
327
328 if (showPhoneAccountSelectionDialog()) {
329 hideMainInCallFragment();
330 }
331 }
332
333 /**
334 * When relaunching from the dialer app, {@code showDialpad} indicates whether the dialpad should
335 * be shown on launch.
336 *
337 * @param showDialpad {@code true} to indicate the dialpad should be shown on launch, and {@code
338 * false} to indicate no change should be made to the dialpad visibility.
339 */
340 private void relaunchedFromDialer(boolean showDialpad) {
341 showDialpadRequest = showDialpad ? DIALPAD_REQUEST_SHOW : DIALPAD_REQUEST_NONE;
342 animateDialpadOnShow = true;
343
344 if (showDialpadRequest == DIALPAD_REQUEST_SHOW) {
345 // If there's only one line in use, AND it's on hold, then we're sure the user
346 // wants to use the dialpad toward the exact line, so un-hold the holding line.
347 DialerCall call = CallList.getInstance().getActiveOrBackgroundCall();
wangqibb94ca62018-04-27 14:34:04 -0700348 if (call != null && call.getState() == DialerCallState.ONHOLD) {
linyuhc3968e62017-11-20 17:40:50 -0800349 call.unhold();
350 }
351 }
352 }
353
354 /**
355 * Show a phone account selection dialog if there is a call waiting for phone account selection.
356 *
357 * @return true if the dialog was shown.
358 */
359 private boolean showPhoneAccountSelectionDialog() {
360 DialerCall waitingForAccountCall = CallList.getInstance().getWaitingForAccountCall();
361 if (waitingForAccountCall == null) {
362 return false;
363 }
364
twyen56f79ba2018-04-30 14:25:46 -0700365 PreferredAccountWorker preferredAccountWorker =
366 PreferredSimComponent.get(this).preferredAccountWorker();
linyuhc3968e62017-11-20 17:40:50 -0800367
twyen56f79ba2018-04-30 14:25:46 -0700368 Bundle extras = waitingForAccountCall.getIntentExtras();
369 List<PhoneAccountHandle> phoneAccountHandles =
370 extras == null
371 ? new ArrayList<>()
372 : extras.getParcelableArrayList(Call.AVAILABLE_PHONE_ACCOUNTS);
373
374 ListenableFuture<PreferredAccountWorker.Result> preferredAccountFuture =
375 preferredAccountWorker.selectAccount(
376 waitingForAccountCall.getNumber(), phoneAccountHandles);
twyena1723252018-04-24 17:02:57 -0700377 preferredAccountWorkerResultListener.listen(
378 this,
379 preferredAccountFuture,
380 result -> {
twyen3b2c7812018-04-30 12:13:06 -0700381 if (!isVisible()) {
382 LogUtil.i(
383 "CallingAccountSelector.showPhoneAccountSelectionDialog",
384 "activity ended before result returned");
385 return;
386 }
twyen56f79ba2018-04-30 14:25:46 -0700387 String callId = waitingForAccountCall.getId();
388 if (result.getSelectedPhoneAccountHandle().isPresent()) {
twyena1723252018-04-24 17:02:57 -0700389 selectPhoneAccountListener.onPhoneAccountSelected(
twyen56f79ba2018-04-30 14:25:46 -0700390 result.getSelectedPhoneAccountHandle().get(), false, callId);
twyena1723252018-04-24 17:02:57 -0700391 return;
392 }
twyen66adad02018-04-24 13:51:08 -0700393
twyena1723252018-04-24 17:02:57 -0700394 waitingForAccountCall.setPreferredAccountRecorder(
395 new PreferredAccountRecorder(
396 waitingForAccountCall.getNumber(),
397 result.getSuggestion().orNull(),
398 result.getDataId().orNull()));
twyena1723252018-04-24 17:02:57 -0700399 selectPhoneAccountDialogFragment =
400 SelectPhoneAccountDialogFragment.newInstance(
twyen56f79ba2018-04-30 14:25:46 -0700401 result.getDialogOptionsBuilder().get().setCallId(callId).build(),
402 selectPhoneAccountListener);
twyena1723252018-04-24 17:02:57 -0700403 selectPhoneAccountDialogFragment.show(getFragmentManager(), Tags.SELECT_ACCOUNT_FRAGMENT);
404 },
405 throwable -> {
406 throw new RuntimeException(throwable);
407 });
twyen73a74c32018-03-07 12:12:24 -0800408
linyuhc3968e62017-11-20 17:40:50 -0800409 return true;
410 }
411
Eric Erfanianccca3152017-02-22 16:32:36 -0800412 @Override
413 protected void onSaveInstanceState(Bundle out) {
linyuh57b093b2017-11-17 14:32:32 -0800414 LogUtil.enterBlock("InCallActivity.onSaveInstanceState");
415
416 // TODO: DialpadFragment should handle this as part of its own state
linyuhc3968e62017-11-20 17:40:50 -0800417 out.putBoolean(IntentExtraNames.SHOW_DIALPAD, isDialpadVisible());
linyuh57b093b2017-11-17 14:32:32 -0800418 DialpadFragment dialpadFragment = getDialpadFragment();
419 if (dialpadFragment != null) {
linyuhc3968e62017-11-20 17:40:50 -0800420 out.putString(KeysForSavedInstance.DIALPAD_TEXT, dialpadFragment.getDtmfText());
linyuh57b093b2017-11-17 14:32:32 -0800421 }
422
linyuhc3968e62017-11-20 17:40:50 -0800423 out.putBoolean(KeysForSavedInstance.DID_SHOW_ANSWER_SCREEN, didShowAnswerScreen);
424 out.putBoolean(KeysForSavedInstance.DID_SHOW_IN_CALL_SCREEN, didShowInCallScreen);
425 out.putBoolean(KeysForSavedInstance.DID_SHOW_VIDEO_CALL_SCREEN, didShowVideoCallScreen);
wangqi153af2f2018-02-15 16:21:49 -0800426 out.putBoolean(KeysForSavedInstance.DID_SHOW_RTT_CALL_SCREEN, didShowRttCallScreen);
erfaniand05d8992018-03-20 19:42:26 -0700427 out.putBoolean(KeysForSavedInstance.DID_SHOW_SPEAK_EASY_SCREEN, didShowSpeakEasyScreen);
linyuh57b093b2017-11-17 14:32:32 -0800428
Eric Erfanianccca3152017-02-22 16:32:36 -0800429 super.onSaveInstanceState(out);
430 isVisible = false;
431 }
432
433 @Override
434 protected void onStart() {
Eric Erfanian2ca43182017-08-31 06:57:16 -0700435 Trace.beginSection("InCallActivity.onStart");
Eric Erfanianccca3152017-02-22 16:32:36 -0800436 super.onStart();
linyuh57b093b2017-11-17 14:32:32 -0800437
Eric Erfanianccca3152017-02-22 16:32:36 -0800438 isVisible = true;
439 showMainInCallFragment();
linyuh57b093b2017-11-17 14:32:32 -0800440
441 InCallPresenter.getInstance().setActivity(this);
442 enableInCallOrientationEventListener(
443 getRequestedOrientation()
444 == InCallOrientationEventListener.ACTIVITY_PREFERENCE_ALLOW_ROTATION);
445 InCallPresenter.getInstance().onActivityStarted();
446
yueg10f6e822018-01-17 15:32:18 -0800447 if (!isRecreating) {
448 InCallPresenter.getInstance().onUiShowing(true);
449 }
450
linyuh437ae952018-03-26 12:46:18 -0700451 if (isInMultiWindowMode() && !getResources().getBoolean(R.bool.incall_dialpad_allowed)) {
Eric Erfanianccca3152017-02-22 16:32:36 -0800452 // Hide the dialpad because there may not be enough room
453 showDialpadFragment(false, false);
454 }
linyuh57b093b2017-11-17 14:32:32 -0800455
Eric Erfanian2ca43182017-08-31 06:57:16 -0700456 Trace.endSection();
Eric Erfanianccca3152017-02-22 16:32:36 -0800457 }
458
459 @Override
460 protected void onResume() {
Eric Erfanian2ca43182017-08-31 06:57:16 -0700461 Trace.beginSection("InCallActivity.onResume");
Eric Erfanianccca3152017-02-22 16:32:36 -0800462 super.onResume();
linyuhc3968e62017-11-20 17:40:50 -0800463
464 if (!InCallPresenter.getInstance().isReadyForTearDown()) {
465 updateTaskDescription();
linyuhc3968e62017-11-20 17:40:50 -0800466 }
467
468 // If there is a pending request to show or hide the dialpad, handle that now.
469 if (showDialpadRequest != DIALPAD_REQUEST_NONE) {
470 if (showDialpadRequest == DIALPAD_REQUEST_SHOW) {
471 // Exit fullscreen so that the user has access to the dialpad hide/show button.
472 // This is important when showing the dialpad from within dialer.
473 InCallPresenter.getInstance().setFullScreen(false /* isFullScreen */, true /* force */);
474
475 showDialpadFragment(true /* show */, animateDialpadOnShow /* animate */);
476 animateDialpadOnShow = false;
477
478 DialpadFragment dialpadFragment = getDialpadFragment();
479 if (dialpadFragment != null) {
480 dialpadFragment.setDtmfText(dtmfTextToPrepopulate);
481 dtmfTextToPrepopulate = null;
482 }
483 } else {
484 LogUtil.i("InCallActivity.onResume", "Force-hide the dialpad");
485 if (getDialpadFragment() != null) {
486 showDialpadFragment(false /* show */, false /* animate */);
487 }
488 }
489 showDialpadRequest = DIALPAD_REQUEST_NONE;
490 }
linyuhc3968e62017-11-20 17:40:50 -0800491
linyuhc3968e62017-11-20 17:40:50 -0800492 CallList.getInstance()
493 .onInCallUiShown(getIntent().getBooleanExtra(IntentExtraNames.FOR_FULL_SCREEN, false));
494
Eric Erfanianccca3152017-02-22 16:32:36 -0800495 PseudoScreenState pseudoScreenState = InCallPresenter.getInstance().getPseudoScreenState();
496 pseudoScreenState.addListener(this);
497 onPseudoScreenStateChanged(pseudoScreenState.isOn());
Eric Erfanian2ca43182017-08-31 06:57:16 -0700498 Trace.endSection();
weijiaxu650e7cc2017-10-31 12:38:54 -0700499 // add 1 sec delay to get memory snapshot so that dialer wont react slowly on resume.
500 ThreadUtil.postDelayedOnUiThread(
weijiaxuc950a9b2017-11-06 16:39:04 -0800501 () ->
zachh7a96dc72018-02-20 22:16:03 -0800502 MetricsComponent.get(this)
503 .metrics()
504 .recordMemory(Metrics.INCALL_ACTIVITY_ON_RESUME_MEMORY_EVENT_NAME),
weijiaxu650e7cc2017-10-31 12:38:54 -0700505 1000);
Eric Erfanianccca3152017-02-22 16:32:36 -0800506 }
507
Eric Erfanianccca3152017-02-22 16:32:36 -0800508 @Override
509 protected void onPause() {
Eric Erfanian2ca43182017-08-31 06:57:16 -0700510 Trace.beginSection("InCallActivity.onPause");
Eric Erfanianccca3152017-02-22 16:32:36 -0800511 super.onPause();
linyuh57b093b2017-11-17 14:32:32 -0800512
513 DialpadFragment dialpadFragment = getDialpadFragment();
514 if (dialpadFragment != null) {
515 dialpadFragment.onDialerKeyUp(null);
516 }
517
Eric Erfanianccca3152017-02-22 16:32:36 -0800518 InCallPresenter.getInstance().getPseudoScreenState().removeListener(this);
Eric Erfanian2ca43182017-08-31 06:57:16 -0700519 Trace.endSection();
Eric Erfanianccca3152017-02-22 16:32:36 -0800520 }
521
522 @Override
523 protected void onStop() {
Eric Erfanian2ca43182017-08-31 06:57:16 -0700524 Trace.beginSection("InCallActivity.onStop");
wangqi4d705e52017-09-28 12:23:35 -0700525 isVisible = false;
Eric Erfanianccca3152017-02-22 16:32:36 -0800526 super.onStop();
linyuh57b093b2017-11-17 14:32:32 -0800527
528 // Disconnects the call waiting for a phone account when the activity is hidden (e.g., after the
529 // user presses the home button).
530 // Without this the pending call will get stuck on phone account selection and new calls can't
531 // be created.
532 // Skip this when the screen is locked since the activity may complete its current life cycle
533 // and restart.
linyuhc3968e62017-11-20 17:40:50 -0800534 if (!isRecreating && !getSystemService(KeyguardManager.class).isKeyguardLocked()) {
linyuh57b093b2017-11-17 14:32:32 -0800535 DialerCall waitingForAccountCall = CallList.getInstance().getWaitingForAccountCall();
536 if (waitingForAccountCall != null) {
537 waitingForAccountCall.disconnect();
538 }
539 }
540
541 enableInCallOrientationEventListener(false);
542 InCallPresenter.getInstance().updateIsChangingConfigurations();
543 InCallPresenter.getInstance().onActivityStopped();
linyuhc3968e62017-11-20 17:40:50 -0800544 if (!isRecreating) {
yueg10f6e822018-01-17 15:32:18 -0800545 InCallPresenter.getInstance().onUiShowing(false);
wangqie6060522018-04-05 11:47:15 -0700546 }
547 if (errorDialog != null) {
548 errorDialog.dismiss();
linyuh57b093b2017-11-17 14:32:32 -0800549 }
550
yueg10f6e822018-01-17 15:32:18 -0800551 if (isFinishing()) {
552 InCallPresenter.getInstance().unsetActivity(this);
553 }
554
Eric Erfanian2ca43182017-08-31 06:57:16 -0700555 Trace.endSection();
Eric Erfanianccca3152017-02-22 16:32:36 -0800556 }
557
558 @Override
559 protected void onDestroy() {
Eric Erfanian2ca43182017-08-31 06:57:16 -0700560 Trace.beginSection("InCallActivity.onDestroy");
Eric Erfanianccca3152017-02-22 16:32:36 -0800561 super.onDestroy();
linyuh57b093b2017-11-17 14:32:32 -0800562
563 InCallPresenter.getInstance().unsetActivity(this);
564 InCallPresenter.getInstance().updateIsChangingConfigurations();
Eric Erfanian2ca43182017-08-31 06:57:16 -0700565 Trace.endSection();
Eric Erfanianccca3152017-02-22 16:32:36 -0800566 }
567
568 @Override
569 public void finish() {
570 if (shouldCloseActivityOnFinish()) {
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700571 // When user select incall ui from recents after the call is disconnected, it tries to launch
572 // a new InCallActivity but InCallPresenter is already teared down at this point, which causes
573 // crash.
574 // By calling finishAndRemoveTask() instead of finish() the task associated with
575 // InCallActivity is cleared completely. So system won't try to create a new InCallActivity in
576 // this case.
577 //
578 // Calling finish won't clear the task and normally when an activity finishes it shouldn't
579 // clear the task since there could be parent activity in the same task that's still alive.
580 // But InCallActivity is special since it's singleInstance which means it's root activity and
581 // only instance of activity in the task. So it should be safe to also remove task when
582 // finishing.
583 // It's also necessary in the sense of it's excluded from recents. So whenever the activity
584 // finishes, the task should also be removed since it doesn't make sense to go back to it in
585 // anyway anymore.
586 super.finishAndRemoveTask();
Eric Erfanianccca3152017-02-22 16:32:36 -0800587 }
588 }
589
590 private boolean shouldCloseActivityOnFinish() {
linyuhc3968e62017-11-20 17:40:50 -0800591 if (!isVisible) {
Eric Erfanianccca3152017-02-22 16:32:36 -0800592 LogUtil.i(
593 "InCallActivity.shouldCloseActivityOnFinish",
594 "allowing activity to be closed because it's not visible");
595 return true;
596 }
597
twyen8efb4952017-10-06 16:35:54 -0700598 if (InCallPresenter.getInstance().isInCallUiLocked()) {
Eric Erfanianccca3152017-02-22 16:32:36 -0800599 LogUtil.i(
600 "InCallActivity.shouldCloseActivityOnFinish",
twyen8efb4952017-10-06 16:35:54 -0700601 "in call ui is locked, not closing activity");
Eric Erfanianccca3152017-02-22 16:32:36 -0800602 return false;
603 }
604
605 LogUtil.i(
606 "InCallActivity.shouldCloseActivityOnFinish",
twyen8efb4952017-10-06 16:35:54 -0700607 "activity is visible and has no locks, allowing activity to close");
Eric Erfanianccca3152017-02-22 16:32:36 -0800608 return true;
609 }
610
611 @Override
612 protected void onNewIntent(Intent intent) {
linyuhc3968e62017-11-20 17:40:50 -0800613 LogUtil.enterBlock("InCallActivity.onNewIntent");
Eric Erfanianccca3152017-02-22 16:32:36 -0800614
615 // If the screen is off, we need to make sure it gets turned on for incoming calls.
616 // This normally works just fine thanks to FLAG_TURN_SCREEN_ON but that only works
617 // when the activity is first created. Therefore, to ensure the screen is turned on
618 // for the call waiting case, we recreate() the current activity. There should be no jank from
619 // this since the screen is already off and will remain so until our new activity is up.
linyuhc3968e62017-11-20 17:40:50 -0800620 if (!isVisible) {
621 onNewIntent(intent, true /* isRecreating */);
Eric Erfanianccca3152017-02-22 16:32:36 -0800622 LogUtil.i("InCallActivity.onNewIntent", "Restarting InCallActivity to force screen on.");
623 recreate();
Eric Erfanian10b34a52017-05-04 08:23:17 -0700624 } else {
linyuhc3968e62017-11-20 17:40:50 -0800625 onNewIntent(intent, false /* isRecreating */);
626 }
627 }
628
yuega3305352018-01-09 11:02:47 -0800629 @VisibleForTesting
630 void onNewIntent(Intent intent, boolean isRecreating) {
linyuhc3968e62017-11-20 17:40:50 -0800631 this.isRecreating = isRecreating;
632
633 // We're being re-launched with a new Intent. Since it's possible for a single InCallActivity
634 // instance to persist indefinitely (even if we finish() ourselves), this sequence can
635 // happen any time the InCallActivity needs to be displayed.
636
637 // Stash away the new intent so that we can get it in the future by calling getIntent().
638 // Otherwise getIntent() will return the original Intent from when we first got created.
639 setIntent(intent);
640
641 // Activities are always paused before receiving a new intent, so we can count on our onResume()
642 // method being called next.
643
644 // Just like in onCreate(), handle the intent.
645 // Skip if InCallActivity is going to be recreated since this will be called in onCreate().
646 if (!isRecreating) {
647 internalResolveIntent(intent);
Eric Erfanianccca3152017-02-22 16:32:36 -0800648 }
649 }
650
651 @Override
652 public void onBackPressed() {
linyuh57b093b2017-11-17 14:32:32 -0800653 LogUtil.enterBlock("InCallActivity.onBackPressed");
654
linyuhc3968e62017-11-20 17:40:50 -0800655 if (!isVisible) {
linyuh57b093b2017-11-17 14:32:32 -0800656 return;
Eric Erfanianccca3152017-02-22 16:32:36 -0800657 }
linyuh57b093b2017-11-17 14:32:32 -0800658
659 if (!getCallCardFragmentVisible()) {
660 return;
661 }
662
663 DialpadFragment dialpadFragment = getDialpadFragment();
664 if (dialpadFragment != null && dialpadFragment.isVisible()) {
665 showDialpadFragment(false /* show */, true /* animate */);
666 return;
667 }
668
669 if (CallList.getInstance().getIncomingCall() != null) {
670 LogUtil.i(
671 "InCallActivity.onBackPressed",
672 "Ignore the press of the back key when an incoming call is ringing");
673 return;
674 }
675
676 // Nothing special to do. Fall back to the default behavior.
677 super.onBackPressed();
Eric Erfanianccca3152017-02-22 16:32:36 -0800678 }
679
680 @Override
681 public boolean onOptionsItemSelected(MenuItem item) {
682 LogUtil.i("InCallActivity.onOptionsItemSelected", "item: " + item);
683 if (item.getItemId() == android.R.id.home) {
684 onBackPressed();
685 return true;
686 }
687 return super.onOptionsItemSelected(item);
688 }
689
690 @Override
691 public boolean onKeyUp(int keyCode, KeyEvent event) {
linyuh57b093b2017-11-17 14:32:32 -0800692 DialpadFragment dialpadFragment = getDialpadFragment();
693 if (dialpadFragment != null
694 && dialpadFragment.isVisible()
695 && dialpadFragment.onDialerKeyUp(event)) {
696 return true;
697 }
698
699 if (keyCode == KeyEvent.KEYCODE_CALL) {
700 // Always consume KEYCODE_CALL to ensure the PhoneWindow won't do anything with it.
701 return true;
702 }
703
704 return super.onKeyUp(keyCode, event);
Eric Erfanianccca3152017-02-22 16:32:36 -0800705 }
706
707 @Override
708 public boolean onKeyDown(int keyCode, KeyEvent event) {
linyuh57b093b2017-11-17 14:32:32 -0800709 switch (keyCode) {
710 case KeyEvent.KEYCODE_CALL:
711 if (!InCallPresenter.getInstance().handleCallKey()) {
712 LogUtil.e(
713 "InCallActivity.onKeyDown",
714 "InCallPresenter should always handle KEYCODE_CALL in onKeyDown");
715 }
716 // Always consume KEYCODE_CALL to ensure the PhoneWindow won't do anything with it.
717 return true;
718
719 // Note that KEYCODE_ENDCALL isn't handled here as the standard system-wide handling of it
720 // is exactly what's needed, namely
721 // (1) "hang up" if there's an active call, or
722 // (2) "don't answer" if there's an incoming call.
723 // (See PhoneWindowManager for implementation details.)
724
725 case KeyEvent.KEYCODE_CAMERA:
726 // Consume KEYCODE_CAMERA since it's easy to accidentally press the camera button.
727 return true;
728
729 case KeyEvent.KEYCODE_VOLUME_UP:
730 case KeyEvent.KEYCODE_VOLUME_DOWN:
731 case KeyEvent.KEYCODE_VOLUME_MUTE:
732 // Ringer silencing handled by PhoneWindowManager.
733 break;
734
735 case KeyEvent.KEYCODE_MUTE:
736 TelecomAdapter.getInstance()
737 .mute(!AudioModeProvider.getInstance().getAudioState().isMuted());
738 return true;
739
740 case KeyEvent.KEYCODE_SLASH:
741 // When verbose logging is enabled, dump the view for debugging/testing purposes.
742 if (LogUtil.isVerboseEnabled()) {
743 View decorView = getWindow().getDecorView();
744 LogUtil.v("InCallActivity.onKeyDown", "View dump:\n%s", decorView);
745 return true;
746 }
747 break;
748
749 case KeyEvent.KEYCODE_EQUALS:
750 break;
751
752 default: // fall out
753 }
754
755 // Pass other key events to DialpadFragment's "onDialerKeyDown" method in case the user types
756 // in DTMF (Dual-tone multi-frequency signaling) code.
757 DialpadFragment dialpadFragment = getDialpadFragment();
758 if (dialpadFragment != null
759 && dialpadFragment.isVisible()
760 && dialpadFragment.onDialerKeyDown(event)) {
761 return true;
762 }
763
764 return super.onKeyDown(keyCode, event);
Eric Erfanianccca3152017-02-22 16:32:36 -0800765 }
766
767 public boolean isInCallScreenAnimating() {
768 return false;
769 }
770
771 public void showConferenceFragment(boolean show) {
772 if (show) {
773 startActivity(new Intent(this, ManageConferenceActivity.class));
774 }
775 }
776
linyuhc3968e62017-11-20 17:40:50 -0800777 public void showDialpadFragment(boolean show, boolean animate) {
778 if (show == isDialpadVisible()) {
779 return;
Eric Erfanianccca3152017-02-22 16:32:36 -0800780 }
linyuhc3968e62017-11-20 17:40:50 -0800781
782 FragmentManager dialpadFragmentManager = getDialpadFragmentManager();
783 if (dialpadFragmentManager == null) {
784 LogUtil.i("InCallActivity.showDialpadFragment", "Unable to obtain a FragmentManager");
785 return;
786 }
787
788 if (!animate) {
789 if (show) {
790 showDialpadFragment();
791 } else {
792 hideDialpadFragment();
793 }
794 } else {
795 if (show) {
796 showDialpadFragment();
797 getDialpadFragment().animateShowDialpad();
798 }
799 getDialpadFragment()
800 .getView()
801 .startAnimation(show ? dialpadSlideInAnimation : dialpadSlideOutAnimation);
802 }
803
804 ProximitySensor sensor = InCallPresenter.getInstance().getProximitySensor();
805 if (sensor != null) {
806 sensor.onDialpadVisible(show);
807 }
808 showDialpadRequest = DIALPAD_REQUEST_NONE;
linyuhc3968e62017-11-20 17:40:50 -0800809 }
810
811 private void showDialpadFragment() {
812 FragmentManager dialpadFragmentManager = getDialpadFragmentManager();
813 if (dialpadFragmentManager == null) {
814 return;
815 }
816
817 FragmentTransaction transaction = dialpadFragmentManager.beginTransaction();
818 DialpadFragment dialpadFragment = getDialpadFragment();
819 if (dialpadFragment == null) {
wangqifd4c9f72018-03-08 18:21:50 -0800820 dialpadFragment = new DialpadFragment();
821 transaction.add(getDialpadContainerId(), dialpadFragment, Tags.DIALPAD_FRAGMENT);
linyuhc3968e62017-11-20 17:40:50 -0800822 } else {
823 transaction.show(dialpadFragment);
calderwoodrad5883872017-12-12 15:29:12 -0800824 dialpadFragment.setUserVisibleHint(true);
linyuhc3968e62017-11-20 17:40:50 -0800825 }
wangqifd4c9f72018-03-08 18:21:50 -0800826 // RTT call screen doesn't show end call button inside dialpad, thus the space reserved for end
827 // call button should be removed.
828 dialpadFragment.setShouldShowEndCallSpace(didShowInCallScreen);
linyuhc3968e62017-11-20 17:40:50 -0800829 transaction.commitAllowingStateLoss();
830 dialpadFragmentManager.executePendingTransactions();
831
832 Logger.get(this).logScreenView(ScreenEvent.Type.INCALL_DIALPAD, this);
wangqi73ed6132018-05-21 15:57:36 -0700833 getInCallOrRttCallScreen().onInCallScreenDialpadVisibilityChange(true);
linyuhc3968e62017-11-20 17:40:50 -0800834 }
835
836 private void hideDialpadFragment() {
837 FragmentManager dialpadFragmentManager = getDialpadFragmentManager();
838 if (dialpadFragmentManager == null) {
839 return;
840 }
841
calderwoodrad5883872017-12-12 15:29:12 -0800842 DialpadFragment dialpadFragment = getDialpadFragment();
linyuhc3968e62017-11-20 17:40:50 -0800843 if (dialpadFragment != null) {
844 FragmentTransaction transaction = dialpadFragmentManager.beginTransaction();
845 transaction.hide(dialpadFragment);
846 transaction.commitAllowingStateLoss();
847 dialpadFragmentManager.executePendingTransactions();
calderwoodrad5883872017-12-12 15:29:12 -0800848 dialpadFragment.setUserVisibleHint(false);
wangqi73ed6132018-05-21 15:57:36 -0700849 getInCallOrRttCallScreen().onInCallScreenDialpadVisibilityChange(false);
linyuhc3968e62017-11-20 17:40:50 -0800850 }
Eric Erfanianccca3152017-02-22 16:32:36 -0800851 }
852
853 public boolean isDialpadVisible() {
linyuh69a25062017-11-15 16:18:51 -0800854 DialpadFragment dialpadFragment = getDialpadFragment();
calderwoodraa584bcd2018-01-24 12:19:56 -0800855 return dialpadFragment != null
856 && dialpadFragment.isAdded()
857 && !dialpadFragment.isHidden()
858 && dialpadFragment.getView() != null
859 && dialpadFragment.getUserVisibleHint();
linyuh69a25062017-11-15 16:18:51 -0800860 }
861
linyuhc3968e62017-11-20 17:40:50 -0800862 /** Returns the {@link DialpadFragment} that's shown by this activity, or {@code null} */
linyuh69a25062017-11-15 16:18:51 -0800863 @Nullable
linyuhc3968e62017-11-20 17:40:50 -0800864 private DialpadFragment getDialpadFragment() {
linyuh69a25062017-11-15 16:18:51 -0800865 FragmentManager fragmentManager = getDialpadFragmentManager();
866 if (fragmentManager == null) {
867 return null;
868 }
linyuhc3968e62017-11-20 17:40:50 -0800869 return (DialpadFragment) fragmentManager.findFragmentByTag(Tags.DIALPAD_FRAGMENT);
Eric Erfanianccca3152017-02-22 16:32:36 -0800870 }
871
872 public void onForegroundCallChanged(DialerCall newForegroundCall) {
linyuh57b093b2017-11-17 14:32:32 -0800873 updateTaskDescription();
874
875 if (newForegroundCall == null || !didShowAnswerScreen) {
Eric Erfanianccca3152017-02-22 16:32:36 -0800876 LogUtil.v("InCallActivity.onForegroundCallChanged", "resetting background color");
linyuh57b093b2017-11-17 14:32:32 -0800877 updateWindowBackgroundColor(0 /* progress */);
Eric Erfanianccca3152017-02-22 16:32:36 -0800878 }
879 }
880
linyuhc3968e62017-11-20 17:40:50 -0800881 private void updateTaskDescription() {
linyuh57b093b2017-11-17 14:32:32 -0800882 int color =
883 getResources().getBoolean(R.bool.is_layout_landscape)
884 ? ResourcesCompat.getColor(
885 getResources(), R.color.statusbar_background_color, getTheme())
886 : InCallPresenter.getInstance().getThemeColorManager().getSecondaryColor();
887 setTaskDescription(
888 new TaskDescription(
889 getResources().getString(R.string.notification_ongoing_call), null /* icon */, color));
890 }
891
Eric Erfanianccca3152017-02-22 16:32:36 -0800892 public void updateWindowBackgroundColor(@FloatRange(from = -1f, to = 1.0f) float progress) {
893 ThemeColorManager themeColorManager = InCallPresenter.getInstance().getThemeColorManager();
894 @ColorInt int top;
895 @ColorInt int middle;
896 @ColorInt int bottom;
897 @ColorInt int gray = 0x66000000;
898
linyuh437ae952018-03-26 12:46:18 -0700899 if (isInMultiWindowMode()) {
Eric Erfanianccca3152017-02-22 16:32:36 -0800900 top = themeColorManager.getBackgroundColorSolid();
901 middle = themeColorManager.getBackgroundColorSolid();
902 bottom = themeColorManager.getBackgroundColorSolid();
903 } else {
904 top = themeColorManager.getBackgroundColorTop();
905 middle = themeColorManager.getBackgroundColorMiddle();
906 bottom = themeColorManager.getBackgroundColorBottom();
907 }
908
909 if (progress < 0) {
910 float correctedProgress = Math.abs(progress);
911 top = ColorUtils.blendARGB(top, gray, correctedProgress);
912 middle = ColorUtils.blendARGB(middle, gray, correctedProgress);
913 bottom = ColorUtils.blendARGB(bottom, gray, correctedProgress);
914 }
915
916 boolean backgroundDirty = false;
917 if (backgroundDrawable == null) {
918 backgroundDrawableColors = new int[] {top, middle, bottom};
919 backgroundDrawable = new GradientDrawable(Orientation.TOP_BOTTOM, backgroundDrawableColors);
920 backgroundDirty = true;
921 } else {
922 if (backgroundDrawableColors[0] != top) {
923 backgroundDrawableColors[0] = top;
924 backgroundDirty = true;
925 }
926 if (backgroundDrawableColors[1] != middle) {
927 backgroundDrawableColors[1] = middle;
928 backgroundDirty = true;
929 }
930 if (backgroundDrawableColors[2] != bottom) {
931 backgroundDrawableColors[2] = bottom;
932 backgroundDirty = true;
933 }
934 if (backgroundDirty) {
935 backgroundDrawable.setColors(backgroundDrawableColors);
936 }
937 }
938
939 if (backgroundDirty) {
940 getWindow().setBackgroundDrawable(backgroundDrawable);
941 }
942 }
943
944 public boolean isVisible() {
945 return isVisible;
946 }
947
948 public boolean getCallCardFragmentVisible() {
erfaniand05d8992018-03-20 19:42:26 -0700949 return didShowInCallScreen
950 || didShowVideoCallScreen
951 || didShowRttCallScreen
952 || didShowSpeakEasyScreen;
Eric Erfanianccca3152017-02-22 16:32:36 -0800953 }
954
955 public void dismissKeyguard(boolean dismiss) {
linyuh9c327da2017-11-14 12:33:48 -0800956 if (dismissKeyguard == dismiss) {
957 return;
958 }
959
960 dismissKeyguard = dismiss;
961 if (dismiss) {
962 getWindow().addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);
963 } else {
964 getWindow().clearFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);
965 }
Eric Erfanianccca3152017-02-22 16:32:36 -0800966 }
967
linyuhc3968e62017-11-20 17:40:50 -0800968 public void showDialogForPostCharWait(String callId, String chars) {
yuega489f512018-04-25 12:01:09 -0700969 PostCharDialogFragment fragment = new PostCharDialogFragment(callId, chars);
970 fragment.show(getSupportFragmentManager(), Tags.POST_CHAR_DIALOG_FRAGMENT);
Eric Erfanianccca3152017-02-22 16:32:36 -0800971 }
972
linyuh7b86f562017-11-16 11:24:09 -0800973 public void showDialogOrToastForDisconnectedCall(DisconnectMessage disconnectMessage) {
974 LogUtil.i(
975 "InCallActivity.showDialogOrToastForDisconnectedCall",
976 "disconnect cause: %s",
977 disconnectMessage);
978
979 if (disconnectMessage.dialog == null || isFinishing()) {
980 return;
981 }
982
983 dismissPendingDialogs();
984
985 // Show a toast if the app is in background when a dialog can't be visible.
986 if (!isVisible()) {
987 Toast.makeText(getApplicationContext(), disconnectMessage.toastMessage, Toast.LENGTH_LONG)
988 .show();
989 return;
990 }
991
992 // Show the dialog.
linyuhc3968e62017-11-20 17:40:50 -0800993 errorDialog = disconnectMessage.dialog;
linyuh7b86f562017-11-16 11:24:09 -0800994 InCallUiLock lock = InCallPresenter.getInstance().acquireInCallUiLock("showErrorDialog");
995 disconnectMessage.dialog.setOnDismissListener(
996 dialogInterface -> {
997 lock.release();
998 onDialogDismissed();
999 });
1000 disconnectMessage.dialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
1001 disconnectMessage.dialog.show();
1002 }
1003
1004 private void onDialogDismissed() {
linyuhc3968e62017-11-20 17:40:50 -08001005 errorDialog = null;
linyuh7b86f562017-11-16 11:24:09 -08001006 CallList.getInstance().onErrorDialogDismissed();
Eric Erfanianccca3152017-02-22 16:32:36 -08001007 }
1008
1009 public void dismissPendingDialogs() {
linyuhc3968e62017-11-20 17:40:50 -08001010 LogUtil.enterBlock("InCallActivity.dismissPendingDialogs");
linyuhf99f6302017-11-15 11:23:51 -08001011
1012 if (!isVisible) {
1013 // Defer the dismissing action as the activity is not visible and onSaveInstanceState may have
1014 // been called.
Eric Erfanianccca3152017-02-22 16:32:36 -08001015 LogUtil.i(
1016 "InCallActivity.dismissPendingDialogs", "defer actions since activity is not visible");
1017 needDismissPendingDialogs = true;
linyuhf99f6302017-11-15 11:23:51 -08001018 return;
Eric Erfanianccca3152017-02-22 16:32:36 -08001019 }
linyuhf99f6302017-11-15 11:23:51 -08001020
1021 // Dismiss the error dialog
linyuhf99f6302017-11-15 11:23:51 -08001022 if (errorDialog != null) {
1023 errorDialog.dismiss();
linyuhc3968e62017-11-20 17:40:50 -08001024 errorDialog = null;
linyuhf99f6302017-11-15 11:23:51 -08001025 }
1026
1027 // Dismiss the phone account selection dialog
linyuhf99f6302017-11-15 11:23:51 -08001028 if (selectPhoneAccountDialogFragment != null) {
1029 selectPhoneAccountDialogFragment.dismiss();
linyuhc3968e62017-11-20 17:40:50 -08001030 selectPhoneAccountDialogFragment = null;
linyuhf99f6302017-11-15 11:23:51 -08001031 }
1032
1033 // Dismiss the dialog for international call on WiFi
1034 InternationalCallOnWifiDialogFragment internationalCallOnWifiFragment =
1035 (InternationalCallOnWifiDialogFragment)
linyuhc3968e62017-11-20 17:40:50 -08001036 getSupportFragmentManager().findFragmentByTag(Tags.INTERNATIONAL_CALL_ON_WIFI);
linyuhf99f6302017-11-15 11:23:51 -08001037 if (internationalCallOnWifiFragment != null) {
1038 internationalCallOnWifiFragment.dismiss();
1039 }
1040
1041 // Dismiss the answer screen
1042 AnswerScreen answerScreen = getAnswerScreen();
1043 if (answerScreen != null) {
1044 answerScreen.dismissPendingDialogs();
1045 }
1046
1047 needDismissPendingDialogs = false;
Eric Erfanianccca3152017-02-22 16:32:36 -08001048 }
1049
linyuhc3968e62017-11-20 17:40:50 -08001050 private void enableInCallOrientationEventListener(boolean enable) {
linyuh69a25062017-11-15 16:18:51 -08001051 if (enable) {
1052 inCallOrientationEventListener.enable(true /* notifyDeviceOrientationChange */);
1053 } else {
1054 inCallOrientationEventListener.disable();
1055 }
Eric Erfanianccca3152017-02-22 16:32:36 -08001056 }
1057
1058 public void setExcludeFromRecents(boolean exclude) {
linyuhc3968e62017-11-20 17:40:50 -08001059 int taskId = getTaskId();
1060
1061 List<AppTask> tasks = getSystemService(ActivityManager.class).getAppTasks();
1062 for (AppTask task : tasks) {
1063 try {
1064 if (task.getTaskInfo().id == taskId) {
1065 task.setExcludeFromRecents(exclude);
1066 }
1067 } catch (RuntimeException e) {
1068 LogUtil.e("InCallActivity.setExcludeFromRecents", "RuntimeException:\n%s", e);
1069 }
1070 }
Eric Erfanianccca3152017-02-22 16:32:36 -08001071 }
1072
Eric Erfanianccca3152017-02-22 16:32:36 -08001073 @Nullable
1074 public FragmentManager getDialpadFragmentManager() {
wangqifd4c9f72018-03-08 18:21:50 -08001075 InCallScreen inCallScreen = getInCallOrRttCallScreen();
Eric Erfanianccca3152017-02-22 16:32:36 -08001076 if (inCallScreen != null) {
1077 return inCallScreen.getInCallScreenFragment().getChildFragmentManager();
1078 }
1079 return null;
1080 }
1081
1082 public int getDialpadContainerId() {
wangqifd4c9f72018-03-08 18:21:50 -08001083 return getInCallOrRttCallScreen().getAnswerAndDialpadContainerResourceId();
Eric Erfanianccca3152017-02-22 16:32:36 -08001084 }
1085
1086 @Override
1087 public AnswerScreenDelegate newAnswerScreenDelegate(AnswerScreen answerScreen) {
1088 DialerCall call = CallList.getInstance().getCallById(answerScreen.getCallId());
1089 if (call == null) {
1090 // This is a work around for a bug where we attempt to create a new delegate after the call
1091 // has already been removed. An example of when this can happen is:
1092 // 1. incoming video call in landscape mode
1093 // 2. remote party hangs up
1094 // 3. activity switches from landscape to portrait
1095 // At step #3 the answer fragment will try to create a new answer delegate but the call won't
1096 // exist. In this case we'll simply return a stub delegate that does nothing. This is ok
1097 // because this new state is transient and the activity will be destroyed soon.
1098 LogUtil.i("InCallActivity.onPrimaryCallStateChanged", "call doesn't exist, using stub");
1099 return new AnswerScreenPresenterStub();
1100 } else {
1101 return new AnswerScreenPresenter(
1102 this, answerScreen, CallList.getInstance().getCallById(answerScreen.getCallId()));
1103 }
1104 }
1105
1106 @Override
1107 public InCallScreenDelegate newInCallScreenDelegate() {
1108 return new CallCardPresenter(this);
1109 }
1110
1111 @Override
1112 public InCallButtonUiDelegate newInCallButtonUiDelegate() {
1113 return new CallButtonPresenter(this);
1114 }
1115
1116 @Override
Eric Erfanian90508232017-03-24 09:31:16 -07001117 public VideoCallScreenDelegate newVideoCallScreenDelegate(VideoCallScreen videoCallScreen) {
1118 DialerCall dialerCall = CallList.getInstance().getCallById(videoCallScreen.getCallId());
1119 if (dialerCall != null && dialerCall.getVideoTech().shouldUseSurfaceView()) {
1120 return dialerCall.getVideoTech().createVideoCallScreenDelegate(this, videoCallScreen);
1121 }
Eric Erfanianccca3152017-02-22 16:32:36 -08001122 return new VideoCallPresenter();
1123 }
1124
1125 public void onPrimaryCallStateChanged() {
Eric Erfanian2ca43182017-08-31 06:57:16 -07001126 Trace.beginSection("InCallActivity.onPrimaryCallStateChanged");
Eric Erfanianccca3152017-02-22 16:32:36 -08001127 showMainInCallFragment();
Eric Erfanian2ca43182017-08-31 06:57:16 -07001128 Trace.endSection();
Eric Erfanianccca3152017-02-22 16:32:36 -08001129 }
1130
linyuh7b86f562017-11-16 11:24:09 -08001131 public void showDialogOrToastForWifiHandoverFailure(DialerCall call) {
1132 if (call.showWifiHandoverAlertAsToast()) {
1133 Toast.makeText(this, R.string.video_call_lte_to_wifi_failed_message, Toast.LENGTH_SHORT)
1134 .show();
1135 return;
1136 }
1137
1138 dismissPendingDialogs();
1139
1140 AlertDialog.Builder builder =
1141 new AlertDialog.Builder(this).setTitle(R.string.video_call_lte_to_wifi_failed_title);
1142
1143 // This allows us to use the theme of the dialog instead of the activity
1144 View dialogCheckBoxView =
1145 View.inflate(builder.getContext(), R.layout.video_call_lte_to_wifi_failed, null /* root */);
1146 CheckBox wifiHandoverFailureCheckbox =
1147 (CheckBox) dialogCheckBoxView.findViewById(R.id.video_call_lte_to_wifi_failed_checkbox);
1148 wifiHandoverFailureCheckbox.setChecked(false);
1149
1150 InCallUiLock lock = InCallPresenter.getInstance().acquireInCallUiLock("WifiFailedDialog");
linyuhc3968e62017-11-20 17:40:50 -08001151 errorDialog =
linyuh7b86f562017-11-16 11:24:09 -08001152 builder
1153 .setView(dialogCheckBoxView)
1154 .setMessage(R.string.video_call_lte_to_wifi_failed_message)
1155 .setOnCancelListener(dialogInterface -> onDialogDismissed())
1156 .setPositiveButton(
1157 android.R.string.ok,
1158 (dialogInterface, id) -> {
1159 call.setDoNotShowDialogForHandoffToWifiFailure(
1160 wifiHandoverFailureCheckbox.isChecked());
1161 dialogInterface.cancel();
1162 onDialogDismissed();
1163 })
1164 .setOnDismissListener(dialogInterface -> lock.release())
1165 .create();
linyuh7b86f562017-11-16 11:24:09 -08001166 errorDialog.show();
Eric Erfanianccca3152017-02-22 16:32:36 -08001167 }
1168
linyuh7b86f562017-11-16 11:24:09 -08001169 public void showDialogForInternationalCallOnWifi(@NonNull DialerCall call) {
linyuh7b86f562017-11-16 11:24:09 -08001170 InternationalCallOnWifiDialogFragment fragment =
yuegb47528e2018-04-24 12:12:57 -07001171 InternationalCallOnWifiDialogFragment.newInstance(call.getId());
linyuhc3968e62017-11-20 17:40:50 -08001172 fragment.show(getSupportFragmentManager(), Tags.INTERNATIONAL_CALL_ON_WIFI);
Eric Erfanianc857f902017-05-15 14:05:33 -07001173 }
1174
wangqibc28ea72018-04-02 16:23:00 -07001175 public void showDialogForRttRequest(DialerCall call, int rttRequestId) {
1176 LogUtil.enterBlock("InCallActivity.showDialogForRttRequest");
1177 DialogFragment fragment = RttRequestDialogFragment.newInstance(call.getId(), rttRequestId);
1178 fragment.show(getSupportFragmentManager(), Tags.RTT_REQUEST_DIALOG);
1179 }
1180
Eric Erfanianccca3152017-02-22 16:32:36 -08001181 public void setAllowOrientationChange(boolean allowOrientationChange) {
wangqi9982f0d2017-10-11 17:46:07 -07001182 if (this.allowOrientationChange == allowOrientationChange) {
1183 return;
1184 }
1185 this.allowOrientationChange = allowOrientationChange;
Eric Erfanianccca3152017-02-22 16:32:36 -08001186 if (!allowOrientationChange) {
1187 setRequestedOrientation(InCallOrientationEventListener.ACTIVITY_PREFERENCE_DISALLOW_ROTATION);
1188 } else {
1189 setRequestedOrientation(InCallOrientationEventListener.ACTIVITY_PREFERENCE_ALLOW_ROTATION);
1190 }
1191 enableInCallOrientationEventListener(allowOrientationChange);
1192 }
1193
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001194 public void hideMainInCallFragment() {
linyuhc3968e62017-11-20 17:40:50 -08001195 LogUtil.enterBlock("InCallActivity.hideMainInCallFragment");
1196 if (getCallCardFragmentVisible()) {
Eric Erfanianccca3152017-02-22 16:32:36 -08001197 FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
1198 hideInCallScreenFragment(transaction);
1199 hideVideoCallScreenFragment(transaction);
1200 transaction.commitAllowingStateLoss();
1201 getSupportFragmentManager().executePendingTransactions();
1202 }
1203 }
1204
1205 private void showMainInCallFragment() {
Eric Erfanian2ca43182017-08-31 06:57:16 -07001206 Trace.beginSection("InCallActivity.showMainInCallFragment");
Eric Erfanianccca3152017-02-22 16:32:36 -08001207 // If the activity's onStart method hasn't been called yet then defer doing any work.
1208 if (!isVisible) {
1209 LogUtil.i("InCallActivity.showMainInCallFragment", "not visible yet/anymore");
Eric Erfanian2ca43182017-08-31 06:57:16 -07001210 Trace.endSection();
Eric Erfanianccca3152017-02-22 16:32:36 -08001211 return;
1212 }
1213
1214 // Don't let this be reentrant.
1215 if (isInShowMainInCallFragment) {
1216 LogUtil.i("InCallActivity.showMainInCallFragment", "already in method, bailing");
Eric Erfanian2ca43182017-08-31 06:57:16 -07001217 Trace.endSection();
Eric Erfanianccca3152017-02-22 16:32:36 -08001218 return;
1219 }
1220
1221 isInShowMainInCallFragment = true;
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001222 ShouldShowUiResult shouldShowAnswerUi = getShouldShowAnswerUi();
1223 ShouldShowUiResult shouldShowVideoUi = getShouldShowVideoUi();
wangqi219b8702018-02-13 09:34:41 -08001224 ShouldShowUiResult shouldShowRttUi = getShouldShowRttUi();
erfaniand05d8992018-03-20 19:42:26 -07001225 ShouldShowUiResult shouldShowSpeakEasyUi = getShouldShowSpeakEasyUi();
Eric Erfanianccca3152017-02-22 16:32:36 -08001226 LogUtil.i(
1227 "InCallActivity.showMainInCallFragment",
uabdullah56a4cda2018-05-10 16:38:35 -07001228 "shouldShowAnswerUi: %b, shouldShowRttUi: %b, shouldShowVideoUi: %b, "
1229 + "shouldShowSpeakEasyUi: %b, didShowAnswerScreen: %b, didShowInCallScreen: %b, "
1230 + "didShowRttCallScreen: %b, didShowVideoCallScreen: %b, didShowSpeakEasyScreen: %b",
Eric Erfanianccca3152017-02-22 16:32:36 -08001231 shouldShowAnswerUi.shouldShow,
wangqi219b8702018-02-13 09:34:41 -08001232 shouldShowRttUi.shouldShow,
Eric Erfanian10b34a52017-05-04 08:23:17 -07001233 shouldShowVideoUi.shouldShow,
uabdullah56a4cda2018-05-10 16:38:35 -07001234 shouldShowSpeakEasyUi.shouldShow,
Eric Erfanianccca3152017-02-22 16:32:36 -08001235 didShowAnswerScreen,
1236 didShowInCallScreen,
wangqi219b8702018-02-13 09:34:41 -08001237 didShowRttCallScreen,
erfaniand05d8992018-03-20 19:42:26 -07001238 didShowVideoCallScreen,
1239 didShowSpeakEasyScreen);
Eric Erfanianccca3152017-02-22 16:32:36 -08001240 // Only video call ui allows orientation change.
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001241 setAllowOrientationChange(shouldShowVideoUi.shouldShow);
Eric Erfanianccca3152017-02-22 16:32:36 -08001242
1243 FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
wangqi219b8702018-02-13 09:34:41 -08001244 boolean didChange;
Eric Erfanianccca3152017-02-22 16:32:36 -08001245 if (shouldShowAnswerUi.shouldShow) {
wangqi219b8702018-02-13 09:34:41 -08001246 didChange = hideInCallScreenFragment(transaction);
1247 didChange |= hideVideoCallScreenFragment(transaction);
1248 didChange |= hideRttCallScreenFragment(transaction);
erfaniand05d8992018-03-20 19:42:26 -07001249 didChange |= hideSpeakEasyFragment(transaction);
wangqi219b8702018-02-13 09:34:41 -08001250 didChange |= showAnswerScreenFragment(transaction, shouldShowAnswerUi.call);
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001251 } else if (shouldShowVideoUi.shouldShow) {
wangqi219b8702018-02-13 09:34:41 -08001252 didChange = hideInCallScreenFragment(transaction);
1253 didChange |= showVideoCallScreenFragment(transaction, shouldShowVideoUi.call);
1254 didChange |= hideRttCallScreenFragment(transaction);
erfaniand05d8992018-03-20 19:42:26 -07001255 didChange |= hideSpeakEasyFragment(transaction);
wangqi219b8702018-02-13 09:34:41 -08001256 didChange |= hideAnswerScreenFragment(transaction);
1257 } else if (shouldShowRttUi.shouldShow) {
1258 didChange = hideInCallScreenFragment(transaction);
1259 didChange |= hideVideoCallScreenFragment(transaction);
1260 didChange |= hideAnswerScreenFragment(transaction);
erfaniand05d8992018-03-20 19:42:26 -07001261 didChange |= hideSpeakEasyFragment(transaction);
wangqi219b8702018-02-13 09:34:41 -08001262 didChange |= showRttCallScreenFragment(transaction, shouldShowRttUi.call);
erfaniand05d8992018-03-20 19:42:26 -07001263 } else if (shouldShowSpeakEasyUi.shouldShow) {
1264 didChange = hideInCallScreenFragment(transaction);
1265 didChange |= hideVideoCallScreenFragment(transaction);
1266 didChange |= hideAnswerScreenFragment(transaction);
1267 didChange |= hideRttCallScreenFragment(transaction);
1268 didChange |= showSpeakEasyFragment(transaction, shouldShowSpeakEasyUi.call);
Eric Erfanianccca3152017-02-22 16:32:36 -08001269 } else {
wangqi219b8702018-02-13 09:34:41 -08001270 didChange = showInCallScreenFragment(transaction);
1271 didChange |= hideVideoCallScreenFragment(transaction);
1272 didChange |= hideRttCallScreenFragment(transaction);
erfaniand05d8992018-03-20 19:42:26 -07001273 didChange |= hideSpeakEasyFragment(transaction);
wangqi219b8702018-02-13 09:34:41 -08001274 didChange |= hideAnswerScreenFragment(transaction);
Eric Erfanianccca3152017-02-22 16:32:36 -08001275 }
1276
wangqi219b8702018-02-13 09:34:41 -08001277 if (didChange) {
Eric Erfanian2ca43182017-08-31 06:57:16 -07001278 Trace.beginSection("InCallActivity.commitTransaction");
Eric Erfanianccca3152017-02-22 16:32:36 -08001279 transaction.commitNow();
Eric Erfanian2ca43182017-08-31 06:57:16 -07001280 Trace.endSection();
Eric Erfanianccca3152017-02-22 16:32:36 -08001281 Logger.get(this).logScreenView(ScreenEvent.Type.INCALL, this);
1282 }
1283 isInShowMainInCallFragment = false;
Eric Erfanian2ca43182017-08-31 06:57:16 -07001284 Trace.endSection();
Eric Erfanianccca3152017-02-22 16:32:36 -08001285 }
1286
erfaniand05d8992018-03-20 19:42:26 -07001287 private boolean showSpeakEasyFragment(FragmentTransaction transaction, DialerCall call) {
1288
erfaniand05d8992018-03-20 19:42:26 -07001289 if (didShowSpeakEasyScreen) {
erfanian612d13a2018-04-04 15:27:57 -07001290 if (lastShownSpeakEasyScreenUniqueCallid.equals(call.getUniqueCallId())) {
erfanian12243de2018-04-17 12:17:08 -07001291 LogUtil.i("InCallActivity.showSpeakEasyFragment", "found existing fragment");
erfanian612d13a2018-04-04 15:27:57 -07001292 return false;
1293 }
1294 hideSpeakEasyFragment(transaction);
erfanian12243de2018-04-17 12:17:08 -07001295 LogUtil.i("InCallActivity.showSpeakEasyFragment", "hid existing fragment");
erfaniand05d8992018-03-20 19:42:26 -07001296 }
1297
1298 Optional<Fragment> speakEasyFragment = speakEasyCallManager.getSpeakEasyFragment(call);
1299 if (speakEasyFragment.isPresent()) {
1300 transaction.add(R.id.main, speakEasyFragment.get(), Tags.SPEAK_EASY_SCREEN);
1301 didShowSpeakEasyScreen = true;
erfanian612d13a2018-04-04 15:27:57 -07001302 lastShownSpeakEasyScreenUniqueCallid = call.getUniqueCallId();
erfanian12243de2018-04-17 12:17:08 -07001303 LogUtil.i(
1304 "InCallActivity.showSpeakEasyFragment",
1305 "set fragment for call %s",
1306 lastShownSpeakEasyScreenUniqueCallid);
erfaniand05d8992018-03-20 19:42:26 -07001307 return true;
1308 }
1309 return false;
1310 }
1311
1312 private Fragment getSpeakEasyScreen() {
1313 return getSupportFragmentManager().findFragmentByTag(Tags.SPEAK_EASY_SCREEN);
1314 }
1315
1316 private boolean hideSpeakEasyFragment(FragmentTransaction transaction) {
1317 if (!didShowSpeakEasyScreen) {
1318 return false;
1319 }
1320
1321 Fragment speakEasyFragment = getSpeakEasyScreen();
1322
1323 if (speakEasyFragment != null) {
1324 transaction.remove(speakEasyFragment);
1325 didShowSpeakEasyScreen = false;
1326 return true;
1327 }
1328 return false;
1329 }
1330
erfanian12243de2018-04-17 12:17:08 -07001331 @VisibleForTesting
erfaniand05d8992018-03-20 19:42:26 -07001332 public void setSpeakEasyCallManager(SpeakEasyCallManager speakEasyCallManager) {
erfanian87dbb622018-04-04 15:43:00 -07001333 this.speakEasyCallManager = speakEasyCallManager;
erfaniand05d8992018-03-20 19:42:26 -07001334 }
1335
erfanian12243de2018-04-17 12:17:08 -07001336 @Nullable
erfaniand05d8992018-03-20 19:42:26 -07001337 public SpeakEasyCallManager getSpeakEasyCallManager() {
erfanian12243de2018-04-17 12:17:08 -07001338 if (this.speakEasyCallManager == null) {
1339 this.speakEasyCallManager = InCallPresenter.getInstance().getSpeakEasyCallManager();
1340 }
erfaniand05d8992018-03-20 19:42:26 -07001341 return speakEasyCallManager;
1342 }
1343
1344 private ShouldShowUiResult getShouldShowSpeakEasyUi() {
1345 SpeakEasyCallManager speakEasyCallManager = getSpeakEasyCallManager();
1346
1347 if (speakEasyCallManager == null) {
1348 return new ShouldShowUiResult(false, null);
1349 }
1350
erfanian3bb7cb62018-04-11 09:01:15 -07001351 DialerCall call =
1352 CallList.getInstance().getIncomingCall() != null
1353 ? CallList.getInstance().getIncomingCall()
1354 : CallList.getInstance().getActiveCall();
erfaniand05d8992018-03-20 19:42:26 -07001355
1356 if (call == null) {
1357 return new ShouldShowUiResult(false, call);
1358 }
1359
1360 if (!call.isSpeakEasyCall() || !call.isSpeakEasyEligible()) {
1361 return new ShouldShowUiResult(false, call);
1362 }
1363
1364 Optional<Fragment> speakEasyFragment = speakEasyCallManager.getSpeakEasyFragment(call);
1365
1366 if (!speakEasyFragment.isPresent()) {
1367 return new ShouldShowUiResult(false, call);
1368 }
1369 return new ShouldShowUiResult(true, call);
1370 }
1371
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001372 private ShouldShowUiResult getShouldShowAnswerUi() {
Eric Erfanianccca3152017-02-22 16:32:36 -08001373 DialerCall call = CallList.getInstance().getIncomingCall();
erfanian3bb7cb62018-04-11 09:01:15 -07001374 if (call != null && !call.isSpeakEasyCall()) {
Eric Erfanianccca3152017-02-22 16:32:36 -08001375 LogUtil.i("InCallActivity.getShouldShowAnswerUi", "found incoming call");
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001376 return new ShouldShowUiResult(true, call);
Eric Erfanianccca3152017-02-22 16:32:36 -08001377 }
1378
1379 call = CallList.getInstance().getVideoUpgradeRequestCall();
1380 if (call != null) {
1381 LogUtil.i("InCallActivity.getShouldShowAnswerUi", "found video upgrade request");
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001382 return new ShouldShowUiResult(true, call);
Eric Erfanianccca3152017-02-22 16:32:36 -08001383 }
1384
1385 // Check if we're showing the answer screen and the call is disconnected. If this condition is
1386 // true then we won't switch from the answer UI to the in call UI. This prevents flicker when
1387 // the user rejects an incoming call.
1388 call = CallList.getInstance().getFirstCall();
1389 if (call == null) {
1390 call = CallList.getInstance().getBackgroundCall();
1391 }
wangqibb94ca62018-04-27 14:34:04 -07001392 if (didShowAnswerScreen && (call == null || call.getState() == DialerCallState.DISCONNECTED)) {
Eric Erfanianccca3152017-02-22 16:32:36 -08001393 LogUtil.i("InCallActivity.getShouldShowAnswerUi", "found disconnecting incoming call");
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001394 return new ShouldShowUiResult(true, call);
Eric Erfanianccca3152017-02-22 16:32:36 -08001395 }
1396
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001397 return new ShouldShowUiResult(false, null);
Eric Erfanianccca3152017-02-22 16:32:36 -08001398 }
1399
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001400 private static ShouldShowUiResult getShouldShowVideoUi() {
Eric Erfanianccca3152017-02-22 16:32:36 -08001401 DialerCall call = CallList.getInstance().getFirstCall();
1402 if (call == null) {
1403 LogUtil.i("InCallActivity.getShouldShowVideoUi", "null call");
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001404 return new ShouldShowUiResult(false, null);
Eric Erfanianccca3152017-02-22 16:32:36 -08001405 }
1406
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001407 if (call.isVideoCall()) {
Eric Erfanianccca3152017-02-22 16:32:36 -08001408 LogUtil.i("InCallActivity.getShouldShowVideoUi", "found video call");
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001409 return new ShouldShowUiResult(true, call);
Eric Erfanianccca3152017-02-22 16:32:36 -08001410 }
1411
linyuh8fbecce2017-12-18 13:53:09 -08001412 if (call.hasSentVideoUpgradeRequest() || call.hasReceivedVideoUpgradeRequest()) {
Eric Erfanianccca3152017-02-22 16:32:36 -08001413 LogUtil.i("InCallActivity.getShouldShowVideoUi", "upgrading to video");
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001414 return new ShouldShowUiResult(true, call);
Eric Erfanianccca3152017-02-22 16:32:36 -08001415 }
1416
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001417 return new ShouldShowUiResult(false, null);
Eric Erfanianccca3152017-02-22 16:32:36 -08001418 }
1419
wangqi219b8702018-02-13 09:34:41 -08001420 private static ShouldShowUiResult getShouldShowRttUi() {
1421 DialerCall call = CallList.getInstance().getFirstCall();
1422 if (call == null) {
1423 LogUtil.i("InCallActivity.getShouldShowRttUi", "null call");
1424 return new ShouldShowUiResult(false, null);
1425 }
1426
wangqif6be6172018-03-30 15:57:56 -07001427 if (call.isActiveRttCall()) {
wangqi219b8702018-02-13 09:34:41 -08001428 LogUtil.i("InCallActivity.getShouldShowRttUi", "found rtt call");
1429 return new ShouldShowUiResult(true, call);
1430 }
1431
1432 if (call.hasSentRttUpgradeRequest()) {
1433 LogUtil.i("InCallActivity.getShouldShowRttUi", "upgrading to rtt");
1434 return new ShouldShowUiResult(true, call);
1435 }
1436
1437 return new ShouldShowUiResult(false, null);
1438 }
1439
Eric Erfanianccca3152017-02-22 16:32:36 -08001440 private boolean showAnswerScreenFragment(FragmentTransaction transaction, DialerCall call) {
1441 // When rejecting a call the active call can become null in which case we should continue
1442 // showing the answer screen.
1443 if (didShowAnswerScreen && call == null) {
1444 return false;
1445 }
1446
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001447 Assert.checkArgument(call != null, "didShowAnswerScreen was false but call was still null");
1448
1449 boolean isVideoUpgradeRequest = call.hasReceivedVideoUpgradeRequest();
Eric Erfanianccca3152017-02-22 16:32:36 -08001450
1451 // Check if we're already showing an answer screen for this call.
1452 if (didShowAnswerScreen) {
1453 AnswerScreen answerScreen = getAnswerScreen();
1454 if (answerScreen.getCallId().equals(call.getId())
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001455 && answerScreen.isVideoCall() == call.isVideoCall()
Eric Erfanian2ca43182017-08-31 06:57:16 -07001456 && answerScreen.isVideoUpgradeRequest() == isVideoUpgradeRequest
1457 && !answerScreen.isActionTimeout()) {
1458 LogUtil.d(
1459 "InCallActivity.showAnswerScreenFragment",
1460 "answer fragment exists for same call and has NOT been accepted/rejected/timed out");
Eric Erfanianccca3152017-02-22 16:32:36 -08001461 return false;
1462 }
Eric Erfanian2ca43182017-08-31 06:57:16 -07001463 if (answerScreen.isActionTimeout()) {
1464 LogUtil.i(
1465 "InCallActivity.showAnswerScreenFragment",
1466 "answer fragment exists but has been accepted/rejected and timed out");
1467 } else {
1468 LogUtil.i(
1469 "InCallActivity.showAnswerScreenFragment",
1470 "answer fragment exists but arguments do not match");
1471 }
Eric Erfanianccca3152017-02-22 16:32:36 -08001472 hideAnswerScreenFragment(transaction);
1473 }
1474
1475 // Show a new answer screen.
1476 AnswerScreen answerScreen =
Eric Erfanianfc37b022017-03-21 10:11:17 -07001477 AnswerBindings.createAnswerScreen(
1478 call.getId(),
wangqif6be6172018-03-30 15:57:56 -07001479 call.isActiveRttCall(),
Eric Erfanianfc37b022017-03-21 10:11:17 -07001480 call.isVideoCall(),
1481 isVideoUpgradeRequest,
Eric Erfanian90508232017-03-24 09:31:16 -07001482 call.getVideoTech().isSelfManagedCamera(),
1483 shouldAllowAnswerAndRelease(call),
erfaniand05d8992018-03-20 19:42:26 -07001484 CallList.getInstance().getBackgroundCall() != null,
erfanian89e3d1b2018-05-02 18:50:59 -07001485 getSpeakEasyCallManager().isAvailable(getApplicationContext())
1486 && call.isSpeakEasyEligible());
linyuhc3968e62017-11-20 17:40:50 -08001487 transaction.add(R.id.main, answerScreen.getAnswerScreenFragment(), Tags.ANSWER_SCREEN);
Eric Erfanianccca3152017-02-22 16:32:36 -08001488
1489 Logger.get(this).logScreenView(ScreenEvent.Type.INCOMING_CALL, this);
1490 didShowAnswerScreen = true;
1491 return true;
1492 }
1493
Eric Erfanian90508232017-03-24 09:31:16 -07001494 private boolean shouldAllowAnswerAndRelease(DialerCall call) {
1495 if (CallList.getInstance().getActiveCall() == null) {
1496 LogUtil.i("InCallActivity.shouldAllowAnswerAndRelease", "no active call");
1497 return false;
1498 }
1499 if (getSystemService(TelephonyManager.class).getPhoneType()
1500 == TelephonyManager.PHONE_TYPE_CDMA) {
1501 LogUtil.i("InCallActivity.shouldAllowAnswerAndRelease", "PHONE_TYPE_CDMA not supported");
1502 return false;
1503 }
1504 if (call.isVideoCall() || call.hasReceivedVideoUpgradeRequest()) {
1505 LogUtil.i("InCallActivity.shouldAllowAnswerAndRelease", "video call");
1506 return false;
1507 }
linyuhc3968e62017-11-20 17:40:50 -08001508 if (!ConfigProviderBindings.get(this)
1509 .getBoolean(ConfigNames.ANSWER_AND_RELEASE_ENABLED, true)) {
Eric Erfanian90508232017-03-24 09:31:16 -07001510 LogUtil.i("InCallActivity.shouldAllowAnswerAndRelease", "disabled by config");
1511 return false;
1512 }
1513
1514 return true;
1515 }
1516
Eric Erfanianccca3152017-02-22 16:32:36 -08001517 private boolean hideAnswerScreenFragment(FragmentTransaction transaction) {
1518 if (!didShowAnswerScreen) {
1519 return false;
1520 }
1521 AnswerScreen answerScreen = getAnswerScreen();
1522 if (answerScreen != null) {
1523 transaction.remove(answerScreen.getAnswerScreenFragment());
1524 }
1525
1526 didShowAnswerScreen = false;
1527 return true;
1528 }
1529
1530 private boolean showInCallScreenFragment(FragmentTransaction transaction) {
1531 if (didShowInCallScreen) {
1532 return false;
1533 }
Eric Erfanian2ca43182017-08-31 06:57:16 -07001534 InCallScreen inCallScreen = InCallBindings.createInCallScreen();
linyuhc3968e62017-11-20 17:40:50 -08001535 transaction.add(R.id.main, inCallScreen.getInCallScreenFragment(), Tags.IN_CALL_SCREEN);
Eric Erfanianccca3152017-02-22 16:32:36 -08001536 Logger.get(this).logScreenView(ScreenEvent.Type.INCALL, this);
1537 didShowInCallScreen = true;
1538 return true;
1539 }
1540
1541 private boolean hideInCallScreenFragment(FragmentTransaction transaction) {
1542 if (!didShowInCallScreen) {
1543 return false;
1544 }
1545 InCallScreen inCallScreen = getInCallScreen();
1546 if (inCallScreen != null) {
Eric Erfanian2ca43182017-08-31 06:57:16 -07001547 transaction.remove(inCallScreen.getInCallScreenFragment());
Eric Erfanianccca3152017-02-22 16:32:36 -08001548 }
1549 didShowInCallScreen = false;
1550 return true;
1551 }
1552
wangqi219b8702018-02-13 09:34:41 -08001553 private boolean showRttCallScreenFragment(FragmentTransaction transaction, DialerCall call) {
1554 if (didShowRttCallScreen) {
1555 // This shouldn't happen since only one RTT call is allow at same time.
1556 if (!getRttCallScreen().getCallId().equals(call.getId())) {
1557 LogUtil.e("InCallActivity.showRttCallScreenFragment", "RTT call id doesn't match");
1558 }
1559 return false;
1560 }
1561 RttCallScreen rttCallScreen = RttBindings.createRttCallScreen(call.getId());
1562 transaction.add(R.id.main, rttCallScreen.getRttCallScreenFragment(), Tags.RTT_CALL_SCREEN);
1563 Logger.get(this).logScreenView(ScreenEvent.Type.INCALL, this);
1564 didShowRttCallScreen = true;
1565 return true;
1566 }
1567
1568 private boolean hideRttCallScreenFragment(FragmentTransaction transaction) {
1569 if (!didShowRttCallScreen) {
1570 return false;
1571 }
1572 RttCallScreen rttCallScreen = getRttCallScreen();
1573 if (rttCallScreen != null) {
1574 transaction.remove(rttCallScreen.getRttCallScreenFragment());
1575 }
1576 didShowRttCallScreen = false;
1577 return true;
1578 }
1579
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001580 private boolean showVideoCallScreenFragment(FragmentTransaction transaction, DialerCall call) {
Eric Erfanianccca3152017-02-22 16:32:36 -08001581 if (didShowVideoCallScreen) {
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001582 VideoCallScreen videoCallScreen = getVideoCallScreen();
1583 if (videoCallScreen.getCallId().equals(call.getId())) {
1584 return false;
1585 }
1586 LogUtil.i(
1587 "InCallActivity.showVideoCallScreenFragment",
1588 "video call fragment exists but arguments do not match");
1589 hideVideoCallScreenFragment(transaction);
Eric Erfanianccca3152017-02-22 16:32:36 -08001590 }
1591
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001592 LogUtil.i("InCallActivity.showVideoCallScreenFragment", "call: %s", call);
1593
Eric Erfanian90508232017-03-24 09:31:16 -07001594 VideoCallScreen videoCallScreen =
1595 VideoBindings.createVideoCallScreen(
1596 call.getId(), call.getVideoTech().shouldUseSurfaceView());
linyuhc3968e62017-11-20 17:40:50 -08001597 transaction.add(
1598 R.id.main, videoCallScreen.getVideoCallScreenFragment(), Tags.VIDEO_CALL_SCREEN);
Eric Erfanianccca3152017-02-22 16:32:36 -08001599
1600 Logger.get(this).logScreenView(ScreenEvent.Type.INCALL, this);
1601 didShowVideoCallScreen = true;
1602 return true;
1603 }
1604
1605 private boolean hideVideoCallScreenFragment(FragmentTransaction transaction) {
1606 if (!didShowVideoCallScreen) {
1607 return false;
1608 }
1609 VideoCallScreen videoCallScreen = getVideoCallScreen();
1610 if (videoCallScreen != null) {
1611 transaction.remove(videoCallScreen.getVideoCallScreenFragment());
1612 }
1613 didShowVideoCallScreen = false;
1614 return true;
1615 }
1616
linyuhc3968e62017-11-20 17:40:50 -08001617 private AnswerScreen getAnswerScreen() {
1618 return (AnswerScreen) getSupportFragmentManager().findFragmentByTag(Tags.ANSWER_SCREEN);
Eric Erfanianccca3152017-02-22 16:32:36 -08001619 }
1620
linyuhc3968e62017-11-20 17:40:50 -08001621 private InCallScreen getInCallScreen() {
1622 return (InCallScreen) getSupportFragmentManager().findFragmentByTag(Tags.IN_CALL_SCREEN);
Eric Erfanianccca3152017-02-22 16:32:36 -08001623 }
1624
linyuhc3968e62017-11-20 17:40:50 -08001625 private VideoCallScreen getVideoCallScreen() {
1626 return (VideoCallScreen) getSupportFragmentManager().findFragmentByTag(Tags.VIDEO_CALL_SCREEN);
Eric Erfanianccca3152017-02-22 16:32:36 -08001627 }
1628
wangqi219b8702018-02-13 09:34:41 -08001629 private RttCallScreen getRttCallScreen() {
1630 return (RttCallScreen) getSupportFragmentManager().findFragmentByTag(Tags.RTT_CALL_SCREEN);
1631 }
1632
wangqifd4c9f72018-03-08 18:21:50 -08001633 private InCallScreen getInCallOrRttCallScreen() {
1634 InCallScreen inCallScreen = null;
1635 if (didShowInCallScreen) {
1636 inCallScreen = getInCallScreen();
1637 }
1638 if (didShowRttCallScreen) {
1639 inCallScreen = getRttCallScreen();
1640 }
1641 return inCallScreen;
1642 }
1643
Eric Erfanianccca3152017-02-22 16:32:36 -08001644 @Override
1645 public void onPseudoScreenStateChanged(boolean isOn) {
1646 LogUtil.i("InCallActivity.onPseudoScreenStateChanged", "isOn: " + isOn);
1647 pseudoBlackScreenOverlay.setVisibility(isOn ? View.GONE : View.VISIBLE);
1648 }
1649
1650 /**
1651 * For some touch related issue, turning off the screen can be faked by drawing a black view over
1652 * the activity. All touch events started when the screen is "off" is rejected.
1653 *
1654 * @see PseudoScreenState
1655 */
1656 @Override
1657 public boolean dispatchTouchEvent(MotionEvent event) {
1658 // Reject any gesture that started when the screen is in the fake off state.
1659 if (touchDownWhenPseudoScreenOff) {
1660 if (event.getAction() == MotionEvent.ACTION_UP) {
1661 touchDownWhenPseudoScreenOff = false;
1662 }
1663 return true;
1664 }
1665 // Reject all touch event when the screen is in the fake off state.
1666 if (!InCallPresenter.getInstance().getPseudoScreenState().isOn()) {
1667 if (event.getAction() == MotionEvent.ACTION_DOWN) {
1668 touchDownWhenPseudoScreenOff = true;
1669 LogUtil.i("InCallActivity.dispatchTouchEvent", "touchDownWhenPseudoScreenOff");
1670 }
1671 return true;
1672 }
1673 return super.dispatchTouchEvent(event);
1674 }
1675
wangqi219b8702018-02-13 09:34:41 -08001676 @Override
1677 public RttCallScreenDelegate newRttCallScreenDelegate(RttCallScreen videoCallScreen) {
1678 return new RttCallPresenter();
1679 }
1680
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001681 private static class ShouldShowUiResult {
Eric Erfanianccca3152017-02-22 16:32:36 -08001682 public final boolean shouldShow;
1683 public final DialerCall call;
1684
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001685 ShouldShowUiResult(boolean shouldShow, DialerCall call) {
Eric Erfanianccca3152017-02-22 16:32:36 -08001686 this.shouldShow = shouldShow;
1687 this.call = call;
1688 }
1689 }
linyuhc3968e62017-11-20 17:40:50 -08001690
1691 private static final class IntentExtraNames {
1692 static final String FOR_FULL_SCREEN = "InCallActivity.for_full_screen_intent";
1693 static final String NEW_OUTGOING_CALL = "InCallActivity.new_outgoing_call";
1694 static final String SHOW_DIALPAD = "InCallActivity.show_dialpad";
1695 }
1696
1697 private static final class KeysForSavedInstance {
1698 static final String DIALPAD_TEXT = "InCallActivity.dialpad_text";
1699 static final String DID_SHOW_ANSWER_SCREEN = "did_show_answer_screen";
1700 static final String DID_SHOW_IN_CALL_SCREEN = "did_show_in_call_screen";
1701 static final String DID_SHOW_VIDEO_CALL_SCREEN = "did_show_video_call_screen";
wangqi153af2f2018-02-15 16:21:49 -08001702 static final String DID_SHOW_RTT_CALL_SCREEN = "did_show_rtt_call_screen";
erfaniand05d8992018-03-20 19:42:26 -07001703 static final String DID_SHOW_SPEAK_EASY_SCREEN = "did_show_speak_easy_screen";
linyuhc3968e62017-11-20 17:40:50 -08001704 }
1705
1706 /** Request codes for pending intents. */
1707 public static final class PendingIntentRequestCodes {
1708 static final int NON_FULL_SCREEN = 0;
1709 static final int FULL_SCREEN = 1;
1710 static final int BUBBLE = 2;
1711 }
1712
1713 private static final class Tags {
1714 static final String ANSWER_SCREEN = "tag_answer_screen";
1715 static final String DIALPAD_FRAGMENT = "tag_dialpad_fragment";
1716 static final String IN_CALL_SCREEN = "tag_in_call_screen";
1717 static final String INTERNATIONAL_CALL_ON_WIFI = "tag_international_call_on_wifi";
1718 static final String SELECT_ACCOUNT_FRAGMENT = "tag_select_account_fragment";
1719 static final String VIDEO_CALL_SCREEN = "tag_video_call_screen";
wangqi219b8702018-02-13 09:34:41 -08001720 static final String RTT_CALL_SCREEN = "tag_rtt_call_screen";
linyuhc3968e62017-11-20 17:40:50 -08001721 static final String POST_CHAR_DIALOG_FRAGMENT = "tag_post_char_dialog_fragment";
erfaniand05d8992018-03-20 19:42:26 -07001722 static final String SPEAK_EASY_SCREEN = "tag_speak_easy_screen";
wangqibc28ea72018-04-02 16:23:00 -07001723 static final String RTT_REQUEST_DIALOG = "tag_rtt_request_dialog";
linyuhc3968e62017-11-20 17:40:50 -08001724 }
1725
1726 private static final class ConfigNames {
1727 static final String ANSWER_AND_RELEASE_ENABLED = "answer_and_release_enabled";
1728 }
1729
linyuhc3968e62017-11-20 17:40:50 -08001730 private static final class SelectPhoneAccountListener
1731 extends SelectPhoneAccountDialogFragment.SelectPhoneAccountListener {
1732 private static final String TAG = SelectPhoneAccountListener.class.getCanonicalName();
1733
twyen73a74c32018-03-07 12:12:24 -08001734 private final Context appContext;
1735
1736 SelectPhoneAccountListener(Context appContext) {
1737 this.appContext = appContext;
1738 }
1739
linyuhc3968e62017-11-20 17:40:50 -08001740 @Override
1741 public void onPhoneAccountSelected(
1742 PhoneAccountHandle selectedAccountHandle, boolean setDefault, String callId) {
1743 DialerCall call = CallList.getInstance().getCallById(callId);
1744 LogUtil.i(TAG, "Phone account select with call:\n%s", call);
1745
1746 if (call != null) {
twyen73a74c32018-03-07 12:12:24 -08001747 call.phoneAccountSelected(selectedAccountHandle, false);
1748 if (call.getPreferredAccountRecorder() != null) {
1749 call.getPreferredAccountRecorder().record(appContext, selectedAccountHandle, setDefault);
1750 }
linyuhc3968e62017-11-20 17:40:50 -08001751 }
1752 }
1753
1754 @Override
1755 public void onDialogDismissed(String callId) {
1756 DialerCall call = CallList.getInstance().getCallById(callId);
1757 LogUtil.i(TAG, "Disconnecting call:\n%s" + call);
1758
1759 if (call != null) {
1760 call.disconnect();
1761 }
1762 }
1763 }
Eric Erfanianccca3152017-02-22 16:32:36 -08001764}