blob: 307415916db46674ec32c4a1d05a1c0f0fc237f5 [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
19import android.content.Context;
20import android.content.Intent;
21import android.graphics.drawable.GradientDrawable;
22import android.graphics.drawable.GradientDrawable.Orientation;
23import android.os.Bundle;
24import android.support.annotation.ColorInt;
25import android.support.annotation.FloatRange;
26import android.support.annotation.Nullable;
27import android.support.v4.app.FragmentManager;
28import android.support.v4.app.FragmentTransaction;
29import android.support.v4.graphics.ColorUtils;
30import android.telecom.DisconnectCause;
31import android.view.KeyEvent;
32import android.view.MenuItem;
33import android.view.MotionEvent;
34import android.view.View;
35import com.android.dialer.common.LogUtil;
36import com.android.dialer.compat.ActivityCompat;
37import com.android.dialer.logging.Logger;
38import com.android.dialer.logging.nano.ScreenEvent;
39import com.android.incallui.answer.bindings.AnswerBindings;
40import com.android.incallui.answer.protocol.AnswerScreen;
41import com.android.incallui.answer.protocol.AnswerScreenDelegate;
42import com.android.incallui.answer.protocol.AnswerScreenDelegateFactory;
43import com.android.incallui.answerproximitysensor.PseudoScreenState;
44import com.android.incallui.call.CallList;
45import com.android.incallui.call.DialerCall;
46import com.android.incallui.call.DialerCall.State;
47import com.android.incallui.call.VideoUtils;
48import com.android.incallui.incall.bindings.InCallBindings;
49import com.android.incallui.incall.protocol.InCallButtonUiDelegate;
50import com.android.incallui.incall.protocol.InCallButtonUiDelegateFactory;
51import com.android.incallui.incall.protocol.InCallScreen;
52import com.android.incallui.incall.protocol.InCallScreenDelegate;
53import com.android.incallui.incall.protocol.InCallScreenDelegateFactory;
54import com.android.incallui.video.bindings.VideoBindings;
55import com.android.incallui.video.protocol.VideoCallScreen;
56import com.android.incallui.video.protocol.VideoCallScreenDelegate;
57import com.android.incallui.video.protocol.VideoCallScreenDelegateFactory;
58
59/** Version of {@link InCallActivity} that shows the new UI */
60public class InCallActivity extends TransactionSafeFragmentActivity
61 implements AnswerScreenDelegateFactory,
62 InCallScreenDelegateFactory,
63 InCallButtonUiDelegateFactory,
64 VideoCallScreenDelegateFactory,
65 PseudoScreenState.StateChangedListener {
66
67 private static final String TAG_IN_CALL_SCREEN = "tag_in_call_screen";
68 private static final String TAG_ANSWER_SCREEN = "tag_answer_screen";
69 private static final String TAG_VIDEO_CALL_SCREEN = "tag_video_call_screen";
70
71 private static final String DID_SHOW_ANSWER_SCREEN_KEY = "did_show_answer_screen";
72 private static final String DID_SHOW_IN_CALL_SCREEN_KEY = "did_show_in_call_screen";
73 private static final String DID_SHOW_VIDEO_CALL_SCREEN_KEY = "did_show_video_call_screen";
74
75 private final InCallActivityCommon common;
76 private boolean didShowAnswerScreen;
77 private boolean didShowInCallScreen;
78 private boolean didShowVideoCallScreen;
79 private int[] backgroundDrawableColors;
80 private GradientDrawable backgroundDrawable;
81 private boolean isVisible;
82 private View pseudoBlackScreenOverlay;
83 private boolean touchDownWhenPseudoScreenOff;
84 private boolean isInShowMainInCallFragment;
85 private boolean needDismissPendingDialogs;
86
87 public InCallActivity() {
88 common = new InCallActivityCommon(this);
89 }
90
91 public static Intent getIntent(
92 Context context,
93 boolean showDialpad,
94 boolean newOutgoingCall,
95 boolean isVideoCall,
96 boolean isForFullScreen) {
97 Intent intent = new Intent(Intent.ACTION_MAIN, null);
98 intent.setFlags(Intent.FLAG_ACTIVITY_NO_USER_ACTION | Intent.FLAG_ACTIVITY_NEW_TASK);
99 intent.setClass(context, InCallActivity.class);
100 InCallActivityCommon.setIntentExtras(intent, showDialpad, newOutgoingCall, isForFullScreen);
101 return intent;
102 }
103
104 @Override
105 protected void onResumeFragments() {
106 super.onResumeFragments();
107 if (needDismissPendingDialogs) {
108 dismissPendingDialogs();
109 }
110 }
111
112 @Override
113 protected void onCreate(Bundle icicle) {
114 LogUtil.i("InCallActivity.onCreate", "");
115 super.onCreate(icicle);
116
117 if (icicle != null) {
118 didShowAnswerScreen = icicle.getBoolean(DID_SHOW_ANSWER_SCREEN_KEY);
119 didShowInCallScreen = icicle.getBoolean(DID_SHOW_IN_CALL_SCREEN_KEY);
120 didShowVideoCallScreen = icicle.getBoolean(DID_SHOW_VIDEO_CALL_SCREEN_KEY);
121 }
122
123 common.onCreate(icicle);
124
125 getWindow()
126 .getDecorView()
127 .setSystemUiVisibility(
128 View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
129
130 pseudoBlackScreenOverlay = findViewById(R.id.psuedo_black_screen_overlay);
131 }
132
133 @Override
134 protected void onSaveInstanceState(Bundle out) {
135 LogUtil.i("InCallActivity.onSaveInstanceState", "");
136 common.onSaveInstanceState(out);
137 out.putBoolean(DID_SHOW_ANSWER_SCREEN_KEY, didShowAnswerScreen);
138 out.putBoolean(DID_SHOW_IN_CALL_SCREEN_KEY, didShowInCallScreen);
139 out.putBoolean(DID_SHOW_VIDEO_CALL_SCREEN_KEY, didShowVideoCallScreen);
140 super.onSaveInstanceState(out);
141 isVisible = false;
142 }
143
144 @Override
145 protected void onStart() {
146 LogUtil.i("InCallActivity.onStart", "");
147 super.onStart();
148 isVisible = true;
149 showMainInCallFragment();
150 common.onStart();
151 if (ActivityCompat.isInMultiWindowMode(this)
152 && !getResources().getBoolean(R.bool.incall_dialpad_allowed)) {
153 // Hide the dialpad because there may not be enough room
154 showDialpadFragment(false, false);
155 }
156 }
157
158 @Override
159 protected void onResume() {
160 LogUtil.i("InCallActivity.onResume", "");
161 super.onResume();
162 common.onResume();
163 PseudoScreenState pseudoScreenState = InCallPresenter.getInstance().getPseudoScreenState();
164 pseudoScreenState.addListener(this);
165 onPseudoScreenStateChanged(pseudoScreenState.isOn());
166 }
167
168 /** onPause is guaranteed to be called when the InCallActivity goes in the background. */
169 @Override
170 protected void onPause() {
171 LogUtil.i("InCallActivity.onPause", "");
172 super.onPause();
173 common.onPause();
174 InCallPresenter.getInstance().getPseudoScreenState().removeListener(this);
175 }
176
177 @Override
178 protected void onStop() {
179 LogUtil.i("InCallActivity.onStop", "");
180 super.onStop();
181 common.onStop();
182 isVisible = false;
183 }
184
185 @Override
186 protected void onDestroy() {
187 LogUtil.i("InCallActivity.onDestroy", "");
188 super.onDestroy();
189 common.onDestroy();
190 }
191
192 @Override
193 public void finish() {
194 if (shouldCloseActivityOnFinish()) {
195 super.finish();
196 }
197 }
198
199 private boolean shouldCloseActivityOnFinish() {
200 if (!isVisible()) {
201 LogUtil.i(
202 "InCallActivity.shouldCloseActivityOnFinish",
203 "allowing activity to be closed because it's not visible");
204 return true;
205 }
206
207 if (common.hasPendingDialogs()) {
208 LogUtil.i(
209 "InCallActivity.shouldCloseActivityOnFinish", "dialog is visible, not closing activity");
210 return false;
211 }
212
213 AnswerScreen answerScreen = getAnswerScreen();
214 if (answerScreen != null && answerScreen.hasPendingDialogs()) {
215 LogUtil.i(
216 "InCallActivity.shouldCloseActivityOnFinish",
217 "answer screen dialog is visible, not closing activity");
218 return false;
219 }
220
221 LogUtil.i(
222 "InCallActivity.shouldCloseActivityOnFinish",
223 "activity is visible and has no dialogs, allowing activity to close");
224 return true;
225 }
226
227 @Override
228 protected void onNewIntent(Intent intent) {
229 LogUtil.i("InCallActivity.onNewIntent", "");
230 common.onNewIntent(intent);
231
232 // If the screen is off, we need to make sure it gets turned on for incoming calls.
233 // This normally works just fine thanks to FLAG_TURN_SCREEN_ON but that only works
234 // when the activity is first created. Therefore, to ensure the screen is turned on
235 // for the call waiting case, we recreate() the current activity. There should be no jank from
236 // this since the screen is already off and will remain so until our new activity is up.
237 if (!isVisible()) {
238 LogUtil.i("InCallActivity.onNewIntent", "Restarting InCallActivity to force screen on.");
239 recreate();
240 }
241 }
242
243 @Override
244 public void onBackPressed() {
245 LogUtil.i("InCallActivity.onBackPressed", "");
246 if (!common.onBackPressed(didShowInCallScreen || didShowVideoCallScreen)) {
247 super.onBackPressed();
248 }
249 }
250
251 @Override
252 public boolean onOptionsItemSelected(MenuItem item) {
253 LogUtil.i("InCallActivity.onOptionsItemSelected", "item: " + item);
254 if (item.getItemId() == android.R.id.home) {
255 onBackPressed();
256 return true;
257 }
258 return super.onOptionsItemSelected(item);
259 }
260
261 @Override
262 public boolean onKeyUp(int keyCode, KeyEvent event) {
263 if (common.onKeyUp(keyCode, event)) {
264 return true;
265 }
266 return super.onKeyUp(keyCode, event);
267 }
268
269 @Override
270 public boolean onKeyDown(int keyCode, KeyEvent event) {
271 if (common.onKeyDown(keyCode, event)) {
272 return true;
273 }
274 return super.onKeyDown(keyCode, event);
275 }
276
277 public boolean isInCallScreenAnimating() {
278 return false;
279 }
280
281 public void showConferenceFragment(boolean show) {
282 if (show) {
283 startActivity(new Intent(this, ManageConferenceActivity.class));
284 }
285 }
286
287 public boolean showDialpadFragment(boolean show, boolean animate) {
288 boolean didChange = common.showDialpadFragment(show, animate);
289 if (didChange) {
290 // Note: onInCallScreenDialpadVisibilityChange is called here to ensure that the dialpad FAB
291 // repositions itself.
292 getInCallScreen().onInCallScreenDialpadVisibilityChange(show);
293 }
294 return didChange;
295 }
296
297 public boolean isDialpadVisible() {
298 return common.isDialpadVisible();
299 }
300
301 public void onForegroundCallChanged(DialerCall newForegroundCall) {
302 common.updateTaskDescription();
303 if (didShowAnswerScreen && newForegroundCall != null) {
304 if (newForegroundCall.getState() == State.DISCONNECTED
305 || newForegroundCall.getState() == State.IDLE) {
306 LogUtil.i(
307 "InCallActivity.onForegroundCallChanged",
308 "rejecting incoming call, not updating " + "window background color");
309 }
310 } else {
311 LogUtil.v("InCallActivity.onForegroundCallChanged", "resetting background color");
312 updateWindowBackgroundColor(0);
313 }
314 }
315
316 public void updateWindowBackgroundColor(@FloatRange(from = -1f, to = 1.0f) float progress) {
317 ThemeColorManager themeColorManager = InCallPresenter.getInstance().getThemeColorManager();
318 @ColorInt int top;
319 @ColorInt int middle;
320 @ColorInt int bottom;
321 @ColorInt int gray = 0x66000000;
322
323 if (ActivityCompat.isInMultiWindowMode(this)) {
324 top = themeColorManager.getBackgroundColorSolid();
325 middle = themeColorManager.getBackgroundColorSolid();
326 bottom = themeColorManager.getBackgroundColorSolid();
327 } else {
328 top = themeColorManager.getBackgroundColorTop();
329 middle = themeColorManager.getBackgroundColorMiddle();
330 bottom = themeColorManager.getBackgroundColorBottom();
331 }
332
333 if (progress < 0) {
334 float correctedProgress = Math.abs(progress);
335 top = ColorUtils.blendARGB(top, gray, correctedProgress);
336 middle = ColorUtils.blendARGB(middle, gray, correctedProgress);
337 bottom = ColorUtils.blendARGB(bottom, gray, correctedProgress);
338 }
339
340 boolean backgroundDirty = false;
341 if (backgroundDrawable == null) {
342 backgroundDrawableColors = new int[] {top, middle, bottom};
343 backgroundDrawable = new GradientDrawable(Orientation.TOP_BOTTOM, backgroundDrawableColors);
344 backgroundDirty = true;
345 } else {
346 if (backgroundDrawableColors[0] != top) {
347 backgroundDrawableColors[0] = top;
348 backgroundDirty = true;
349 }
350 if (backgroundDrawableColors[1] != middle) {
351 backgroundDrawableColors[1] = middle;
352 backgroundDirty = true;
353 }
354 if (backgroundDrawableColors[2] != bottom) {
355 backgroundDrawableColors[2] = bottom;
356 backgroundDirty = true;
357 }
358 if (backgroundDirty) {
359 backgroundDrawable.setColors(backgroundDrawableColors);
360 }
361 }
362
363 if (backgroundDirty) {
364 getWindow().setBackgroundDrawable(backgroundDrawable);
365 }
366 }
367
368 public boolean isVisible() {
369 return isVisible;
370 }
371
372 public boolean getCallCardFragmentVisible() {
373 return didShowInCallScreen || didShowVideoCallScreen;
374 }
375
376 public void dismissKeyguard(boolean dismiss) {
377 common.dismissKeyguard(dismiss);
378 }
379
380 public void showPostCharWaitDialog(String callId, String chars) {
381 common.showPostCharWaitDialog(callId, chars);
382 }
383
384 public void maybeShowErrorDialogOnDisconnect(DisconnectCause disconnectCause) {
385 common.maybeShowErrorDialogOnDisconnect(disconnectCause);
386 }
387
388 public void dismissPendingDialogs() {
389 if (isVisible) {
390 LogUtil.i("InCallActivity.dismissPendingDialogs", "");
391 common.dismissPendingDialogs();
392 AnswerScreen answerScreen = getAnswerScreen();
393 if (answerScreen != null) {
394 answerScreen.dismissPendingDialogs();
395 }
396 needDismissPendingDialogs = false;
397 } else {
398 // The activity is not visible and onSaveInstanceState may have been called so defer the
399 // dismissing action.
400 LogUtil.i(
401 "InCallActivity.dismissPendingDialogs", "defer actions since activity is not visible");
402 needDismissPendingDialogs = true;
403 }
404 }
405
406 private void enableInCallOrientationEventListener(boolean enable) {
407 common.enableInCallOrientationEventListener(enable);
408 }
409
410 public void setExcludeFromRecents(boolean exclude) {
411 common.setExcludeFromRecents(exclude);
412 }
413
414 public void onResolveIntent(
415 DialerCall outgoingCall, boolean isNewOutgoingCall, boolean didShowAccountSelectionDialog) {
416 if (didShowAccountSelectionDialog) {
417 hideMainInCallFragment();
418 }
419 }
420
421 @Nullable
422 public FragmentManager getDialpadFragmentManager() {
423 InCallScreen inCallScreen = getInCallScreen();
424 if (inCallScreen != null) {
425 return inCallScreen.getInCallScreenFragment().getChildFragmentManager();
426 }
427 return null;
428 }
429
430 public int getDialpadContainerId() {
431 return getInCallScreen().getAnswerAndDialpadContainerResourceId();
432 }
433
434 @Override
435 public AnswerScreenDelegate newAnswerScreenDelegate(AnswerScreen answerScreen) {
436 DialerCall call = CallList.getInstance().getCallById(answerScreen.getCallId());
437 if (call == null) {
438 // This is a work around for a bug where we attempt to create a new delegate after the call
439 // has already been removed. An example of when this can happen is:
440 // 1. incoming video call in landscape mode
441 // 2. remote party hangs up
442 // 3. activity switches from landscape to portrait
443 // At step #3 the answer fragment will try to create a new answer delegate but the call won't
444 // exist. In this case we'll simply return a stub delegate that does nothing. This is ok
445 // because this new state is transient and the activity will be destroyed soon.
446 LogUtil.i("InCallActivity.onPrimaryCallStateChanged", "call doesn't exist, using stub");
447 return new AnswerScreenPresenterStub();
448 } else {
449 return new AnswerScreenPresenter(
450 this, answerScreen, CallList.getInstance().getCallById(answerScreen.getCallId()));
451 }
452 }
453
454 @Override
455 public InCallScreenDelegate newInCallScreenDelegate() {
456 return new CallCardPresenter(this);
457 }
458
459 @Override
460 public InCallButtonUiDelegate newInCallButtonUiDelegate() {
461 return new CallButtonPresenter(this);
462 }
463
464 @Override
465 public VideoCallScreenDelegate newVideoCallScreenDelegate() {
466 return new VideoCallPresenter();
467 }
468
469 public void onPrimaryCallStateChanged() {
470 LogUtil.i("InCallActivity.onPrimaryCallStateChanged", "");
471 showMainInCallFragment();
472 }
473
474 public void onWiFiToLteHandover(DialerCall call) {
475 common.showWifiToLteHandoverToast(call);
476 }
477
478 public void onHandoverToWifiFailed(DialerCall call) {
479 common.showWifiFailedDialog(call);
480 }
481
482 public void setAllowOrientationChange(boolean allowOrientationChange) {
483 if (!allowOrientationChange) {
484 setRequestedOrientation(InCallOrientationEventListener.ACTIVITY_PREFERENCE_DISALLOW_ROTATION);
485 } else {
486 setRequestedOrientation(InCallOrientationEventListener.ACTIVITY_PREFERENCE_ALLOW_ROTATION);
487 }
488 enableInCallOrientationEventListener(allowOrientationChange);
489 }
490
491 private void hideMainInCallFragment() {
492 LogUtil.i("InCallActivity.hideMainInCallFragment", "");
493 if (didShowInCallScreen || didShowVideoCallScreen) {
494 FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
495 hideInCallScreenFragment(transaction);
496 hideVideoCallScreenFragment(transaction);
497 transaction.commitAllowingStateLoss();
498 getSupportFragmentManager().executePendingTransactions();
499 }
500 }
501
502 private void showMainInCallFragment() {
503 // If the activity's onStart method hasn't been called yet then defer doing any work.
504 if (!isVisible) {
505 LogUtil.i("InCallActivity.showMainInCallFragment", "not visible yet/anymore");
506 return;
507 }
508
509 // Don't let this be reentrant.
510 if (isInShowMainInCallFragment) {
511 LogUtil.i("InCallActivity.showMainInCallFragment", "already in method, bailing");
512 return;
513 }
514
515 isInShowMainInCallFragment = true;
516 ShouldShowAnswerUiResult shouldShowAnswerUi = getShouldShowAnswerUi();
517 boolean shouldShowVideoUi = getShouldShowVideoUi();
518 LogUtil.i(
519 "InCallActivity.showMainInCallFragment",
520 "shouldShowAnswerUi: %b, shouldShowVideoUi: %b, "
521 + "didShowAnswerScreen: %b, didShowInCallScreen: %b, didShowVideoCallScreen: %b",
522 shouldShowAnswerUi.shouldShow,
523 shouldShowVideoUi,
524 didShowAnswerScreen,
525 didShowInCallScreen,
526 didShowVideoCallScreen);
527 // Only video call ui allows orientation change.
528 setAllowOrientationChange(shouldShowVideoUi);
529
530 FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
531 boolean didChangeInCall;
532 boolean didChangeVideo;
533 boolean didChangeAnswer;
534 if (shouldShowAnswerUi.shouldShow) {
535 didChangeInCall = hideInCallScreenFragment(transaction);
536 didChangeVideo = hideVideoCallScreenFragment(transaction);
537 didChangeAnswer = showAnswerScreenFragment(transaction, shouldShowAnswerUi.call);
538 } else if (shouldShowVideoUi) {
539 didChangeInCall = hideInCallScreenFragment(transaction);
540 didChangeVideo = showVideoCallScreenFragment(transaction);
541 didChangeAnswer = hideAnswerScreenFragment(transaction);
542 } else {
543 didChangeInCall = showInCallScreenFragment(transaction);
544 didChangeVideo = hideVideoCallScreenFragment(transaction);
545 didChangeAnswer = hideAnswerScreenFragment(transaction);
546 }
547
548 if (didChangeInCall || didChangeVideo || didChangeAnswer) {
549 transaction.commitNow();
550 Logger.get(this).logScreenView(ScreenEvent.Type.INCALL, this);
551 }
552 isInShowMainInCallFragment = false;
553 }
554
555 private ShouldShowAnswerUiResult getShouldShowAnswerUi() {
556 DialerCall call = CallList.getInstance().getIncomingCall();
557 if (call != null) {
558 LogUtil.i("InCallActivity.getShouldShowAnswerUi", "found incoming call");
559 return new ShouldShowAnswerUiResult(true, call);
560 }
561
562 call = CallList.getInstance().getVideoUpgradeRequestCall();
563 if (call != null) {
564 LogUtil.i("InCallActivity.getShouldShowAnswerUi", "found video upgrade request");
565 return new ShouldShowAnswerUiResult(true, call);
566 }
567
568 // Check if we're showing the answer screen and the call is disconnected. If this condition is
569 // true then we won't switch from the answer UI to the in call UI. This prevents flicker when
570 // the user rejects an incoming call.
571 call = CallList.getInstance().getFirstCall();
572 if (call == null) {
573 call = CallList.getInstance().getBackgroundCall();
574 }
575 if (didShowAnswerScreen && (call == null || call.getState() == State.DISCONNECTED)) {
576 LogUtil.i("InCallActivity.getShouldShowAnswerUi", "found disconnecting incoming call");
577 return new ShouldShowAnswerUiResult(true, call);
578 }
579
580 return new ShouldShowAnswerUiResult(false, null);
581 }
582
583 private boolean getShouldShowVideoUi() {
584 DialerCall call = CallList.getInstance().getFirstCall();
585 if (call == null) {
586 LogUtil.i("InCallActivity.getShouldShowVideoUi", "null call");
587 return false;
588 }
589
590 if (VideoUtils.isVideoCall(call)) {
591 LogUtil.i("InCallActivity.getShouldShowVideoUi", "found video call");
592 return true;
593 }
594
595 if (VideoUtils.hasSentVideoUpgradeRequest(call)) {
596 LogUtil.i("InCallActivity.getShouldShowVideoUi", "upgrading to video");
597 return true;
598 }
599
600 return false;
601 }
602
603 private boolean showAnswerScreenFragment(FragmentTransaction transaction, DialerCall call) {
604 // When rejecting a call the active call can become null in which case we should continue
605 // showing the answer screen.
606 if (didShowAnswerScreen && call == null) {
607 return false;
608 }
609
610 boolean isVideoUpgradeRequest = VideoUtils.hasReceivedVideoUpgradeRequest(call);
611 int videoState = isVideoUpgradeRequest ? call.getRequestedVideoState() : call.getVideoState();
612
613 // Check if we're already showing an answer screen for this call.
614 if (didShowAnswerScreen) {
615 AnswerScreen answerScreen = getAnswerScreen();
616 if (answerScreen.getCallId().equals(call.getId())
617 && answerScreen.getVideoState() == videoState
618 && answerScreen.isVideoUpgradeRequest() == isVideoUpgradeRequest) {
619 return false;
620 }
621 LogUtil.i(
622 "InCallActivity.showAnswerScreenFragment",
623 "answer fragment exists but arguments do not match");
624 hideAnswerScreenFragment(transaction);
625 }
626
627 // Show a new answer screen.
628 AnswerScreen answerScreen =
629 AnswerBindings.createAnswerScreen(call.getId(), videoState, isVideoUpgradeRequest);
630 transaction.add(R.id.main, answerScreen.getAnswerScreenFragment(), TAG_ANSWER_SCREEN);
631
632 Logger.get(this).logScreenView(ScreenEvent.Type.INCOMING_CALL, this);
633 didShowAnswerScreen = true;
634 return true;
635 }
636
637 private boolean hideAnswerScreenFragment(FragmentTransaction transaction) {
638 if (!didShowAnswerScreen) {
639 return false;
640 }
641 AnswerScreen answerScreen = getAnswerScreen();
642 if (answerScreen != null) {
643 transaction.remove(answerScreen.getAnswerScreenFragment());
644 }
645
646 didShowAnswerScreen = false;
647 return true;
648 }
649
650 private boolean showInCallScreenFragment(FragmentTransaction transaction) {
651 if (didShowInCallScreen) {
652 return false;
653 }
654 InCallScreen inCallScreen = getInCallScreen();
655 if (inCallScreen == null) {
656 inCallScreen = InCallBindings.createInCallScreen();
657 transaction.add(R.id.main, inCallScreen.getInCallScreenFragment(), TAG_IN_CALL_SCREEN);
658 } else {
659 transaction.show(inCallScreen.getInCallScreenFragment());
660 }
661 Logger.get(this).logScreenView(ScreenEvent.Type.INCALL, this);
662 didShowInCallScreen = true;
663 return true;
664 }
665
666 private boolean hideInCallScreenFragment(FragmentTransaction transaction) {
667 if (!didShowInCallScreen) {
668 return false;
669 }
670 InCallScreen inCallScreen = getInCallScreen();
671 if (inCallScreen != null) {
672 transaction.hide(inCallScreen.getInCallScreenFragment());
673 }
674 didShowInCallScreen = false;
675 return true;
676 }
677
678 private boolean showVideoCallScreenFragment(FragmentTransaction transaction) {
679 if (didShowVideoCallScreen) {
680 return false;
681 }
682
683 VideoCallScreen videoCallScreen = VideoBindings.createVideoCallScreen();
684 transaction.add(R.id.main, videoCallScreen.getVideoCallScreenFragment(), TAG_VIDEO_CALL_SCREEN);
685
686 Logger.get(this).logScreenView(ScreenEvent.Type.INCALL, this);
687 didShowVideoCallScreen = true;
688 return true;
689 }
690
691 private boolean hideVideoCallScreenFragment(FragmentTransaction transaction) {
692 if (!didShowVideoCallScreen) {
693 return false;
694 }
695 VideoCallScreen videoCallScreen = getVideoCallScreen();
696 if (videoCallScreen != null) {
697 transaction.remove(videoCallScreen.getVideoCallScreenFragment());
698 }
699 didShowVideoCallScreen = false;
700 return true;
701 }
702
703 AnswerScreen getAnswerScreen() {
704 return (AnswerScreen) getSupportFragmentManager().findFragmentByTag(TAG_ANSWER_SCREEN);
705 }
706
707 InCallScreen getInCallScreen() {
708 return (InCallScreen) getSupportFragmentManager().findFragmentByTag(TAG_IN_CALL_SCREEN);
709 }
710
711 VideoCallScreen getVideoCallScreen() {
712 return (VideoCallScreen) getSupportFragmentManager().findFragmentByTag(TAG_VIDEO_CALL_SCREEN);
713 }
714
715 @Override
716 public void onPseudoScreenStateChanged(boolean isOn) {
717 LogUtil.i("InCallActivity.onPseudoScreenStateChanged", "isOn: " + isOn);
718 pseudoBlackScreenOverlay.setVisibility(isOn ? View.GONE : View.VISIBLE);
719 }
720
721 /**
722 * For some touch related issue, turning off the screen can be faked by drawing a black view over
723 * the activity. All touch events started when the screen is "off" is rejected.
724 *
725 * @see PseudoScreenState
726 */
727 @Override
728 public boolean dispatchTouchEvent(MotionEvent event) {
729 // Reject any gesture that started when the screen is in the fake off state.
730 if (touchDownWhenPseudoScreenOff) {
731 if (event.getAction() == MotionEvent.ACTION_UP) {
732 touchDownWhenPseudoScreenOff = false;
733 }
734 return true;
735 }
736 // Reject all touch event when the screen is in the fake off state.
737 if (!InCallPresenter.getInstance().getPseudoScreenState().isOn()) {
738 if (event.getAction() == MotionEvent.ACTION_DOWN) {
739 touchDownWhenPseudoScreenOff = true;
740 LogUtil.i("InCallActivity.dispatchTouchEvent", "touchDownWhenPseudoScreenOff");
741 }
742 return true;
743 }
744 return super.dispatchTouchEvent(event);
745 }
746
747 private static class ShouldShowAnswerUiResult {
748 public final boolean shouldShow;
749 public final DialerCall call;
750
751 ShouldShowAnswerUiResult(boolean shouldShow, DialerCall call) {
752 this.shouldShow = shouldShow;
753 this.call = call;
754 }
755 }
756}