From c3968e62c44530369eb2ca73bc0f7290e53bd613 Mon Sep 17 00:00:00 2001 From: linyuh Date: Mon, 20 Nov 2017 17:40:50 -0800 Subject: Merge what's left in InCallActivityCommon into InCallActivity. Bug: 69272096 Test: None PiperOrigin-RevId: 176443652 Change-Id: I90da4789deb4b6337a38cfe010b8aee5090d35e0 --- java/com/android/incallui/InCallActivity.java | 614 +++++++++++++++++++++----- 1 file changed, 513 insertions(+), 101 deletions(-) (limited to 'java/com/android/incallui/InCallActivity.java') diff --git a/java/com/android/incallui/InCallActivity.java b/java/com/android/incallui/InCallActivity.java index 1e5a5fc02..28ff7da60 100644 --- a/java/com/android/incallui/InCallActivity.java +++ b/java/com/android/incallui/InCallActivity.java @@ -16,42 +16,56 @@ package com.android.incallui; +import android.app.ActivityManager; +import android.app.ActivityManager.AppTask; import android.app.ActivityManager.TaskDescription; import android.app.AlertDialog; import android.app.Dialog; import android.app.KeyguardManager; import android.content.Context; import android.content.Intent; +import android.content.res.Configuration; import android.graphics.drawable.GradientDrawable; import android.graphics.drawable.GradientDrawable.Orientation; import android.os.Bundle; import android.os.Trace; import android.support.annotation.ColorInt; import android.support.annotation.FloatRange; +import android.support.annotation.IntDef; import android.support.annotation.NonNull; import android.support.annotation.Nullable; +import android.support.annotation.VisibleForTesting; +import android.support.v4.app.Fragment; import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentTransaction; import android.support.v4.content.res.ResourcesCompat; import android.support.v4.graphics.ColorUtils; +import android.telecom.CallAudioState; +import android.telecom.PhoneAccountHandle; import android.telephony.TelephonyManager; import android.view.KeyEvent; import android.view.MenuItem; import android.view.MotionEvent; import android.view.View; import android.view.WindowManager; +import android.view.animation.Animation; +import android.view.animation.AnimationUtils; import android.widget.CheckBox; import android.widget.Toast; import com.android.contacts.common.widget.SelectPhoneAccountDialogFragment; +import com.android.dialer.animation.AnimUtils; +import com.android.dialer.animation.AnimationListenerAdapter; import com.android.dialer.common.Assert; import com.android.dialer.common.LogUtil; import com.android.dialer.common.concurrent.ThreadUtil; import com.android.dialer.compat.ActivityCompat; +import com.android.dialer.compat.CompatUtils; import com.android.dialer.configprovider.ConfigProviderBindings; import com.android.dialer.logging.DialerImpression; import com.android.dialer.logging.Logger; import com.android.dialer.logging.LoggingBindings; import com.android.dialer.logging.ScreenEvent; +import com.android.dialer.util.ViewUtil; import com.android.incallui.answer.bindings.AnswerBindings; import com.android.incallui.answer.protocol.AnswerScreen; import com.android.incallui.answer.protocol.AnswerScreenDelegate; @@ -76,6 +90,11 @@ import com.android.incallui.video.bindings.VideoBindings; import com.android.incallui.video.protocol.VideoCallScreen; import com.android.incallui.video.protocol.VideoCallScreenDelegate; import com.android.incallui.video.protocol.VideoCallScreenDelegateFactory; +import com.google.common.base.Optional; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.ArrayList; +import java.util.List; /** Version of {@link InCallActivity} that shows the new UI */ public class InCallActivity extends TransactionSafeFragmentActivity @@ -85,51 +104,60 @@ public class InCallActivity extends TransactionSafeFragmentActivity VideoCallScreenDelegateFactory, PseudoScreenState.StateChangedListener { - public static final int PENDING_INTENT_REQUEST_CODE_NON_FULL_SCREEN = 0; - public static final int PENDING_INTENT_REQUEST_CODE_FULL_SCREEN = 1; - public static final int PENDING_INTENT_REQUEST_CODE_BUBBLE = 2; + @Retention(RetentionPolicy.SOURCE) + @IntDef({ + DIALPAD_REQUEST_NONE, + DIALPAD_REQUEST_SHOW, + DIALPAD_REQUEST_HIDE, + }) + @interface DialpadRequestType {} - private static final String DIALPAD_TEXT_KEY = "InCallActivity.dialpad_text"; + private static final int DIALPAD_REQUEST_NONE = 1; + private static final int DIALPAD_REQUEST_SHOW = 2; + private static final int DIALPAD_REQUEST_HIDE = 3; - private static final String INTENT_EXTRA_SHOW_DIALPAD = "InCallActivity.show_dialpad"; + private static Optional audioRouteForTesting = Optional.absent(); - private static final String TAG_ANSWER_SCREEN = "tag_answer_screen"; - private static final String TAG_DIALPAD_FRAGMENT = "tag_dialpad_fragment"; - private static final String TAG_INTERNATIONAL_CALL_ON_WIFI = "tag_international_call_on_wifi"; - private static final String TAG_IN_CALL_SCREEN = "tag_in_call_screen"; - private static final String TAG_VIDEO_CALL_SCREEN = "tag_video_call_screen"; + private final InternationalCallOnWifiCallback internationalCallOnWifiCallback = + new InternationalCallOnWifiCallback(); + private final SelectPhoneAccountListener selectPhoneAccountListener = + new SelectPhoneAccountListener(); - private static final String DID_SHOW_ANSWER_SCREEN_KEY = "did_show_answer_screen"; - private static final String DID_SHOW_IN_CALL_SCREEN_KEY = "did_show_in_call_screen"; - private static final String DID_SHOW_VIDEO_CALL_SCREEN_KEY = "did_show_video_call_screen"; - - private static final String CONFIG_ANSWER_AND_RELEASE_ENABLED = "answer_and_release_enabled"; - - private final InCallActivityCommon common; + private Animation dialpadSlideInAnimation; + private Animation dialpadSlideOutAnimation; + private Dialog errorDialog; + private GradientDrawable backgroundDrawable; private InCallOrientationEventListener inCallOrientationEventListener; + private View pseudoBlackScreenOverlay; + private SelectPhoneAccountDialogFragment selectPhoneAccountDialogFragment; + private String dtmfTextToPrepopulate; + private String showPostCharWaitDialogCallId; + private String showPostCharWaitDialogChars; + private boolean allowOrientationChange; + private boolean animateDialpadOnShow; private boolean didShowAnswerScreen; private boolean didShowInCallScreen; private boolean didShowVideoCallScreen; private boolean dismissKeyguard; - private int[] backgroundDrawableColors; - private GradientDrawable backgroundDrawable; - private boolean isVisible; - private View pseudoBlackScreenOverlay; - private boolean touchDownWhenPseudoScreenOff; private boolean isInShowMainInCallFragment; + private boolean isRecreating; // whether the activity is going to be recreated + private boolean isVisible; private boolean needDismissPendingDialogs; - private boolean allowOrientationChange; - - public InCallActivity() { - common = new InCallActivityCommon(this); - } + private boolean showPostCharWaitDialogOnResume; + private boolean touchDownWhenPseudoScreenOff; + private int[] backgroundDrawableColors; + @DialpadRequestType private int showDialpadRequest = DIALPAD_REQUEST_NONE; public static Intent getIntent( Context context, boolean showDialpad, boolean newOutgoingCall, boolean isForFullScreen) { Intent intent = new Intent(Intent.ACTION_MAIN, null); intent.setFlags(Intent.FLAG_ACTIVITY_NO_USER_ACTION | Intent.FLAG_ACTIVITY_NEW_TASK); intent.setClass(context, InCallActivity.class); - InCallActivityCommon.setIntentExtras(intent, showDialpad, newOutgoingCall, isForFullScreen); + if (showDialpad) { + intent.putExtra(IntentExtraNames.SHOW_DIALPAD, true); + } + intent.putExtra(IntentExtraNames.NEW_OUTGOING_CALL, newOutgoingCall); + intent.putExtra(IntentExtraNames.FOR_FULL_SCREEN, isForFullScreen); return intent; } @@ -142,23 +170,75 @@ public class InCallActivity extends TransactionSafeFragmentActivity } @Override - protected void onCreate(Bundle icicle) { + protected void onCreate(Bundle bundle) { Trace.beginSection("InCallActivity.onCreate"); - LogUtil.i("InCallActivity.onCreate", ""); - super.onCreate(icicle); + super.onCreate(bundle); if (getIntent().getBooleanExtra(ReturnToCallController.RETURN_TO_CALL_EXTRA_KEY, false)) { Logger.get(this).logImpression(DialerImpression.Type.BUBBLE_PRIMARY_BUTTON_RETURN_TO_CALL); getIntent().removeExtra(ReturnToCallController.RETURN_TO_CALL_EXTRA_KEY); } - if (icicle != null) { - didShowAnswerScreen = icicle.getBoolean(DID_SHOW_ANSWER_SCREEN_KEY); - didShowInCallScreen = icicle.getBoolean(DID_SHOW_IN_CALL_SCREEN_KEY); - didShowVideoCallScreen = icicle.getBoolean(DID_SHOW_VIDEO_CALL_SCREEN_KEY); + if (bundle != null) { + didShowAnswerScreen = bundle.getBoolean(KeysForSavedInstance.DID_SHOW_ANSWER_SCREEN); + didShowInCallScreen = bundle.getBoolean(KeysForSavedInstance.DID_SHOW_IN_CALL_SCREEN); + didShowVideoCallScreen = bundle.getBoolean(KeysForSavedInstance.DID_SHOW_VIDEO_CALL_SCREEN); + } + + setWindowFlags(); + setContentView(R.layout.incall_screen); + internalResolveIntent(getIntent()); + + boolean isLandscape = + getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE; + boolean isRtl = ViewUtil.isRtl(); + if (isLandscape) { + dialpadSlideInAnimation = + AnimationUtils.loadAnimation( + this, isRtl ? R.anim.dialpad_slide_in_left : R.anim.dialpad_slide_in_right); + dialpadSlideOutAnimation = + AnimationUtils.loadAnimation( + this, isRtl ? R.anim.dialpad_slide_out_left : R.anim.dialpad_slide_out_right); + } else { + dialpadSlideInAnimation = AnimationUtils.loadAnimation(this, R.anim.dialpad_slide_in_bottom); + dialpadSlideOutAnimation = + AnimationUtils.loadAnimation(this, R.anim.dialpad_slide_out_bottom); + } + dialpadSlideInAnimation.setInterpolator(AnimUtils.EASE_IN); + dialpadSlideOutAnimation.setInterpolator(AnimUtils.EASE_OUT); + dialpadSlideOutAnimation.setAnimationListener( + new AnimationListenerAdapter() { + @Override + public void onAnimationEnd(Animation animation) { + hideDialpadFragment(); + } + }); + + if (bundle != null && showDialpadRequest == DIALPAD_REQUEST_NONE) { + // If the dialpad was shown before, set related variables so that it can be shown and + // populated with the previous DTMF text during onResume(). + if (bundle.containsKey(IntentExtraNames.SHOW_DIALPAD)) { + boolean showDialpad = bundle.getBoolean(IntentExtraNames.SHOW_DIALPAD); + showDialpadRequest = showDialpad ? DIALPAD_REQUEST_SHOW : DIALPAD_REQUEST_HIDE; + animateDialpadOnShow = false; + } + dtmfTextToPrepopulate = bundle.getString(KeysForSavedInstance.DIALPAD_TEXT); + + SelectPhoneAccountDialogFragment selectPhoneAccountDialogFragment = + (SelectPhoneAccountDialogFragment) + getFragmentManager().findFragmentByTag(Tags.SELECT_ACCOUNT_FRAGMENT); + if (selectPhoneAccountDialogFragment != null) { + selectPhoneAccountDialogFragment.setListener(selectPhoneAccountListener); + } + } + + InternationalCallOnWifiDialogFragment existingInternationalCallOnWifiDialogFragment = + (InternationalCallOnWifiDialogFragment) + getSupportFragmentManager().findFragmentByTag(Tags.INTERNATIONAL_CALL_ON_WIFI); + if (existingInternationalCallOnWifiDialogFragment != null) { + existingInternationalCallOnWifiDialogFragment.setCallback(internationalCallOnWifiCallback); } - common.onCreate(icicle); inCallOrientationEventListener = new InCallOrientationEventListener(this); getWindow() @@ -175,20 +255,138 @@ public class InCallActivity extends TransactionSafeFragmentActivity .logStopLatencyTimer(LoggingBindings.ON_CALL_ADDED_TO_ON_INCALL_UI_SHOWN_OUTGOING); } + private void setWindowFlags() { + // Allow the activity to be shown when the screen is locked and filter out touch events that are + // "too fat". + int flags = + WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED + | WindowManager.LayoutParams.FLAG_IGNORE_CHEEK_PRESSES; + + // When the audio stream is not directed through Bluetooth, turn the screen on once the + // activity is shown. + final int audioRoute = getAudioRoute(); + if (audioRoute != CallAudioState.ROUTE_BLUETOOTH) { + flags |= WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON; + } + + getWindow().addFlags(flags); + } + + private static int getAudioRoute() { + if (audioRouteForTesting.isPresent()) { + return audioRouteForTesting.get(); + } + + return AudioModeProvider.getInstance().getAudioState().getRoute(); + } + + @VisibleForTesting(otherwise = VisibleForTesting.NONE) + public static void setAudioRouteForTesting(int audioRoute) { + audioRouteForTesting = Optional.of(audioRoute); + } + + private void internalResolveIntent(Intent intent) { + if (!intent.getAction().equals(Intent.ACTION_MAIN)) { + return; + } + + if (intent.hasExtra(IntentExtraNames.SHOW_DIALPAD)) { + // IntentExtraNames.SHOW_DIALPAD can be used to specify whether the DTMF dialpad should be + // initially visible. If the extra is absent, leave the dialpad in its previous state. + boolean showDialpad = intent.getBooleanExtra(IntentExtraNames.SHOW_DIALPAD, false); + relaunchedFromDialer(showDialpad); + } + + DialerCall outgoingCall = CallList.getInstance().getOutgoingCall(); + if (outgoingCall == null) { + outgoingCall = CallList.getInstance().getPendingOutgoingCall(); + } + if (intent.getBooleanExtra(IntentExtraNames.NEW_OUTGOING_CALL, false)) { + intent.removeExtra(IntentExtraNames.NEW_OUTGOING_CALL); + + // InCallActivity is responsible for disconnecting a new outgoing call if there is no way of + // making it (i.e. no valid call capable accounts). + // If the version is not MSIM compatible, ignore this code. + if (CompatUtils.isMSIMCompatible() + && InCallPresenter.isCallWithNoValidAccounts(outgoingCall)) { + LogUtil.i( + "InCallActivity.internalResolveIntent", "Call with no valid accounts, disconnecting"); + outgoingCall.disconnect(); + } + + dismissKeyguard(true); + } + + if (showPhoneAccountSelectionDialog()) { + hideMainInCallFragment(); + } + } + + /** + * When relaunching from the dialer app, {@code showDialpad} indicates whether the dialpad should + * be shown on launch. + * + * @param showDialpad {@code true} to indicate the dialpad should be shown on launch, and {@code + * false} to indicate no change should be made to the dialpad visibility. + */ + private void relaunchedFromDialer(boolean showDialpad) { + showDialpadRequest = showDialpad ? DIALPAD_REQUEST_SHOW : DIALPAD_REQUEST_NONE; + animateDialpadOnShow = true; + + if (showDialpadRequest == DIALPAD_REQUEST_SHOW) { + // If there's only one line in use, AND it's on hold, then we're sure the user + // wants to use the dialpad toward the exact line, so un-hold the holding line. + DialerCall call = CallList.getInstance().getActiveOrBackgroundCall(); + if (call != null && call.getState() == State.ONHOLD) { + call.unhold(); + } + } + } + + /** + * Show a phone account selection dialog if there is a call waiting for phone account selection. + * + * @return true if the dialog was shown. + */ + private boolean showPhoneAccountSelectionDialog() { + DialerCall waitingForAccountCall = CallList.getInstance().getWaitingForAccountCall(); + if (waitingForAccountCall == null) { + return false; + } + + Bundle extras = waitingForAccountCall.getIntentExtras(); + List phoneAccountHandles = + extras == null + ? new ArrayList<>() + : extras.getParcelableArrayList(android.telecom.Call.AVAILABLE_PHONE_ACCOUNTS); + + selectPhoneAccountDialogFragment = + SelectPhoneAccountDialogFragment.newInstance( + R.string.select_phone_account_for_calls, + true /* canSetDefault */, + 0 /* setDefaultResId */, + phoneAccountHandles, + selectPhoneAccountListener, + waitingForAccountCall.getId(), + null /* hints */); + selectPhoneAccountDialogFragment.show(getFragmentManager(), Tags.SELECT_ACCOUNT_FRAGMENT); + return true; + } + @Override protected void onSaveInstanceState(Bundle out) { LogUtil.enterBlock("InCallActivity.onSaveInstanceState"); // TODO: DialpadFragment should handle this as part of its own state - out.putBoolean(INTENT_EXTRA_SHOW_DIALPAD, isDialpadVisible()); + out.putBoolean(IntentExtraNames.SHOW_DIALPAD, isDialpadVisible()); DialpadFragment dialpadFragment = getDialpadFragment(); if (dialpadFragment != null) { - out.putString(DIALPAD_TEXT_KEY, dialpadFragment.getDtmfText()); + out.putString(KeysForSavedInstance.DIALPAD_TEXT, dialpadFragment.getDtmfText()); } - out.putBoolean(DID_SHOW_ANSWER_SCREEN_KEY, didShowAnswerScreen); - out.putBoolean(DID_SHOW_IN_CALL_SCREEN_KEY, didShowInCallScreen); - out.putBoolean(DID_SHOW_VIDEO_CALL_SCREEN_KEY, didShowVideoCallScreen); + out.putBoolean(KeysForSavedInstance.DID_SHOW_ANSWER_SCREEN, didShowAnswerScreen); + out.putBoolean(KeysForSavedInstance.DID_SHOW_IN_CALL_SCREEN, didShowInCallScreen); + out.putBoolean(KeysForSavedInstance.DID_SHOW_VIDEO_CALL_SCREEN, didShowVideoCallScreen); super.onSaveInstanceState(out); isVisible = false; @@ -220,9 +418,45 @@ public class InCallActivity extends TransactionSafeFragmentActivity @Override protected void onResume() { Trace.beginSection("InCallActivity.onResume"); - LogUtil.i("InCallActivity.onResume", ""); super.onResume(); - common.onResume(); + + if (!InCallPresenter.getInstance().isReadyForTearDown()) { + updateTaskDescription(); + InCallPresenter.getInstance().onUiShowing(true); + } + + // If there is a pending request to show or hide the dialpad, handle that now. + if (showDialpadRequest != DIALPAD_REQUEST_NONE) { + if (showDialpadRequest == DIALPAD_REQUEST_SHOW) { + // Exit fullscreen so that the user has access to the dialpad hide/show button. + // This is important when showing the dialpad from within dialer. + InCallPresenter.getInstance().setFullScreen(false /* isFullScreen */, true /* force */); + + showDialpadFragment(true /* show */, animateDialpadOnShow /* animate */); + animateDialpadOnShow = false; + + DialpadFragment dialpadFragment = getDialpadFragment(); + if (dialpadFragment != null) { + dialpadFragment.setDtmfText(dtmfTextToPrepopulate); + dtmfTextToPrepopulate = null; + } + } else { + LogUtil.i("InCallActivity.onResume", "Force-hide the dialpad"); + if (getDialpadFragment() != null) { + showDialpadFragment(false /* show */, false /* animate */); + } + } + showDialpadRequest = DIALPAD_REQUEST_NONE; + } + updateNavigationBar(isDialpadVisible()); + + if (showPostCharWaitDialogOnResume) { + showDialogForPostCharWait(showPostCharWaitDialogCallId, showPostCharWaitDialogChars); + } + + CallList.getInstance() + .onInCallUiShown(getIntent().getBooleanExtra(IntentExtraNames.FOR_FULL_SCREEN, false)); + PseudoScreenState pseudoScreenState = InCallPresenter.getInstance().getPseudoScreenState(); pseudoScreenState.addListener(this); onPseudoScreenStateChanged(pseudoScreenState.isOn()); @@ -266,7 +500,7 @@ public class InCallActivity extends TransactionSafeFragmentActivity // be created. // Skip this when the screen is locked since the activity may complete its current life cycle // and restart. - if (!common.getIsRecreating() && !getSystemService(KeyguardManager.class).isKeyguardLocked()) { + if (!isRecreating && !getSystemService(KeyguardManager.class).isKeyguardLocked()) { DialerCall waitingForAccountCall = CallList.getInstance().getWaitingForAccountCall(); if (waitingForAccountCall != null) { waitingForAccountCall.disconnect(); @@ -276,8 +510,7 @@ public class InCallActivity extends TransactionSafeFragmentActivity enableInCallOrientationEventListener(false); InCallPresenter.getInstance().updateIsChangingConfigurations(); InCallPresenter.getInstance().onActivityStopped(); - if (!common.getIsRecreating()) { - Dialog errorDialog = common.getErrorDialog(); + if (!isRecreating) { if (errorDialog != null) { errorDialog.dismiss(); } @@ -319,7 +552,7 @@ public class InCallActivity extends TransactionSafeFragmentActivity } private boolean shouldCloseActivityOnFinish() { - if (!isVisible()) { + if (!isVisible) { LogUtil.i( "InCallActivity.shouldCloseActivityOnFinish", "allowing activity to be closed because it's not visible"); @@ -341,19 +574,40 @@ public class InCallActivity extends TransactionSafeFragmentActivity @Override protected void onNewIntent(Intent intent) { - LogUtil.i("InCallActivity.onNewIntent", ""); + LogUtil.enterBlock("InCallActivity.onNewIntent"); // If the screen is off, we need to make sure it gets turned on for incoming calls. // This normally works just fine thanks to FLAG_TURN_SCREEN_ON but that only works // when the activity is first created. Therefore, to ensure the screen is turned on // for the call waiting case, we recreate() the current activity. There should be no jank from // this since the screen is already off and will remain so until our new activity is up. - if (!isVisible()) { - common.onNewIntent(intent, true /* isRecreating */); + if (!isVisible) { + onNewIntent(intent, true /* isRecreating */); LogUtil.i("InCallActivity.onNewIntent", "Restarting InCallActivity to force screen on."); recreate(); } else { - common.onNewIntent(intent, false /* isRecreating */); + onNewIntent(intent, false /* isRecreating */); + } + } + + private void onNewIntent(Intent intent, boolean isRecreating) { + this.isRecreating = isRecreating; + + // We're being re-launched with a new Intent. Since it's possible for a single InCallActivity + // instance to persist indefinitely (even if we finish() ourselves), this sequence can + // happen any time the InCallActivity needs to be displayed. + + // Stash away the new intent so that we can get it in the future by calling getIntent(). + // Otherwise getIntent() will return the original Intent from when we first got created. + setIntent(intent); + + // Activities are always paused before receiving a new intent, so we can count on our onResume() + // method being called next. + + // Just like in onCreate(), handle the intent. + // Skip if InCallActivity is going to be recreated since this will be called in onCreate(). + if (!isRecreating) { + internalResolveIntent(intent); } } @@ -361,7 +615,7 @@ public class InCallActivity extends TransactionSafeFragmentActivity public void onBackPressed() { LogUtil.enterBlock("InCallActivity.onBackPressed"); - if (!isVisible()) { + if (!isVisible) { return; } @@ -483,14 +737,78 @@ public class InCallActivity extends TransactionSafeFragmentActivity } } - public boolean showDialpadFragment(boolean show, boolean animate) { - boolean didChange = common.showDialpadFragment(show, animate); - if (didChange) { - // Note: onInCallScreenDialpadVisibilityChange is called here to ensure that the dialpad FAB - // repositions itself. - getInCallScreen().onInCallScreenDialpadVisibilityChange(show); + public void showDialpadFragment(boolean show, boolean animate) { + if (show == isDialpadVisible()) { + return; + } + + FragmentManager dialpadFragmentManager = getDialpadFragmentManager(); + if (dialpadFragmentManager == null) { + LogUtil.i("InCallActivity.showDialpadFragment", "Unable to obtain a FragmentManager"); + return; + } + + if (!animate) { + if (show) { + showDialpadFragment(); + } else { + hideDialpadFragment(); + } + } else { + if (show) { + showDialpadFragment(); + getDialpadFragment().animateShowDialpad(); + } + getDialpadFragment() + .getView() + .startAnimation(show ? dialpadSlideInAnimation : dialpadSlideOutAnimation); + } + + ProximitySensor sensor = InCallPresenter.getInstance().getProximitySensor(); + if (sensor != null) { + sensor.onDialpadVisible(show); + } + showDialpadRequest = DIALPAD_REQUEST_NONE; + + // Note: onInCallScreenDialpadVisibilityChange is called here to ensure that the dialpad FAB + // repositions itself. + getInCallScreen().onInCallScreenDialpadVisibilityChange(show); + } + + private void showDialpadFragment() { + FragmentManager dialpadFragmentManager = getDialpadFragmentManager(); + if (dialpadFragmentManager == null) { + return; } - return didChange; + + FragmentTransaction transaction = dialpadFragmentManager.beginTransaction(); + DialpadFragment dialpadFragment = getDialpadFragment(); + if (dialpadFragment == null) { + transaction.add(getDialpadContainerId(), new DialpadFragment(), Tags.DIALPAD_FRAGMENT); + } else { + transaction.show(dialpadFragment); + } + transaction.commitAllowingStateLoss(); + dialpadFragmentManager.executePendingTransactions(); + + Logger.get(this).logScreenView(ScreenEvent.Type.INCALL_DIALPAD, this); + updateNavigationBar(true /* isDialpadVisible */); + } + + private void hideDialpadFragment() { + FragmentManager dialpadFragmentManager = getDialpadFragmentManager(); + if (dialpadFragmentManager == null) { + return; + } + + Fragment dialpadFragment = dialpadFragmentManager.findFragmentByTag(Tags.DIALPAD_FRAGMENT); + if (dialpadFragment != null) { + FragmentTransaction transaction = dialpadFragmentManager.beginTransaction(); + transaction.hide(dialpadFragment); + transaction.commitAllowingStateLoss(); + dialpadFragmentManager.executePendingTransactions(); + } + updateNavigationBar(false /* isDialpadVisible */); } public boolean isDialpadVisible() { @@ -498,17 +816,14 @@ public class InCallActivity extends TransactionSafeFragmentActivity return dialpadFragment != null && dialpadFragment.isVisible(); } - /** - * Returns the {@link DialpadFragment} that's shown by this activity, or {@code null} - * TODO(a bug): Make this method private after InCallActivityCommon is deleted. - */ + /** Returns the {@link DialpadFragment} that's shown by this activity, or {@code null} */ @Nullable - DialpadFragment getDialpadFragment() { + private DialpadFragment getDialpadFragment() { FragmentManager fragmentManager = getDialpadFragmentManager(); if (fragmentManager == null) { return null; } - return (DialpadFragment) fragmentManager.findFragmentByTag(TAG_DIALPAD_FRAGMENT); + return (DialpadFragment) fragmentManager.findFragmentByTag(Tags.DIALPAD_FRAGMENT); } public void onForegroundCallChanged(DialerCall newForegroundCall) { @@ -520,8 +835,7 @@ public class InCallActivity extends TransactionSafeFragmentActivity } } - // TODO(a bug): Make this method private after InCallActivityCommon is deleted. - void updateTaskDescription() { + private void updateTaskDescription() { int color = getResources().getBoolean(R.bool.is_layout_landscape) ? ResourcesCompat.getColor( @@ -605,8 +919,19 @@ public class InCallActivity extends TransactionSafeFragmentActivity } } - public void showPostCharWaitDialog(String callId, String chars) { - common.showPostCharWaitDialog(callId, chars); + public void showDialogForPostCharWait(String callId, String chars) { + if (isVisible) { + PostCharDialogFragment fragment = new PostCharDialogFragment(callId, chars); + fragment.show(getSupportFragmentManager(), Tags.POST_CHAR_DIALOG_FRAGMENT); + + showPostCharWaitDialogOnResume = false; + showPostCharWaitDialogCallId = null; + showPostCharWaitDialogChars = null; + } else { + showPostCharWaitDialogOnResume = true; + showPostCharWaitDialogCallId = callId; + showPostCharWaitDialogChars = chars; + } } public void showDialogOrToastForDisconnectedCall(DisconnectMessage disconnectMessage) { @@ -629,7 +954,7 @@ public class InCallActivity extends TransactionSafeFragmentActivity } // Show the dialog. - common.setErrorDialog(disconnectMessage.dialog); + errorDialog = disconnectMessage.dialog; InCallUiLock lock = InCallPresenter.getInstance().acquireInCallUiLock("showErrorDialog"); disconnectMessage.dialog.setOnDismissListener( dialogInterface -> { @@ -641,12 +966,12 @@ public class InCallActivity extends TransactionSafeFragmentActivity } private void onDialogDismissed() { - common.setErrorDialog(null); + errorDialog = null; CallList.getInstance().onErrorDialogDismissed(); } public void dismissPendingDialogs() { - LogUtil.i("InCallActivity.dismissPendingDialogs", ""); + LogUtil.enterBlock("InCallActivity.dismissPendingDialogs"); if (!isVisible) { // Defer the dismissing action as the activity is not visible and onSaveInstanceState may have @@ -658,24 +983,21 @@ public class InCallActivity extends TransactionSafeFragmentActivity } // Dismiss the error dialog - Dialog errorDialog = common.getErrorDialog(); if (errorDialog != null) { errorDialog.dismiss(); - common.setErrorDialog(null); + errorDialog = null; } // Dismiss the phone account selection dialog - SelectPhoneAccountDialogFragment selectPhoneAccountDialogFragment = - common.getSelectPhoneAccountDialogFragment(); if (selectPhoneAccountDialogFragment != null) { selectPhoneAccountDialogFragment.dismiss(); - common.setSelectPhoneAccountDialogFragment(null); + selectPhoneAccountDialogFragment = null; } // Dismiss the dialog for international call on WiFi InternationalCallOnWifiDialogFragment internationalCallOnWifiFragment = (InternationalCallOnWifiDialogFragment) - getSupportFragmentManager().findFragmentByTag(TAG_INTERNATIONAL_CALL_ON_WIFI); + getSupportFragmentManager().findFragmentByTag(Tags.INTERNATIONAL_CALL_ON_WIFI); if (internationalCallOnWifiFragment != null) { internationalCallOnWifiFragment.dismiss(); } @@ -689,8 +1011,7 @@ public class InCallActivity extends TransactionSafeFragmentActivity needDismissPendingDialogs = false; } - // TODO(a bug): Make this method private after InCallActivityCommon is deleted. - void enableInCallOrientationEventListener(boolean enable) { + private void enableInCallOrientationEventListener(boolean enable) { if (enable) { inCallOrientationEventListener.enable(true /* notifyDeviceOrientationChange */); } else { @@ -699,7 +1020,18 @@ public class InCallActivity extends TransactionSafeFragmentActivity } public void setExcludeFromRecents(boolean exclude) { - common.setExcludeFromRecents(exclude); + int taskId = getTaskId(); + + List tasks = getSystemService(ActivityManager.class).getAppTasks(); + for (AppTask task : tasks) { + try { + if (task.getTaskInfo().id == taskId) { + task.setExcludeFromRecents(exclude); + } + } catch (RuntimeException e) { + LogUtil.e("InCallActivity.setExcludeFromRecents", "RuntimeException:\n%s", e); + } + } } @Nullable @@ -756,7 +1088,6 @@ public class InCallActivity extends TransactionSafeFragmentActivity public void onPrimaryCallStateChanged() { Trace.beginSection("InCallActivity.onPrimaryCallStateChanged"); - LogUtil.i("InCallActivity.onPrimaryCallStateChanged", ""); showMainInCallFragment(); Trace.endSection(); } @@ -790,7 +1121,7 @@ public class InCallActivity extends TransactionSafeFragmentActivity wifiHandoverFailureCheckbox.setChecked(false); InCallUiLock lock = InCallPresenter.getInstance().acquireInCallUiLock("WifiFailedDialog"); - Dialog errorDialog = + errorDialog = builder .setView(dialogCheckBoxView) .setMessage(R.string.video_call_lte_to_wifi_failed_message) @@ -805,8 +1136,6 @@ public class InCallActivity extends TransactionSafeFragmentActivity }) .setOnDismissListener(dialogInterface -> lock.release()) .create(); - - common.setErrorDialog(errorDialog); errorDialog.show(); } @@ -820,8 +1149,8 @@ public class InCallActivity extends TransactionSafeFragmentActivity InternationalCallOnWifiDialogFragment fragment = InternationalCallOnWifiDialogFragment.newInstance( - call.getId(), common.getCallbackForInternationalCallOnWifiDialog()); - fragment.show(getSupportFragmentManager(), TAG_INTERNATIONAL_CALL_ON_WIFI); + call.getId(), internationalCallOnWifiCallback); + fragment.show(getSupportFragmentManager(), Tags.INTERNATIONAL_CALL_ON_WIFI); } @Override @@ -830,8 +1159,7 @@ public class InCallActivity extends TransactionSafeFragmentActivity updateNavigationBar(isDialpadVisible()); } - // TODO(a bug): Make this method private after InCallActivityCommon is deleted. - void updateNavigationBar(boolean isDialpadVisible) { + private void updateNavigationBar(boolean isDialpadVisible) { if (ActivityCompat.isInMultiWindowMode(this)) { return; } @@ -856,8 +1184,8 @@ public class InCallActivity extends TransactionSafeFragmentActivity } public void hideMainInCallFragment() { - LogUtil.i("InCallActivity.hideMainInCallFragment", ""); - if (didShowInCallScreen || didShowVideoCallScreen) { + LogUtil.enterBlock("InCallActivity.hideMainInCallFragment"); + if (getCallCardFragmentVisible()) { FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); hideInCallScreenFragment(transaction); hideVideoCallScreenFragment(transaction); @@ -1017,7 +1345,7 @@ public class InCallActivity extends TransactionSafeFragmentActivity call.getVideoTech().isSelfManagedCamera(), shouldAllowAnswerAndRelease(call), CallList.getInstance().getBackgroundCall() != null); - transaction.add(R.id.main, answerScreen.getAnswerScreenFragment(), TAG_ANSWER_SCREEN); + transaction.add(R.id.main, answerScreen.getAnswerScreenFragment(), Tags.ANSWER_SCREEN); Logger.get(this).logScreenView(ScreenEvent.Type.INCOMING_CALL, this); didShowAnswerScreen = true; @@ -1038,7 +1366,8 @@ public class InCallActivity extends TransactionSafeFragmentActivity LogUtil.i("InCallActivity.shouldAllowAnswerAndRelease", "video call"); return false; } - if (!ConfigProviderBindings.get(this).getBoolean(CONFIG_ANSWER_AND_RELEASE_ENABLED, true)) { + if (!ConfigProviderBindings.get(this) + .getBoolean(ConfigNames.ANSWER_AND_RELEASE_ENABLED, true)) { LogUtil.i("InCallActivity.shouldAllowAnswerAndRelease", "disabled by config"); return false; } @@ -1064,7 +1393,7 @@ public class InCallActivity extends TransactionSafeFragmentActivity return false; } InCallScreen inCallScreen = InCallBindings.createInCallScreen(); - transaction.add(R.id.main, inCallScreen.getInCallScreenFragment(), TAG_IN_CALL_SCREEN); + transaction.add(R.id.main, inCallScreen.getInCallScreenFragment(), Tags.IN_CALL_SCREEN); Logger.get(this).logScreenView(ScreenEvent.Type.INCALL, this); didShowInCallScreen = true; return true; @@ -1099,7 +1428,8 @@ public class InCallActivity extends TransactionSafeFragmentActivity VideoCallScreen videoCallScreen = VideoBindings.createVideoCallScreen( call.getId(), call.getVideoTech().shouldUseSurfaceView()); - transaction.add(R.id.main, videoCallScreen.getVideoCallScreenFragment(), TAG_VIDEO_CALL_SCREEN); + transaction.add( + R.id.main, videoCallScreen.getVideoCallScreenFragment(), Tags.VIDEO_CALL_SCREEN); Logger.get(this).logScreenView(ScreenEvent.Type.INCALL, this); didShowVideoCallScreen = true; @@ -1118,16 +1448,16 @@ public class InCallActivity extends TransactionSafeFragmentActivity return true; } - AnswerScreen getAnswerScreen() { - return (AnswerScreen) getSupportFragmentManager().findFragmentByTag(TAG_ANSWER_SCREEN); + private AnswerScreen getAnswerScreen() { + return (AnswerScreen) getSupportFragmentManager().findFragmentByTag(Tags.ANSWER_SCREEN); } - InCallScreen getInCallScreen() { - return (InCallScreen) getSupportFragmentManager().findFragmentByTag(TAG_IN_CALL_SCREEN); + private InCallScreen getInCallScreen() { + return (InCallScreen) getSupportFragmentManager().findFragmentByTag(Tags.IN_CALL_SCREEN); } - VideoCallScreen getVideoCallScreen() { - return (VideoCallScreen) getSupportFragmentManager().findFragmentByTag(TAG_VIDEO_CALL_SCREEN); + private VideoCallScreen getVideoCallScreen() { + return (VideoCallScreen) getSupportFragmentManager().findFragmentByTag(Tags.VIDEO_CALL_SCREEN); } @Override @@ -1171,4 +1501,86 @@ public class InCallActivity extends TransactionSafeFragmentActivity this.call = call; } } + + private static final class IntentExtraNames { + static final String FOR_FULL_SCREEN = "InCallActivity.for_full_screen_intent"; + static final String NEW_OUTGOING_CALL = "InCallActivity.new_outgoing_call"; + static final String SHOW_DIALPAD = "InCallActivity.show_dialpad"; + } + + private static final class KeysForSavedInstance { + static final String DIALPAD_TEXT = "InCallActivity.dialpad_text"; + static final String DID_SHOW_ANSWER_SCREEN = "did_show_answer_screen"; + static final String DID_SHOW_IN_CALL_SCREEN = "did_show_in_call_screen"; + static final String DID_SHOW_VIDEO_CALL_SCREEN = "did_show_video_call_screen"; + } + + /** Request codes for pending intents. */ + public static final class PendingIntentRequestCodes { + static final int NON_FULL_SCREEN = 0; + static final int FULL_SCREEN = 1; + static final int BUBBLE = 2; + } + + private static final class Tags { + static final String ANSWER_SCREEN = "tag_answer_screen"; + static final String DIALPAD_FRAGMENT = "tag_dialpad_fragment"; + static final String IN_CALL_SCREEN = "tag_in_call_screen"; + static final String INTERNATIONAL_CALL_ON_WIFI = "tag_international_call_on_wifi"; + static final String SELECT_ACCOUNT_FRAGMENT = "tag_select_account_fragment"; + static final String VIDEO_CALL_SCREEN = "tag_video_call_screen"; + static final String POST_CHAR_DIALOG_FRAGMENT = "tag_post_char_dialog_fragment"; + } + + private static final class ConfigNames { + static final String ANSWER_AND_RELEASE_ENABLED = "answer_and_release_enabled"; + } + + private static final class InternationalCallOnWifiCallback + implements InternationalCallOnWifiDialogFragment.Callback { + private static final String TAG = InternationalCallOnWifiCallback.class.getCanonicalName(); + + @Override + public void continueCall(@NonNull String callId) { + LogUtil.i(TAG, "Continuing call with ID: %s", callId); + } + + @Override + public void cancelCall(@NonNull String callId) { + DialerCall call = CallList.getInstance().getCallById(callId); + if (call == null) { + LogUtil.i(TAG, "Call destroyed before the dialog is closed"); + return; + } + + LogUtil.i(TAG, "Disconnecting international call on WiFi"); + call.disconnect(); + } + } + + private static final class SelectPhoneAccountListener + extends SelectPhoneAccountDialogFragment.SelectPhoneAccountListener { + private static final String TAG = SelectPhoneAccountListener.class.getCanonicalName(); + + @Override + public void onPhoneAccountSelected( + PhoneAccountHandle selectedAccountHandle, boolean setDefault, String callId) { + DialerCall call = CallList.getInstance().getCallById(callId); + LogUtil.i(TAG, "Phone account select with call:\n%s", call); + + if (call != null) { + call.phoneAccountSelected(selectedAccountHandle, setDefault); + } + } + + @Override + public void onDialogDismissed(String callId) { + DialerCall call = CallList.getInstance().getCallById(callId); + LogUtil.i(TAG, "Disconnecting call:\n%s" + call); + + if (call != null) { + call.disconnect(); + } + } + } } -- cgit v1.2.3