blob: ed10ed0bbf07e53644ebc380310999ce78bdeba3 [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
linyuh7b86f562017-11-16 11:24:09 -080019import android.app.AlertDialog;
linyuhf99f6302017-11-15 11:23:51 -080020import android.app.Dialog;
Eric Erfanianccca3152017-02-22 16:32:36 -080021import android.content.Context;
22import android.content.Intent;
23import android.graphics.drawable.GradientDrawable;
24import android.graphics.drawable.GradientDrawable.Orientation;
25import android.os.Bundle;
Eric Erfanian2ca43182017-08-31 06:57:16 -070026import android.os.Trace;
Eric Erfanianccca3152017-02-22 16:32:36 -080027import android.support.annotation.ColorInt;
28import android.support.annotation.FloatRange;
Eric Erfanianc857f902017-05-15 14:05:33 -070029import android.support.annotation.NonNull;
Eric Erfanianccca3152017-02-22 16:32:36 -080030import android.support.annotation.Nullable;
31import android.support.v4.app.FragmentManager;
32import android.support.v4.app.FragmentTransaction;
33import android.support.v4.graphics.ColorUtils;
Eric Erfanian90508232017-03-24 09:31:16 -070034import android.telephony.TelephonyManager;
Eric Erfanianccca3152017-02-22 16:32:36 -080035import android.view.KeyEvent;
36import android.view.MenuItem;
37import android.view.MotionEvent;
38import android.view.View;
linyuh9c327da2017-11-14 12:33:48 -080039import android.view.WindowManager;
linyuh7b86f562017-11-16 11:24:09 -080040import android.widget.CheckBox;
41import android.widget.Toast;
linyuhf99f6302017-11-15 11:23:51 -080042import com.android.contacts.common.widget.SelectPhoneAccountDialogFragment;
Eric Erfaniand5e47f62017-03-15 14:41:07 -070043import com.android.dialer.common.Assert;
Eric Erfanianccca3152017-02-22 16:32:36 -080044import com.android.dialer.common.LogUtil;
weijiaxu650e7cc2017-10-31 12:38:54 -070045import com.android.dialer.common.concurrent.ThreadUtil;
Eric Erfanianccca3152017-02-22 16:32:36 -080046import com.android.dialer.compat.ActivityCompat;
Eric Erfanian2ca43182017-08-31 06:57:16 -070047import com.android.dialer.configprovider.ConfigProviderBindings;
48import com.android.dialer.logging.DialerImpression;
Eric Erfanianccca3152017-02-22 16:32:36 -080049import com.android.dialer.logging.Logger;
weijiaxu94df7202017-10-25 18:21:41 -070050import com.android.dialer.logging.LoggingBindings;
Eric Erfanian8369df02017-05-03 10:27:13 -070051import com.android.dialer.logging.ScreenEvent;
Eric Erfanianccca3152017-02-22 16:32:36 -080052import com.android.incallui.answer.bindings.AnswerBindings;
53import com.android.incallui.answer.protocol.AnswerScreen;
54import com.android.incallui.answer.protocol.AnswerScreenDelegate;
55import com.android.incallui.answer.protocol.AnswerScreenDelegateFactory;
56import com.android.incallui.answerproximitysensor.PseudoScreenState;
57import com.android.incallui.call.CallList;
58import com.android.incallui.call.DialerCall;
59import com.android.incallui.call.DialerCall.State;
Eric Erfanian2ca43182017-08-31 06:57:16 -070060import com.android.incallui.callpending.CallPendingActivity;
61import com.android.incallui.disconnectdialog.DisconnectMessage;
Eric Erfanianccca3152017-02-22 16:32:36 -080062import com.android.incallui.incall.bindings.InCallBindings;
63import com.android.incallui.incall.protocol.InCallButtonUiDelegate;
64import com.android.incallui.incall.protocol.InCallButtonUiDelegateFactory;
65import com.android.incallui.incall.protocol.InCallScreen;
66import com.android.incallui.incall.protocol.InCallScreenDelegate;
67import com.android.incallui.incall.protocol.InCallScreenDelegateFactory;
linyuh7b86f562017-11-16 11:24:09 -080068import com.android.incallui.incalluilock.InCallUiLock;
linyuhf99f6302017-11-15 11:23:51 -080069import com.android.incallui.telecomeventui.InternationalCallOnWifiDialogFragment;
Eric Erfanianccca3152017-02-22 16:32:36 -080070import com.android.incallui.video.bindings.VideoBindings;
71import com.android.incallui.video.protocol.VideoCallScreen;
72import com.android.incallui.video.protocol.VideoCallScreenDelegate;
73import com.android.incallui.video.protocol.VideoCallScreenDelegateFactory;
74
75/** Version of {@link InCallActivity} that shows the new UI */
76public class InCallActivity extends TransactionSafeFragmentActivity
77 implements AnswerScreenDelegateFactory,
78 InCallScreenDelegateFactory,
79 InCallButtonUiDelegateFactory,
80 VideoCallScreenDelegateFactory,
81 PseudoScreenState.StateChangedListener {
82
Eric Erfanian2ca43182017-08-31 06:57:16 -070083 public static final int PENDING_INTENT_REQUEST_CODE_NON_FULL_SCREEN = 0;
84 public static final int PENDING_INTENT_REQUEST_CODE_FULL_SCREEN = 1;
85 public static final int PENDING_INTENT_REQUEST_CODE_BUBBLE = 2;
86
Eric Erfanianccca3152017-02-22 16:32:36 -080087 private static final String TAG_ANSWER_SCREEN = "tag_answer_screen";
linyuh69a25062017-11-15 16:18:51 -080088 private static final String TAG_DIALPAD_FRAGMENT = "tag_dialpad_fragment";
linyuhf99f6302017-11-15 11:23:51 -080089 private static final String TAG_INTERNATIONAL_CALL_ON_WIFI = "tag_international_call_on_wifi";
90 private static final String TAG_IN_CALL_SCREEN = "tag_in_call_screen";
Eric Erfanianccca3152017-02-22 16:32:36 -080091 private static final String TAG_VIDEO_CALL_SCREEN = "tag_video_call_screen";
92
93 private static final String DID_SHOW_ANSWER_SCREEN_KEY = "did_show_answer_screen";
94 private static final String DID_SHOW_IN_CALL_SCREEN_KEY = "did_show_in_call_screen";
95 private static final String DID_SHOW_VIDEO_CALL_SCREEN_KEY = "did_show_video_call_screen";
96
Eric Erfanian90508232017-03-24 09:31:16 -070097 private static final String CONFIG_ANSWER_AND_RELEASE_ENABLED = "answer_and_release_enabled";
98
Eric Erfanianccca3152017-02-22 16:32:36 -080099 private final InCallActivityCommon common;
linyuh69a25062017-11-15 16:18:51 -0800100 private InCallOrientationEventListener inCallOrientationEventListener;
Eric Erfanianccca3152017-02-22 16:32:36 -0800101 private boolean didShowAnswerScreen;
102 private boolean didShowInCallScreen;
103 private boolean didShowVideoCallScreen;
linyuh9c327da2017-11-14 12:33:48 -0800104 private boolean dismissKeyguard;
Eric Erfanianccca3152017-02-22 16:32:36 -0800105 private int[] backgroundDrawableColors;
106 private GradientDrawable backgroundDrawable;
107 private boolean isVisible;
108 private View pseudoBlackScreenOverlay;
109 private boolean touchDownWhenPseudoScreenOff;
110 private boolean isInShowMainInCallFragment;
111 private boolean needDismissPendingDialogs;
wangqi9982f0d2017-10-11 17:46:07 -0700112 private boolean allowOrientationChange;
Eric Erfanianccca3152017-02-22 16:32:36 -0800113
114 public InCallActivity() {
115 common = new InCallActivityCommon(this);
116 }
117
118 public static Intent getIntent(
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700119 Context context, boolean showDialpad, boolean newOutgoingCall, boolean isForFullScreen) {
Eric Erfanianccca3152017-02-22 16:32:36 -0800120 Intent intent = new Intent(Intent.ACTION_MAIN, null);
121 intent.setFlags(Intent.FLAG_ACTIVITY_NO_USER_ACTION | Intent.FLAG_ACTIVITY_NEW_TASK);
122 intent.setClass(context, InCallActivity.class);
123 InCallActivityCommon.setIntentExtras(intent, showDialpad, newOutgoingCall, isForFullScreen);
124 return intent;
125 }
126
127 @Override
128 protected void onResumeFragments() {
129 super.onResumeFragments();
130 if (needDismissPendingDialogs) {
131 dismissPendingDialogs();
132 }
133 }
134
135 @Override
136 protected void onCreate(Bundle icicle) {
Eric Erfanian2ca43182017-08-31 06:57:16 -0700137 Trace.beginSection("InCallActivity.onCreate");
Eric Erfanianccca3152017-02-22 16:32:36 -0800138 LogUtil.i("InCallActivity.onCreate", "");
139 super.onCreate(icicle);
140
Eric Erfanian2ca43182017-08-31 06:57:16 -0700141 if (getIntent().getBooleanExtra(ReturnToCallController.RETURN_TO_CALL_EXTRA_KEY, false)) {
142 Logger.get(this).logImpression(DialerImpression.Type.BUBBLE_PRIMARY_BUTTON_RETURN_TO_CALL);
143 getIntent().removeExtra(ReturnToCallController.RETURN_TO_CALL_EXTRA_KEY);
144 }
145
Eric Erfanianccca3152017-02-22 16:32:36 -0800146 if (icicle != null) {
147 didShowAnswerScreen = icicle.getBoolean(DID_SHOW_ANSWER_SCREEN_KEY);
148 didShowInCallScreen = icicle.getBoolean(DID_SHOW_IN_CALL_SCREEN_KEY);
149 didShowVideoCallScreen = icicle.getBoolean(DID_SHOW_VIDEO_CALL_SCREEN_KEY);
150 }
151
152 common.onCreate(icicle);
linyuh69a25062017-11-15 16:18:51 -0800153 inCallOrientationEventListener = new InCallOrientationEventListener(this);
Eric Erfanianccca3152017-02-22 16:32:36 -0800154
155 getWindow()
156 .getDecorView()
157 .setSystemUiVisibility(
158 View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
159
160 pseudoBlackScreenOverlay = findViewById(R.id.psuedo_black_screen_overlay);
Eric Erfanian2ca43182017-08-31 06:57:16 -0700161 sendBroadcast(CallPendingActivity.getFinishBroadcast());
162 Trace.endSection();
weijiaxuc950a9b2017-11-06 16:39:04 -0800163 Logger.get(this)
164 .logStopLatencyTimer(LoggingBindings.ON_CALL_ADDED_TO_ON_INCALL_UI_SHOWN_INCOMING);
165 Logger.get(this)
166 .logStopLatencyTimer(LoggingBindings.ON_CALL_ADDED_TO_ON_INCALL_UI_SHOWN_OUTGOING);
Eric Erfanianccca3152017-02-22 16:32:36 -0800167 }
168
169 @Override
170 protected void onSaveInstanceState(Bundle out) {
171 LogUtil.i("InCallActivity.onSaveInstanceState", "");
172 common.onSaveInstanceState(out);
173 out.putBoolean(DID_SHOW_ANSWER_SCREEN_KEY, didShowAnswerScreen);
174 out.putBoolean(DID_SHOW_IN_CALL_SCREEN_KEY, didShowInCallScreen);
175 out.putBoolean(DID_SHOW_VIDEO_CALL_SCREEN_KEY, didShowVideoCallScreen);
176 super.onSaveInstanceState(out);
177 isVisible = false;
178 }
179
180 @Override
181 protected void onStart() {
Eric Erfanian2ca43182017-08-31 06:57:16 -0700182 Trace.beginSection("InCallActivity.onStart");
Eric Erfanianccca3152017-02-22 16:32:36 -0800183 LogUtil.i("InCallActivity.onStart", "");
wangqi9982f0d2017-10-11 17:46:07 -0700184 Trace.beginSection("call super");
Eric Erfanianccca3152017-02-22 16:32:36 -0800185 super.onStart();
wangqi9982f0d2017-10-11 17:46:07 -0700186 Trace.endSection();
Eric Erfanianccca3152017-02-22 16:32:36 -0800187 isVisible = true;
188 showMainInCallFragment();
189 common.onStart();
190 if (ActivityCompat.isInMultiWindowMode(this)
191 && !getResources().getBoolean(R.bool.incall_dialpad_allowed)) {
192 // Hide the dialpad because there may not be enough room
193 showDialpadFragment(false, false);
194 }
Eric Erfanian2ca43182017-08-31 06:57:16 -0700195 Trace.endSection();
Eric Erfanianccca3152017-02-22 16:32:36 -0800196 }
197
198 @Override
199 protected void onResume() {
Eric Erfanian2ca43182017-08-31 06:57:16 -0700200 Trace.beginSection("InCallActivity.onResume");
Eric Erfanianccca3152017-02-22 16:32:36 -0800201 LogUtil.i("InCallActivity.onResume", "");
202 super.onResume();
203 common.onResume();
204 PseudoScreenState pseudoScreenState = InCallPresenter.getInstance().getPseudoScreenState();
205 pseudoScreenState.addListener(this);
206 onPseudoScreenStateChanged(pseudoScreenState.isOn());
Eric Erfanian2ca43182017-08-31 06:57:16 -0700207 Trace.endSection();
weijiaxu650e7cc2017-10-31 12:38:54 -0700208 // add 1 sec delay to get memory snapshot so that dialer wont react slowly on resume.
209 ThreadUtil.postDelayedOnUiThread(
weijiaxuc950a9b2017-11-06 16:39:04 -0800210 () ->
211 Logger.get(this)
212 .logRecordMemory(LoggingBindings.INCALL_ACTIVITY_ON_RESUME_MEMORY_EVENT_NAME),
weijiaxu650e7cc2017-10-31 12:38:54 -0700213 1000);
Eric Erfanianccca3152017-02-22 16:32:36 -0800214 }
215
216 /** onPause is guaranteed to be called when the InCallActivity goes in the background. */
217 @Override
218 protected void onPause() {
Eric Erfanian2ca43182017-08-31 06:57:16 -0700219 Trace.beginSection("InCallActivity.onPause");
Eric Erfanianccca3152017-02-22 16:32:36 -0800220 LogUtil.i("InCallActivity.onPause", "");
221 super.onPause();
222 common.onPause();
223 InCallPresenter.getInstance().getPseudoScreenState().removeListener(this);
Eric Erfanian2ca43182017-08-31 06:57:16 -0700224 Trace.endSection();
Eric Erfanianccca3152017-02-22 16:32:36 -0800225 }
226
227 @Override
228 protected void onStop() {
Eric Erfanian2ca43182017-08-31 06:57:16 -0700229 Trace.beginSection("InCallActivity.onStop");
Eric Erfanianccca3152017-02-22 16:32:36 -0800230 LogUtil.i("InCallActivity.onStop", "");
wangqi4d705e52017-09-28 12:23:35 -0700231 isVisible = false;
Eric Erfanianccca3152017-02-22 16:32:36 -0800232 super.onStop();
233 common.onStop();
Eric Erfanian2ca43182017-08-31 06:57:16 -0700234 Trace.endSection();
Eric Erfanianccca3152017-02-22 16:32:36 -0800235 }
236
237 @Override
238 protected void onDestroy() {
Eric Erfanian2ca43182017-08-31 06:57:16 -0700239 Trace.beginSection("InCallActivity.onDestroy");
Eric Erfanianccca3152017-02-22 16:32:36 -0800240 LogUtil.i("InCallActivity.onDestroy", "");
241 super.onDestroy();
242 common.onDestroy();
Eric Erfanian2ca43182017-08-31 06:57:16 -0700243 Trace.endSection();
Eric Erfanianccca3152017-02-22 16:32:36 -0800244 }
245
246 @Override
247 public void finish() {
248 if (shouldCloseActivityOnFinish()) {
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700249 // When user select incall ui from recents after the call is disconnected, it tries to launch
250 // a new InCallActivity but InCallPresenter is already teared down at this point, which causes
251 // crash.
252 // By calling finishAndRemoveTask() instead of finish() the task associated with
253 // InCallActivity is cleared completely. So system won't try to create a new InCallActivity in
254 // this case.
255 //
256 // Calling finish won't clear the task and normally when an activity finishes it shouldn't
257 // clear the task since there could be parent activity in the same task that's still alive.
258 // But InCallActivity is special since it's singleInstance which means it's root activity and
259 // only instance of activity in the task. So it should be safe to also remove task when
260 // finishing.
261 // It's also necessary in the sense of it's excluded from recents. So whenever the activity
262 // finishes, the task should also be removed since it doesn't make sense to go back to it in
263 // anyway anymore.
264 super.finishAndRemoveTask();
Eric Erfanianccca3152017-02-22 16:32:36 -0800265 }
266 }
267
268 private boolean shouldCloseActivityOnFinish() {
269 if (!isVisible()) {
270 LogUtil.i(
271 "InCallActivity.shouldCloseActivityOnFinish",
272 "allowing activity to be closed because it's not visible");
273 return true;
274 }
275
twyen8efb4952017-10-06 16:35:54 -0700276 if (InCallPresenter.getInstance().isInCallUiLocked()) {
Eric Erfanianccca3152017-02-22 16:32:36 -0800277 LogUtil.i(
278 "InCallActivity.shouldCloseActivityOnFinish",
twyen8efb4952017-10-06 16:35:54 -0700279 "in call ui is locked, not closing activity");
Eric Erfanianccca3152017-02-22 16:32:36 -0800280 return false;
281 }
282
283 LogUtil.i(
284 "InCallActivity.shouldCloseActivityOnFinish",
twyen8efb4952017-10-06 16:35:54 -0700285 "activity is visible and has no locks, allowing activity to close");
Eric Erfanianccca3152017-02-22 16:32:36 -0800286 return true;
287 }
288
289 @Override
290 protected void onNewIntent(Intent intent) {
291 LogUtil.i("InCallActivity.onNewIntent", "");
Eric Erfanianccca3152017-02-22 16:32:36 -0800292
293 // If the screen is off, we need to make sure it gets turned on for incoming calls.
294 // This normally works just fine thanks to FLAG_TURN_SCREEN_ON but that only works
295 // when the activity is first created. Therefore, to ensure the screen is turned on
296 // for the call waiting case, we recreate() the current activity. There should be no jank from
297 // this since the screen is already off and will remain so until our new activity is up.
298 if (!isVisible()) {
Eric Erfanian10b34a52017-05-04 08:23:17 -0700299 common.onNewIntent(intent, true /* isRecreating */);
Eric Erfanianccca3152017-02-22 16:32:36 -0800300 LogUtil.i("InCallActivity.onNewIntent", "Restarting InCallActivity to force screen on.");
301 recreate();
Eric Erfanian10b34a52017-05-04 08:23:17 -0700302 } else {
303 common.onNewIntent(intent, false /* isRecreating */);
Eric Erfanianccca3152017-02-22 16:32:36 -0800304 }
305 }
306
307 @Override
308 public void onBackPressed() {
309 LogUtil.i("InCallActivity.onBackPressed", "");
310 if (!common.onBackPressed(didShowInCallScreen || didShowVideoCallScreen)) {
311 super.onBackPressed();
312 }
313 }
314
315 @Override
316 public boolean onOptionsItemSelected(MenuItem item) {
317 LogUtil.i("InCallActivity.onOptionsItemSelected", "item: " + item);
318 if (item.getItemId() == android.R.id.home) {
319 onBackPressed();
320 return true;
321 }
322 return super.onOptionsItemSelected(item);
323 }
324
325 @Override
326 public boolean onKeyUp(int keyCode, KeyEvent event) {
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700327 return common.onKeyUp(keyCode, event) || super.onKeyUp(keyCode, event);
Eric Erfanianccca3152017-02-22 16:32:36 -0800328 }
329
330 @Override
331 public boolean onKeyDown(int keyCode, KeyEvent event) {
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700332 return common.onKeyDown(keyCode, event) || super.onKeyDown(keyCode, event);
Eric Erfanianccca3152017-02-22 16:32:36 -0800333 }
334
335 public boolean isInCallScreenAnimating() {
336 return false;
337 }
338
339 public void showConferenceFragment(boolean show) {
340 if (show) {
341 startActivity(new Intent(this, ManageConferenceActivity.class));
342 }
343 }
344
345 public boolean showDialpadFragment(boolean show, boolean animate) {
346 boolean didChange = common.showDialpadFragment(show, animate);
347 if (didChange) {
348 // Note: onInCallScreenDialpadVisibilityChange is called here to ensure that the dialpad FAB
349 // repositions itself.
350 getInCallScreen().onInCallScreenDialpadVisibilityChange(show);
351 }
352 return didChange;
353 }
354
355 public boolean isDialpadVisible() {
linyuh69a25062017-11-15 16:18:51 -0800356 DialpadFragment dialpadFragment = getDialpadFragment();
357 return dialpadFragment != null && dialpadFragment.isVisible();
358 }
359
360 /**
361 * Returns the {@link DialpadFragment} that's shown by this activity, or {@code null}
362 * TODO(a bug): Make this method private after InCallActivityCommon is deleted.
363 */
364 @Nullable
365 DialpadFragment getDialpadFragment() {
366 FragmentManager fragmentManager = getDialpadFragmentManager();
367 if (fragmentManager == null) {
368 return null;
369 }
370 return (DialpadFragment) fragmentManager.findFragmentByTag(TAG_DIALPAD_FRAGMENT);
Eric Erfanianccca3152017-02-22 16:32:36 -0800371 }
372
373 public void onForegroundCallChanged(DialerCall newForegroundCall) {
374 common.updateTaskDescription();
375 if (didShowAnswerScreen && newForegroundCall != null) {
376 if (newForegroundCall.getState() == State.DISCONNECTED
377 || newForegroundCall.getState() == State.IDLE) {
378 LogUtil.i(
379 "InCallActivity.onForegroundCallChanged",
380 "rejecting incoming call, not updating " + "window background color");
381 }
382 } else {
383 LogUtil.v("InCallActivity.onForegroundCallChanged", "resetting background color");
384 updateWindowBackgroundColor(0);
385 }
386 }
387
388 public void updateWindowBackgroundColor(@FloatRange(from = -1f, to = 1.0f) float progress) {
389 ThemeColorManager themeColorManager = InCallPresenter.getInstance().getThemeColorManager();
390 @ColorInt int top;
391 @ColorInt int middle;
392 @ColorInt int bottom;
393 @ColorInt int gray = 0x66000000;
394
395 if (ActivityCompat.isInMultiWindowMode(this)) {
396 top = themeColorManager.getBackgroundColorSolid();
397 middle = themeColorManager.getBackgroundColorSolid();
398 bottom = themeColorManager.getBackgroundColorSolid();
399 } else {
400 top = themeColorManager.getBackgroundColorTop();
401 middle = themeColorManager.getBackgroundColorMiddle();
402 bottom = themeColorManager.getBackgroundColorBottom();
403 }
404
405 if (progress < 0) {
406 float correctedProgress = Math.abs(progress);
407 top = ColorUtils.blendARGB(top, gray, correctedProgress);
408 middle = ColorUtils.blendARGB(middle, gray, correctedProgress);
409 bottom = ColorUtils.blendARGB(bottom, gray, correctedProgress);
410 }
411
412 boolean backgroundDirty = false;
413 if (backgroundDrawable == null) {
414 backgroundDrawableColors = new int[] {top, middle, bottom};
415 backgroundDrawable = new GradientDrawable(Orientation.TOP_BOTTOM, backgroundDrawableColors);
416 backgroundDirty = true;
417 } else {
418 if (backgroundDrawableColors[0] != top) {
419 backgroundDrawableColors[0] = top;
420 backgroundDirty = true;
421 }
422 if (backgroundDrawableColors[1] != middle) {
423 backgroundDrawableColors[1] = middle;
424 backgroundDirty = true;
425 }
426 if (backgroundDrawableColors[2] != bottom) {
427 backgroundDrawableColors[2] = bottom;
428 backgroundDirty = true;
429 }
430 if (backgroundDirty) {
431 backgroundDrawable.setColors(backgroundDrawableColors);
432 }
433 }
434
435 if (backgroundDirty) {
436 getWindow().setBackgroundDrawable(backgroundDrawable);
437 }
438 }
439
440 public boolean isVisible() {
441 return isVisible;
442 }
443
444 public boolean getCallCardFragmentVisible() {
445 return didShowInCallScreen || didShowVideoCallScreen;
446 }
447
448 public void dismissKeyguard(boolean dismiss) {
linyuh9c327da2017-11-14 12:33:48 -0800449 if (dismissKeyguard == dismiss) {
450 return;
451 }
452
453 dismissKeyguard = dismiss;
454 if (dismiss) {
455 getWindow().addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);
456 } else {
457 getWindow().clearFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);
458 }
Eric Erfanianccca3152017-02-22 16:32:36 -0800459 }
460
461 public void showPostCharWaitDialog(String callId, String chars) {
462 common.showPostCharWaitDialog(callId, chars);
463 }
464
linyuh7b86f562017-11-16 11:24:09 -0800465 public void showDialogOrToastForDisconnectedCall(DisconnectMessage disconnectMessage) {
466 LogUtil.i(
467 "InCallActivity.showDialogOrToastForDisconnectedCall",
468 "disconnect cause: %s",
469 disconnectMessage);
470
471 if (disconnectMessage.dialog == null || isFinishing()) {
472 return;
473 }
474
475 dismissPendingDialogs();
476
477 // Show a toast if the app is in background when a dialog can't be visible.
478 if (!isVisible()) {
479 Toast.makeText(getApplicationContext(), disconnectMessage.toastMessage, Toast.LENGTH_LONG)
480 .show();
481 return;
482 }
483
484 // Show the dialog.
485 common.setErrorDialog(disconnectMessage.dialog);
486 InCallUiLock lock = InCallPresenter.getInstance().acquireInCallUiLock("showErrorDialog");
487 disconnectMessage.dialog.setOnDismissListener(
488 dialogInterface -> {
489 lock.release();
490 onDialogDismissed();
491 });
492 disconnectMessage.dialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
493 disconnectMessage.dialog.show();
494 }
495
496 private void onDialogDismissed() {
497 common.setErrorDialog(null);
498 CallList.getInstance().onErrorDialogDismissed();
Eric Erfanianccca3152017-02-22 16:32:36 -0800499 }
500
501 public void dismissPendingDialogs() {
linyuhf99f6302017-11-15 11:23:51 -0800502 LogUtil.i("InCallActivity.dismissPendingDialogs", "");
503
504 if (!isVisible) {
505 // Defer the dismissing action as the activity is not visible and onSaveInstanceState may have
506 // been called.
Eric Erfanianccca3152017-02-22 16:32:36 -0800507 LogUtil.i(
508 "InCallActivity.dismissPendingDialogs", "defer actions since activity is not visible");
509 needDismissPendingDialogs = true;
linyuhf99f6302017-11-15 11:23:51 -0800510 return;
Eric Erfanianccca3152017-02-22 16:32:36 -0800511 }
linyuhf99f6302017-11-15 11:23:51 -0800512
513 // Dismiss the error dialog
514 Dialog errorDialog = common.getErrorDialog();
515 if (errorDialog != null) {
516 errorDialog.dismiss();
517 common.setErrorDialog(null);
518 }
519
520 // Dismiss the phone account selection dialog
521 SelectPhoneAccountDialogFragment selectPhoneAccountDialogFragment =
522 common.getSelectPhoneAccountDialogFragment();
523 if (selectPhoneAccountDialogFragment != null) {
524 selectPhoneAccountDialogFragment.dismiss();
525 common.setSelectPhoneAccountDialogFragment(null);
526 }
527
528 // Dismiss the dialog for international call on WiFi
529 InternationalCallOnWifiDialogFragment internationalCallOnWifiFragment =
530 (InternationalCallOnWifiDialogFragment)
531 getSupportFragmentManager().findFragmentByTag(TAG_INTERNATIONAL_CALL_ON_WIFI);
532 if (internationalCallOnWifiFragment != null) {
533 internationalCallOnWifiFragment.dismiss();
534 }
535
536 // Dismiss the answer screen
537 AnswerScreen answerScreen = getAnswerScreen();
538 if (answerScreen != null) {
539 answerScreen.dismissPendingDialogs();
540 }
541
542 needDismissPendingDialogs = false;
Eric Erfanianccca3152017-02-22 16:32:36 -0800543 }
544
linyuh69a25062017-11-15 16:18:51 -0800545 // TODO(a bug): Make this method private after InCallActivityCommon is deleted.
546 void enableInCallOrientationEventListener(boolean enable) {
547 if (enable) {
548 inCallOrientationEventListener.enable(true /* notifyDeviceOrientationChange */);
549 } else {
550 inCallOrientationEventListener.disable();
551 }
Eric Erfanianccca3152017-02-22 16:32:36 -0800552 }
553
554 public void setExcludeFromRecents(boolean exclude) {
555 common.setExcludeFromRecents(exclude);
556 }
557
Eric Erfanianccca3152017-02-22 16:32:36 -0800558 @Nullable
559 public FragmentManager getDialpadFragmentManager() {
560 InCallScreen inCallScreen = getInCallScreen();
561 if (inCallScreen != null) {
562 return inCallScreen.getInCallScreenFragment().getChildFragmentManager();
563 }
564 return null;
565 }
566
567 public int getDialpadContainerId() {
568 return getInCallScreen().getAnswerAndDialpadContainerResourceId();
569 }
570
571 @Override
572 public AnswerScreenDelegate newAnswerScreenDelegate(AnswerScreen answerScreen) {
573 DialerCall call = CallList.getInstance().getCallById(answerScreen.getCallId());
574 if (call == null) {
575 // This is a work around for a bug where we attempt to create a new delegate after the call
576 // has already been removed. An example of when this can happen is:
577 // 1. incoming video call in landscape mode
578 // 2. remote party hangs up
579 // 3. activity switches from landscape to portrait
580 // At step #3 the answer fragment will try to create a new answer delegate but the call won't
581 // exist. In this case we'll simply return a stub delegate that does nothing. This is ok
582 // because this new state is transient and the activity will be destroyed soon.
583 LogUtil.i("InCallActivity.onPrimaryCallStateChanged", "call doesn't exist, using stub");
584 return new AnswerScreenPresenterStub();
585 } else {
586 return new AnswerScreenPresenter(
587 this, answerScreen, CallList.getInstance().getCallById(answerScreen.getCallId()));
588 }
589 }
590
591 @Override
592 public InCallScreenDelegate newInCallScreenDelegate() {
593 return new CallCardPresenter(this);
594 }
595
596 @Override
597 public InCallButtonUiDelegate newInCallButtonUiDelegate() {
598 return new CallButtonPresenter(this);
599 }
600
601 @Override
Eric Erfanian90508232017-03-24 09:31:16 -0700602 public VideoCallScreenDelegate newVideoCallScreenDelegate(VideoCallScreen videoCallScreen) {
603 DialerCall dialerCall = CallList.getInstance().getCallById(videoCallScreen.getCallId());
604 if (dialerCall != null && dialerCall.getVideoTech().shouldUseSurfaceView()) {
605 return dialerCall.getVideoTech().createVideoCallScreenDelegate(this, videoCallScreen);
606 }
Eric Erfanianccca3152017-02-22 16:32:36 -0800607 return new VideoCallPresenter();
608 }
609
610 public void onPrimaryCallStateChanged() {
Eric Erfanian2ca43182017-08-31 06:57:16 -0700611 Trace.beginSection("InCallActivity.onPrimaryCallStateChanged");
Eric Erfanianccca3152017-02-22 16:32:36 -0800612 LogUtil.i("InCallActivity.onPrimaryCallStateChanged", "");
613 showMainInCallFragment();
Eric Erfanian2ca43182017-08-31 06:57:16 -0700614 Trace.endSection();
Eric Erfanianccca3152017-02-22 16:32:36 -0800615 }
616
linyuh7b86f562017-11-16 11:24:09 -0800617 public void showToastForWiFiToLteHandover(DialerCall call) {
618 if (call.hasShownWiFiToLteHandoverToast()) {
619 return;
620 }
621
622 Toast.makeText(this, R.string.video_call_wifi_to_lte_handover_toast, Toast.LENGTH_LONG).show();
623 call.setHasShownWiFiToLteHandoverToast();
Eric Erfanianccca3152017-02-22 16:32:36 -0800624 }
625
linyuh7b86f562017-11-16 11:24:09 -0800626 public void showDialogOrToastForWifiHandoverFailure(DialerCall call) {
627 if (call.showWifiHandoverAlertAsToast()) {
628 Toast.makeText(this, R.string.video_call_lte_to_wifi_failed_message, Toast.LENGTH_SHORT)
629 .show();
630 return;
631 }
632
633 dismissPendingDialogs();
634
635 AlertDialog.Builder builder =
636 new AlertDialog.Builder(this).setTitle(R.string.video_call_lte_to_wifi_failed_title);
637
638 // This allows us to use the theme of the dialog instead of the activity
639 View dialogCheckBoxView =
640 View.inflate(builder.getContext(), R.layout.video_call_lte_to_wifi_failed, null /* root */);
641 CheckBox wifiHandoverFailureCheckbox =
642 (CheckBox) dialogCheckBoxView.findViewById(R.id.video_call_lte_to_wifi_failed_checkbox);
643 wifiHandoverFailureCheckbox.setChecked(false);
644
645 InCallUiLock lock = InCallPresenter.getInstance().acquireInCallUiLock("WifiFailedDialog");
646 Dialog errorDialog =
647 builder
648 .setView(dialogCheckBoxView)
649 .setMessage(R.string.video_call_lte_to_wifi_failed_message)
650 .setOnCancelListener(dialogInterface -> onDialogDismissed())
651 .setPositiveButton(
652 android.R.string.ok,
653 (dialogInterface, id) -> {
654 call.setDoNotShowDialogForHandoffToWifiFailure(
655 wifiHandoverFailureCheckbox.isChecked());
656 dialogInterface.cancel();
657 onDialogDismissed();
658 })
659 .setOnDismissListener(dialogInterface -> lock.release())
660 .create();
661
662 common.setErrorDialog(errorDialog);
663 errorDialog.show();
Eric Erfanianccca3152017-02-22 16:32:36 -0800664 }
665
linyuh7b86f562017-11-16 11:24:09 -0800666 public void showDialogForInternationalCallOnWifi(@NonNull DialerCall call) {
667 if (!InternationalCallOnWifiDialogFragment.shouldShow(this)) {
668 LogUtil.i(
669 "InCallActivity.showDialogForInternationalCallOnWifi",
670 "InternationalCallOnWifiDialogFragment.shouldShow returned false");
671 return;
672 }
673
674 InternationalCallOnWifiDialogFragment fragment =
675 InternationalCallOnWifiDialogFragment.newInstance(
676 call.getId(), common.getCallbackForInternationalCallOnWifiDialog());
677 fragment.show(getSupportFragmentManager(), TAG_INTERNATIONAL_CALL_ON_WIFI);
Eric Erfanianc857f902017-05-15 14:05:33 -0700678 }
679
Eric Erfanian938468d2017-10-24 14:05:52 -0700680 @Override
681 public void onMultiWindowModeChanged(boolean isInMultiWindowMode) {
682 super.onMultiWindowModeChanged(isInMultiWindowMode);
683 if (!isInMultiWindowMode) {
684 common.updateNavigationBar(isDialpadVisible());
685 }
686 }
687
Eric Erfanianccca3152017-02-22 16:32:36 -0800688 public void setAllowOrientationChange(boolean allowOrientationChange) {
wangqi9982f0d2017-10-11 17:46:07 -0700689 if (this.allowOrientationChange == allowOrientationChange) {
690 return;
691 }
692 this.allowOrientationChange = allowOrientationChange;
Eric Erfanianccca3152017-02-22 16:32:36 -0800693 if (!allowOrientationChange) {
694 setRequestedOrientation(InCallOrientationEventListener.ACTIVITY_PREFERENCE_DISALLOW_ROTATION);
695 } else {
696 setRequestedOrientation(InCallOrientationEventListener.ACTIVITY_PREFERENCE_ALLOW_ROTATION);
697 }
698 enableInCallOrientationEventListener(allowOrientationChange);
699 }
700
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700701 public void hideMainInCallFragment() {
Eric Erfanianccca3152017-02-22 16:32:36 -0800702 LogUtil.i("InCallActivity.hideMainInCallFragment", "");
703 if (didShowInCallScreen || didShowVideoCallScreen) {
704 FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
705 hideInCallScreenFragment(transaction);
706 hideVideoCallScreenFragment(transaction);
707 transaction.commitAllowingStateLoss();
708 getSupportFragmentManager().executePendingTransactions();
709 }
710 }
711
712 private void showMainInCallFragment() {
Eric Erfanian2ca43182017-08-31 06:57:16 -0700713 Trace.beginSection("InCallActivity.showMainInCallFragment");
Eric Erfanianccca3152017-02-22 16:32:36 -0800714 // If the activity's onStart method hasn't been called yet then defer doing any work.
715 if (!isVisible) {
716 LogUtil.i("InCallActivity.showMainInCallFragment", "not visible yet/anymore");
Eric Erfanian2ca43182017-08-31 06:57:16 -0700717 Trace.endSection();
Eric Erfanianccca3152017-02-22 16:32:36 -0800718 return;
719 }
720
721 // Don't let this be reentrant.
722 if (isInShowMainInCallFragment) {
723 LogUtil.i("InCallActivity.showMainInCallFragment", "already in method, bailing");
Eric Erfanian2ca43182017-08-31 06:57:16 -0700724 Trace.endSection();
Eric Erfanianccca3152017-02-22 16:32:36 -0800725 return;
726 }
727
728 isInShowMainInCallFragment = true;
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700729 ShouldShowUiResult shouldShowAnswerUi = getShouldShowAnswerUi();
730 ShouldShowUiResult shouldShowVideoUi = getShouldShowVideoUi();
Eric Erfanianccca3152017-02-22 16:32:36 -0800731 LogUtil.i(
732 "InCallActivity.showMainInCallFragment",
733 "shouldShowAnswerUi: %b, shouldShowVideoUi: %b, "
734 + "didShowAnswerScreen: %b, didShowInCallScreen: %b, didShowVideoCallScreen: %b",
735 shouldShowAnswerUi.shouldShow,
Eric Erfanian10b34a52017-05-04 08:23:17 -0700736 shouldShowVideoUi.shouldShow,
Eric Erfanianccca3152017-02-22 16:32:36 -0800737 didShowAnswerScreen,
738 didShowInCallScreen,
739 didShowVideoCallScreen);
740 // Only video call ui allows orientation change.
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700741 setAllowOrientationChange(shouldShowVideoUi.shouldShow);
Eric Erfanianccca3152017-02-22 16:32:36 -0800742
743 FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
744 boolean didChangeInCall;
745 boolean didChangeVideo;
746 boolean didChangeAnswer;
747 if (shouldShowAnswerUi.shouldShow) {
748 didChangeInCall = hideInCallScreenFragment(transaction);
749 didChangeVideo = hideVideoCallScreenFragment(transaction);
750 didChangeAnswer = showAnswerScreenFragment(transaction, shouldShowAnswerUi.call);
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700751 } else if (shouldShowVideoUi.shouldShow) {
Eric Erfanianccca3152017-02-22 16:32:36 -0800752 didChangeInCall = hideInCallScreenFragment(transaction);
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700753 didChangeVideo = showVideoCallScreenFragment(transaction, shouldShowVideoUi.call);
Eric Erfanianccca3152017-02-22 16:32:36 -0800754 didChangeAnswer = hideAnswerScreenFragment(transaction);
755 } else {
756 didChangeInCall = showInCallScreenFragment(transaction);
757 didChangeVideo = hideVideoCallScreenFragment(transaction);
758 didChangeAnswer = hideAnswerScreenFragment(transaction);
759 }
760
761 if (didChangeInCall || didChangeVideo || didChangeAnswer) {
Eric Erfanian2ca43182017-08-31 06:57:16 -0700762 Trace.beginSection("InCallActivity.commitTransaction");
Eric Erfanianccca3152017-02-22 16:32:36 -0800763 transaction.commitNow();
Eric Erfanian2ca43182017-08-31 06:57:16 -0700764 Trace.endSection();
Eric Erfanianccca3152017-02-22 16:32:36 -0800765 Logger.get(this).logScreenView(ScreenEvent.Type.INCALL, this);
766 }
767 isInShowMainInCallFragment = false;
Eric Erfanian2ca43182017-08-31 06:57:16 -0700768 Trace.endSection();
Eric Erfanianccca3152017-02-22 16:32:36 -0800769 }
770
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700771 private ShouldShowUiResult getShouldShowAnswerUi() {
Eric Erfanianccca3152017-02-22 16:32:36 -0800772 DialerCall call = CallList.getInstance().getIncomingCall();
773 if (call != null) {
774 LogUtil.i("InCallActivity.getShouldShowAnswerUi", "found incoming call");
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700775 return new ShouldShowUiResult(true, call);
Eric Erfanianccca3152017-02-22 16:32:36 -0800776 }
777
778 call = CallList.getInstance().getVideoUpgradeRequestCall();
779 if (call != null) {
780 LogUtil.i("InCallActivity.getShouldShowAnswerUi", "found video upgrade request");
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700781 return new ShouldShowUiResult(true, call);
Eric Erfanianccca3152017-02-22 16:32:36 -0800782 }
783
784 // Check if we're showing the answer screen and the call is disconnected. If this condition is
785 // true then we won't switch from the answer UI to the in call UI. This prevents flicker when
786 // the user rejects an incoming call.
787 call = CallList.getInstance().getFirstCall();
788 if (call == null) {
789 call = CallList.getInstance().getBackgroundCall();
790 }
791 if (didShowAnswerScreen && (call == null || call.getState() == State.DISCONNECTED)) {
792 LogUtil.i("InCallActivity.getShouldShowAnswerUi", "found disconnecting incoming call");
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700793 return new ShouldShowUiResult(true, call);
Eric Erfanianccca3152017-02-22 16:32:36 -0800794 }
795
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700796 return new ShouldShowUiResult(false, null);
Eric Erfanianccca3152017-02-22 16:32:36 -0800797 }
798
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700799 private static ShouldShowUiResult getShouldShowVideoUi() {
Eric Erfanianccca3152017-02-22 16:32:36 -0800800 DialerCall call = CallList.getInstance().getFirstCall();
801 if (call == null) {
802 LogUtil.i("InCallActivity.getShouldShowVideoUi", "null call");
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700803 return new ShouldShowUiResult(false, null);
Eric Erfanianccca3152017-02-22 16:32:36 -0800804 }
805
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700806 if (call.isVideoCall()) {
Eric Erfanianccca3152017-02-22 16:32:36 -0800807 LogUtil.i("InCallActivity.getShouldShowVideoUi", "found video call");
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700808 return new ShouldShowUiResult(true, call);
Eric Erfanianccca3152017-02-22 16:32:36 -0800809 }
810
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700811 if (call.hasSentVideoUpgradeRequest()) {
Eric Erfanianccca3152017-02-22 16:32:36 -0800812 LogUtil.i("InCallActivity.getShouldShowVideoUi", "upgrading to video");
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700813 return new ShouldShowUiResult(true, call);
Eric Erfanianccca3152017-02-22 16:32:36 -0800814 }
815
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700816 return new ShouldShowUiResult(false, null);
Eric Erfanianccca3152017-02-22 16:32:36 -0800817 }
818
819 private boolean showAnswerScreenFragment(FragmentTransaction transaction, DialerCall call) {
820 // When rejecting a call the active call can become null in which case we should continue
821 // showing the answer screen.
822 if (didShowAnswerScreen && call == null) {
823 return false;
824 }
825
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700826 Assert.checkArgument(call != null, "didShowAnswerScreen was false but call was still null");
827
828 boolean isVideoUpgradeRequest = call.hasReceivedVideoUpgradeRequest();
Eric Erfanianccca3152017-02-22 16:32:36 -0800829
830 // Check if we're already showing an answer screen for this call.
831 if (didShowAnswerScreen) {
832 AnswerScreen answerScreen = getAnswerScreen();
833 if (answerScreen.getCallId().equals(call.getId())
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700834 && answerScreen.isVideoCall() == call.isVideoCall()
Eric Erfanian2ca43182017-08-31 06:57:16 -0700835 && answerScreen.isVideoUpgradeRequest() == isVideoUpgradeRequest
836 && !answerScreen.isActionTimeout()) {
837 LogUtil.d(
838 "InCallActivity.showAnswerScreenFragment",
839 "answer fragment exists for same call and has NOT been accepted/rejected/timed out");
Eric Erfanianccca3152017-02-22 16:32:36 -0800840 return false;
841 }
Eric Erfanian2ca43182017-08-31 06:57:16 -0700842 if (answerScreen.isActionTimeout()) {
843 LogUtil.i(
844 "InCallActivity.showAnswerScreenFragment",
845 "answer fragment exists but has been accepted/rejected and timed out");
846 } else {
847 LogUtil.i(
848 "InCallActivity.showAnswerScreenFragment",
849 "answer fragment exists but arguments do not match");
850 }
Eric Erfanianccca3152017-02-22 16:32:36 -0800851 hideAnswerScreenFragment(transaction);
852 }
853
854 // Show a new answer screen.
855 AnswerScreen answerScreen =
Eric Erfanianfc37b022017-03-21 10:11:17 -0700856 AnswerBindings.createAnswerScreen(
857 call.getId(),
858 call.isVideoCall(),
859 isVideoUpgradeRequest,
Eric Erfanian90508232017-03-24 09:31:16 -0700860 call.getVideoTech().isSelfManagedCamera(),
861 shouldAllowAnswerAndRelease(call),
862 CallList.getInstance().getBackgroundCall() != null);
Eric Erfanianccca3152017-02-22 16:32:36 -0800863 transaction.add(R.id.main, answerScreen.getAnswerScreenFragment(), TAG_ANSWER_SCREEN);
864
865 Logger.get(this).logScreenView(ScreenEvent.Type.INCOMING_CALL, this);
866 didShowAnswerScreen = true;
867 return true;
868 }
869
Eric Erfanian90508232017-03-24 09:31:16 -0700870 private boolean shouldAllowAnswerAndRelease(DialerCall call) {
871 if (CallList.getInstance().getActiveCall() == null) {
872 LogUtil.i("InCallActivity.shouldAllowAnswerAndRelease", "no active call");
873 return false;
874 }
875 if (getSystemService(TelephonyManager.class).getPhoneType()
876 == TelephonyManager.PHONE_TYPE_CDMA) {
877 LogUtil.i("InCallActivity.shouldAllowAnswerAndRelease", "PHONE_TYPE_CDMA not supported");
878 return false;
879 }
880 if (call.isVideoCall() || call.hasReceivedVideoUpgradeRequest()) {
881 LogUtil.i("InCallActivity.shouldAllowAnswerAndRelease", "video call");
882 return false;
883 }
884 if (!ConfigProviderBindings.get(this).getBoolean(CONFIG_ANSWER_AND_RELEASE_ENABLED, true)) {
885 LogUtil.i("InCallActivity.shouldAllowAnswerAndRelease", "disabled by config");
886 return false;
887 }
888
889 return true;
890 }
891
Eric Erfanianccca3152017-02-22 16:32:36 -0800892 private boolean hideAnswerScreenFragment(FragmentTransaction transaction) {
893 if (!didShowAnswerScreen) {
894 return false;
895 }
896 AnswerScreen answerScreen = getAnswerScreen();
897 if (answerScreen != null) {
898 transaction.remove(answerScreen.getAnswerScreenFragment());
899 }
900
901 didShowAnswerScreen = false;
902 return true;
903 }
904
905 private boolean showInCallScreenFragment(FragmentTransaction transaction) {
906 if (didShowInCallScreen) {
907 return false;
908 }
Eric Erfanian2ca43182017-08-31 06:57:16 -0700909 InCallScreen inCallScreen = InCallBindings.createInCallScreen();
910 transaction.add(R.id.main, inCallScreen.getInCallScreenFragment(), TAG_IN_CALL_SCREEN);
Eric Erfanianccca3152017-02-22 16:32:36 -0800911 Logger.get(this).logScreenView(ScreenEvent.Type.INCALL, this);
912 didShowInCallScreen = true;
913 return true;
914 }
915
916 private boolean hideInCallScreenFragment(FragmentTransaction transaction) {
917 if (!didShowInCallScreen) {
918 return false;
919 }
920 InCallScreen inCallScreen = getInCallScreen();
921 if (inCallScreen != null) {
Eric Erfanian2ca43182017-08-31 06:57:16 -0700922 transaction.remove(inCallScreen.getInCallScreenFragment());
Eric Erfanianccca3152017-02-22 16:32:36 -0800923 }
924 didShowInCallScreen = false;
925 return true;
926 }
927
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700928 private boolean showVideoCallScreenFragment(FragmentTransaction transaction, DialerCall call) {
Eric Erfanianccca3152017-02-22 16:32:36 -0800929 if (didShowVideoCallScreen) {
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700930 VideoCallScreen videoCallScreen = getVideoCallScreen();
931 if (videoCallScreen.getCallId().equals(call.getId())) {
932 return false;
933 }
934 LogUtil.i(
935 "InCallActivity.showVideoCallScreenFragment",
936 "video call fragment exists but arguments do not match");
937 hideVideoCallScreenFragment(transaction);
Eric Erfanianccca3152017-02-22 16:32:36 -0800938 }
939
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700940 LogUtil.i("InCallActivity.showVideoCallScreenFragment", "call: %s", call);
941
Eric Erfanian90508232017-03-24 09:31:16 -0700942 VideoCallScreen videoCallScreen =
943 VideoBindings.createVideoCallScreen(
944 call.getId(), call.getVideoTech().shouldUseSurfaceView());
Eric Erfanianccca3152017-02-22 16:32:36 -0800945 transaction.add(R.id.main, videoCallScreen.getVideoCallScreenFragment(), TAG_VIDEO_CALL_SCREEN);
946
947 Logger.get(this).logScreenView(ScreenEvent.Type.INCALL, this);
948 didShowVideoCallScreen = true;
949 return true;
950 }
951
952 private boolean hideVideoCallScreenFragment(FragmentTransaction transaction) {
953 if (!didShowVideoCallScreen) {
954 return false;
955 }
956 VideoCallScreen videoCallScreen = getVideoCallScreen();
957 if (videoCallScreen != null) {
958 transaction.remove(videoCallScreen.getVideoCallScreenFragment());
959 }
960 didShowVideoCallScreen = false;
961 return true;
962 }
963
964 AnswerScreen getAnswerScreen() {
965 return (AnswerScreen) getSupportFragmentManager().findFragmentByTag(TAG_ANSWER_SCREEN);
966 }
967
968 InCallScreen getInCallScreen() {
969 return (InCallScreen) getSupportFragmentManager().findFragmentByTag(TAG_IN_CALL_SCREEN);
970 }
971
972 VideoCallScreen getVideoCallScreen() {
973 return (VideoCallScreen) getSupportFragmentManager().findFragmentByTag(TAG_VIDEO_CALL_SCREEN);
974 }
975
976 @Override
977 public void onPseudoScreenStateChanged(boolean isOn) {
978 LogUtil.i("InCallActivity.onPseudoScreenStateChanged", "isOn: " + isOn);
979 pseudoBlackScreenOverlay.setVisibility(isOn ? View.GONE : View.VISIBLE);
980 }
981
982 /**
983 * For some touch related issue, turning off the screen can be faked by drawing a black view over
984 * the activity. All touch events started when the screen is "off" is rejected.
985 *
986 * @see PseudoScreenState
987 */
988 @Override
989 public boolean dispatchTouchEvent(MotionEvent event) {
990 // Reject any gesture that started when the screen is in the fake off state.
991 if (touchDownWhenPseudoScreenOff) {
992 if (event.getAction() == MotionEvent.ACTION_UP) {
993 touchDownWhenPseudoScreenOff = false;
994 }
995 return true;
996 }
997 // Reject all touch event when the screen is in the fake off state.
998 if (!InCallPresenter.getInstance().getPseudoScreenState().isOn()) {
999 if (event.getAction() == MotionEvent.ACTION_DOWN) {
1000 touchDownWhenPseudoScreenOff = true;
1001 LogUtil.i("InCallActivity.dispatchTouchEvent", "touchDownWhenPseudoScreenOff");
1002 }
1003 return true;
1004 }
1005 return super.dispatchTouchEvent(event);
1006 }
1007
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001008 private static class ShouldShowUiResult {
Eric Erfanianccca3152017-02-22 16:32:36 -08001009 public final boolean shouldShow;
1010 public final DialerCall call;
1011
Eric Erfaniand5e47f62017-03-15 14:41:07 -07001012 ShouldShowUiResult(boolean shouldShow, DialerCall call) {
Eric Erfanianccca3152017-02-22 16:32:36 -08001013 this.shouldShow = shouldShow;
1014 this.call = call;
1015 }
1016 }
1017}