/* * Copyright (C) 2016 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.incallui; import android.app.ActivityManager; import android.app.ActivityManager.AppTask; import android.app.ActivityManager.TaskDescription; import android.app.Dialog; import android.app.KeyguardManager; import android.content.Intent; import android.content.res.Configuration; import android.content.res.Resources; import android.os.Bundle; import android.os.Trace; 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.telecom.CallAudioState; import android.telecom.PhoneAccountHandle; import android.view.KeyEvent; import android.view.View; import android.view.Window; import android.view.WindowManager; import android.view.animation.Animation; import android.view.animation.AnimationUtils; import com.android.contacts.common.widget.SelectPhoneAccountDialogFragment; import com.android.contacts.common.widget.SelectPhoneAccountDialogFragment.SelectPhoneAccountListener; import com.android.dialer.animation.AnimUtils; import com.android.dialer.animation.AnimationListenerAdapter; import com.android.dialer.common.LogUtil; import com.android.dialer.compat.ActivityCompat; import com.android.dialer.compat.CompatUtils; import com.android.dialer.logging.Logger; import com.android.dialer.logging.ScreenEvent; import com.android.dialer.util.ViewUtil; import com.android.incallui.audiomode.AudioModeProvider; import com.android.incallui.call.CallList; import com.android.incallui.call.DialerCall; import com.android.incallui.call.DialerCall.State; import com.android.incallui.call.TelecomAdapter; import com.android.incallui.telecomeventui.InternationalCallOnWifiDialogFragment; import com.android.incallui.telecomeventui.InternationalCallOnWifiDialogFragment.Callback; import com.google.common.base.Optional; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.List; /** Shared functionality between the new and old in call activity. */ public class InCallActivityCommon { private static final String INTENT_EXTRA_SHOW_DIALPAD = "InCallActivity.show_dialpad"; private static final String INTENT_EXTRA_NEW_OUTGOING_CALL = "InCallActivity.new_outgoing_call"; private static final String INTENT_EXTRA_FOR_FULL_SCREEN = "InCallActivity.for_full_screen_intent"; private static final String DIALPAD_TEXT_KEY = "InCallActivity.dialpad_text"; private static final String TAG_SELECT_ACCOUNT_FRAGMENT = "tag_select_account_fragment"; private static final String TAG_DIALPAD_FRAGMENT = "tag_dialpad_fragment"; private static final String TAG_INTERNATIONAL_CALL_ON_WIFI = "tag_international_call_on_wifi"; @Retention(RetentionPolicy.SOURCE) @IntDef({ DIALPAD_REQUEST_NONE, DIALPAD_REQUEST_SHOW, DIALPAD_REQUEST_HIDE, }) @interface DialpadRequestType {} 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 Optional audioRouteForTesting = Optional.absent(); private final InCallActivity inCallActivity; private boolean showPostCharWaitDialogOnResume; private String showPostCharWaitDialogCallId; private String showPostCharWaitDialogChars; private Dialog errorDialog; private SelectPhoneAccountDialogFragment selectPhoneAccountDialogFragment; private Animation dialpadSlideInAnimation; private Animation dialpadSlideOutAnimation; private boolean animateDialpadOnShow; private String dtmfTextToPreopulate; @DialpadRequestType private int showDialpadRequest = DIALPAD_REQUEST_NONE; // If activity is going to be recreated. This is usually happening in {@link onNewIntent}. private boolean isRecreating; private final SelectPhoneAccountListener selectAccountListener = new SelectPhoneAccountListener() { @Override public void onPhoneAccountSelected( PhoneAccountHandle selectedAccountHandle, boolean setDefault, String callId) { DialerCall call = CallList.getInstance().getCallById(callId); LogUtil.i( "InCallActivityCommon.SelectPhoneAccountListener.onPhoneAccountSelected", "call: " + call); if (call != null) { call.phoneAccountSelected(selectedAccountHandle, setDefault); } } @Override public void onDialogDismissed(String callId) { DialerCall call = CallList.getInstance().getCallById(callId); LogUtil.i( "InCallActivityCommon.SelectPhoneAccountListener.onDialogDismissed", "disconnecting call: " + call); if (call != null) { call.disconnect(); } } }; private InternationalCallOnWifiDialogFragment.Callback internationalCallOnWifiCallback = new Callback() { @Override public void continueCall(@NonNull String callId) { LogUtil.i("InCallActivityCommon.continueCall", "continuing call with id: %s", callId); } @Override public void cancelCall(@NonNull String callId) { DialerCall call = CallList.getInstance().getCallById(callId); if (call == null) { LogUtil.i("InCallActivityCommon.cancelCall", "call destroyed before dialog closed"); return; } LogUtil.i("InCallActivityCommon.cancelCall", "disconnecting international call on wifi"); call.disconnect(); } }; public static void setIntentExtras( Intent intent, boolean showDialpad, boolean newOutgoingCall, boolean isForFullScreen) { if (showDialpad) { intent.putExtra(INTENT_EXTRA_SHOW_DIALPAD, true); } intent.putExtra(INTENT_EXTRA_NEW_OUTGOING_CALL, newOutgoingCall); intent.putExtra(INTENT_EXTRA_FOR_FULL_SCREEN, isForFullScreen); } public InCallActivityCommon(InCallActivity inCallActivity) { this.inCallActivity = inCallActivity; } public void onCreate(Bundle icicle) { setWindowFlags(); inCallActivity.setContentView(R.layout.incall_screen); internalResolveIntent(inCallActivity.getIntent()); boolean isLandscape = inCallActivity.getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE; boolean isRtl = ViewUtil.isRtl(); if (isLandscape) { dialpadSlideInAnimation = AnimationUtils.loadAnimation( inCallActivity, isRtl ? R.anim.dialpad_slide_in_left : R.anim.dialpad_slide_in_right); dialpadSlideOutAnimation = AnimationUtils.loadAnimation( inCallActivity, isRtl ? R.anim.dialpad_slide_out_left : R.anim.dialpad_slide_out_right); } else { dialpadSlideInAnimation = AnimationUtils.loadAnimation(inCallActivity, R.anim.dialpad_slide_in_bottom); dialpadSlideOutAnimation = AnimationUtils.loadAnimation(inCallActivity, 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) { performHideDialpadFragment(); } }); // Don't override the value if show dialpad request is true in intent extras. if (icicle != null && showDialpadRequest == DIALPAD_REQUEST_NONE) { // If the dialpad was shown before, set variables indicating it should be shown and // populated with the previous DTMF text. The dialpad is actually shown and populated // in onResume() to ensure the hosting fragment has been inflated and is ready to receive it. if (icicle.containsKey(INTENT_EXTRA_SHOW_DIALPAD)) { boolean showDialpad = icicle.getBoolean(INTENT_EXTRA_SHOW_DIALPAD); showDialpadRequest = showDialpad ? DIALPAD_REQUEST_SHOW : DIALPAD_REQUEST_HIDE; animateDialpadOnShow = false; } dtmfTextToPreopulate = icicle.getString(DIALPAD_TEXT_KEY); SelectPhoneAccountDialogFragment dialogFragment = (SelectPhoneAccountDialogFragment) inCallActivity.getFragmentManager().findFragmentByTag(TAG_SELECT_ACCOUNT_FRAGMENT); if (dialogFragment != null) { dialogFragment.setListener(selectAccountListener); } } InternationalCallOnWifiDialogFragment existingInternationalFragment = (InternationalCallOnWifiDialogFragment) inCallActivity .getSupportFragmentManager() .findFragmentByTag(TAG_INTERNATIONAL_CALL_ON_WIFI); if (existingInternationalFragment != null) { LogUtil.i( "InCallActivityCommon.onCreate", "international fragment exists attaching callback"); existingInternationalFragment.setCallback(internationalCallOnWifiCallback); } } public void onSaveInstanceState(Bundle out) { // TODO: The dialpad fragment should handle this as part of its own state out.putBoolean(INTENT_EXTRA_SHOW_DIALPAD, inCallActivity.isDialpadVisible()); DialpadFragment dialpadFragment = inCallActivity.getDialpadFragment(); if (dialpadFragment != null) { out.putString(DIALPAD_TEXT_KEY, dialpadFragment.getDtmfText()); } } public void onStart() { Trace.beginSection("InCallActivityCommon.onStart"); // setting activity should be last thing in setup process InCallPresenter.getInstance().setActivity(inCallActivity); inCallActivity.enableInCallOrientationEventListener( inCallActivity.getRequestedOrientation() == InCallOrientationEventListener.ACTIVITY_PREFERENCE_ALLOW_ROTATION); InCallPresenter.getInstance().onActivityStarted(); Trace.endSection(); } public void onResume() { Trace.beginSection("InCallActivityCommon.onResume"); if (InCallPresenter.getInstance().isReadyForTearDown()) { LogUtil.i( "InCallActivityCommon.onResume", "InCallPresenter is ready for tear down, not sending updates"); } else { 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 and // can hide the dialpad. Important when showing the dialpad from within dialer. InCallPresenter.getInstance().setFullScreen(false, true /* force */); inCallActivity.showDialpadFragment(true /* show */, animateDialpadOnShow /* animate */); animateDialpadOnShow = false; DialpadFragment dialpadFragment = inCallActivity.getDialpadFragment(); if (dialpadFragment != null) { dialpadFragment.setDtmfText(dtmfTextToPreopulate); dtmfTextToPreopulate = null; } } else { LogUtil.i("InCallActivityCommon.onResume", "force hide dialpad"); if (inCallActivity.getDialpadFragment() != null) { inCallActivity.showDialpadFragment(false /* show */, false /* animate */); } } showDialpadRequest = DIALPAD_REQUEST_NONE; } updateNavigationBar(inCallActivity.isDialpadVisible()); if (showPostCharWaitDialogOnResume) { showPostCharWaitDialog(showPostCharWaitDialogCallId, showPostCharWaitDialogChars); } CallList.getInstance() .onInCallUiShown( inCallActivity.getIntent().getBooleanExtra(INTENT_EXTRA_FOR_FULL_SCREEN, false)); Trace.endSection(); } // onPause is guaranteed to be called when the InCallActivity goes // in the background. public void onPause() { DialpadFragment dialpadFragment = inCallActivity.getDialpadFragment(); if (dialpadFragment != null) { dialpadFragment.onDialerKeyUp(null); } InCallPresenter.getInstance().onUiShowing(false); if (inCallActivity.isFinishing()) { InCallPresenter.getInstance().unsetActivity(inCallActivity); } } public void onStop() { // Disconnects call waiting for account when activity is hidden e.g. user press home button. // This is necessary otherwise the pending call will stuck on account choose and no new call // will be able to create. See a bug for more details. // Skip this on locked screen since the activity may go over life cycle and start again. if (!isRecreating && !inCallActivity.getSystemService(KeyguardManager.class).isKeyguardLocked()) { DialerCall waitingForAccountCall = CallList.getInstance().getWaitingForAccountCall(); if (waitingForAccountCall != null) { waitingForAccountCall.disconnect(); } } inCallActivity.enableInCallOrientationEventListener(false); InCallPresenter.getInstance().updateIsChangingConfigurations(); InCallPresenter.getInstance().onActivityStopped(); if (!isRecreating) { if (errorDialog != null) { errorDialog.dismiss(); } } } public void onDestroy() { InCallPresenter.getInstance().unsetActivity(inCallActivity); InCallPresenter.getInstance().updateIsChangingConfigurations(); } void onNewIntent(Intent intent, boolean isRecreating) { LogUtil.i("InCallActivityCommon.onNewIntent", ""); 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 potentially 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!) inCallActivity.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 recreate since this will be called in onCreate(). if (!isRecreating) { internalResolveIntent(intent); } } public boolean onBackPressed(boolean isInCallScreenVisible) { LogUtil.i("InCallActivityCommon.onBackPressed", ""); // BACK is also used to exit out of any "special modes" of the // in-call UI: if (!inCallActivity.isVisible()) { return true; } if (!isInCallScreenVisible) { return true; } DialpadFragment dialpadFragment = inCallActivity.getDialpadFragment(); if (dialpadFragment != null && dialpadFragment.isVisible()) { inCallActivity.showDialpadFragment(false /* show */, true /* animate */); return true; } // Always disable the Back key while an incoming call is ringing DialerCall call = CallList.getInstance().getIncomingCall(); if (call != null) { LogUtil.i("InCallActivityCommon.onBackPressed", "consume Back press for an incoming call"); return true; } // Nothing special to do. Fall back to the default behavior. return false; } public boolean onKeyUp(int keyCode, KeyEvent event) { DialpadFragment dialpadFragment = inCallActivity.getDialpadFragment(); // push input to the dialer. if (dialpadFragment != null && (dialpadFragment.isVisible()) && (dialpadFragment.onDialerKeyUp(event))) { return true; } else if (keyCode == KeyEvent.KEYCODE_CALL) { // Always consume CALL to be sure the PhoneWindow won't do anything with it return true; } return false; } public boolean onKeyDown(int keyCode, KeyEvent event) { switch (keyCode) { case KeyEvent.KEYCODE_CALL: boolean handled = InCallPresenter.getInstance().handleCallKey(); if (!handled) { LogUtil.e( "InCallActivityCommon.onKeyDown", "InCallPresenter should always handle KEYCODE_CALL in onKeyDown"); } // Always consume CALL to be sure the PhoneWindow won't do anything with it return true; // Note there's no KeyEvent.KEYCODE_ENDCALL case here. // The standard system-wide handling of the ENDCALL key // (see PhoneWindowManager's handling of KEYCODE_ENDCALL) // already implements exactly what the UI spec wants, // namely (1) "hang up" if there's a current active call, // or (2) "don't answer" if there's a current ringing call. case KeyEvent.KEYCODE_CAMERA: // Disable the CAMERA button while in-call since it's too // easy to press accidentally. return true; case KeyEvent.KEYCODE_VOLUME_UP: case KeyEvent.KEYCODE_VOLUME_DOWN: case KeyEvent.KEYCODE_VOLUME_MUTE: // Ringer silencing handled by PhoneWindowManager. break; case KeyEvent.KEYCODE_MUTE: TelecomAdapter.getInstance() .mute(!AudioModeProvider.getInstance().getAudioState().isMuted()); return true; // Various testing/debugging features, enabled ONLY when VERBOSE == true. case KeyEvent.KEYCODE_SLASH: if (LogUtil.isVerboseEnabled()) { LogUtil.v( "InCallActivityCommon.onKeyDown", "----------- InCallActivity View dump --------------"); // Dump starting from the top-level view of the entire activity: Window w = inCallActivity.getWindow(); View decorView = w.getDecorView(); LogUtil.v("InCallActivityCommon.onKeyDown", "View dump:" + decorView); return true; } break; case KeyEvent.KEYCODE_EQUALS: break; default: // fall out } return event.getRepeatCount() == 0 && handleDialerKeyDown(keyCode, event); } 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; } inCallActivity.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 boolean handleDialerKeyDown(int keyCode, KeyEvent event) { LogUtil.v("InCallActivityCommon.handleDialerKeyDown", "keyCode %d, event: %s", keyCode, event); // As soon as the user starts typing valid dialable keys on the // keyboard (presumably to type DTMF tones) we start passing the // key events to the DTMFDialer's onDialerKeyDown. DialpadFragment dialpadFragment = inCallActivity.getDialpadFragment(); if (dialpadFragment != null && dialpadFragment.isVisible()) { return dialpadFragment.onDialerKeyDown(event); } return false; } public void showPostCharWaitDialog(String callId, String chars) { if (inCallActivity.isVisible()) { PostCharDialogFragment fragment = new PostCharDialogFragment(callId, chars); fragment.show(inCallActivity.getSupportFragmentManager(), "postCharWait"); showPostCharWaitDialogOnResume = false; showPostCharWaitDialogCallId = null; showPostCharWaitDialogChars = null; } else { showPostCharWaitDialogOnResume = true; showPostCharWaitDialogCallId = callId; showPostCharWaitDialogChars = chars; } } /** * 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(); } } } public void setExcludeFromRecents(boolean exclude) { List tasks = inCallActivity.getSystemService(ActivityManager.class).getAppTasks(); int taskId = inCallActivity.getTaskId(); for (int i = 0; i < tasks.size(); i++) { ActivityManager.AppTask task = tasks.get(i); try { if (task.getTaskInfo().id == taskId) { task.setExcludeFromRecents(exclude); } } catch (RuntimeException e) { LogUtil.e( "InCallActivityCommon.setExcludeFromRecents", "RuntimeException when excluding task from recents.", e); } } } void updateNavigationBar(boolean isDialpadVisible) { if (!ActivityCompat.isInMultiWindowMode(inCallActivity)) { View navigationBarBackground = inCallActivity.getWindow().findViewById(R.id.navigation_bar_background); if (navigationBarBackground != null) { navigationBarBackground.setVisibility(isDialpadVisible ? View.VISIBLE : View.GONE); } } } public boolean showDialpadFragment(boolean show, boolean animate) { // If the dialpad is already visible, don't animate in. If it's gone, don't animate out. boolean isDialpadVisible = inCallActivity.isDialpadVisible(); LogUtil.i( "InCallActivityCommon.showDialpadFragment", "show: %b, animate: %b, " + "isDialpadVisible: %b", show, animate, isDialpadVisible); if (show == isDialpadVisible) { return false; } FragmentManager dialpadFragmentManager = inCallActivity.getDialpadFragmentManager(); if (dialpadFragmentManager == null) { LogUtil.i( "InCallActivityCommon.showDialpadFragment", "unable to show or hide dialpad fragment"); return false; } // We don't do a FragmentTransaction on the hide case because it will be dealt with when // the listener is fired after an animation finishes. if (!animate) { if (show) { performShowDialpadFragment(dialpadFragmentManager); } else { performHideDialpadFragment(); } } else { if (show) { performShowDialpadFragment(dialpadFragmentManager); inCallActivity.getDialpadFragment().animateShowDialpad(); } inCallActivity .getDialpadFragment() .getView() .startAnimation(show ? dialpadSlideInAnimation : dialpadSlideOutAnimation); } ProximitySensor sensor = InCallPresenter.getInstance().getProximitySensor(); if (sensor != null) { sensor.onDialpadVisible(show); } showDialpadRequest = DIALPAD_REQUEST_NONE; return true; } private void performShowDialpadFragment(@NonNull FragmentManager dialpadFragmentManager) { FragmentTransaction transaction = dialpadFragmentManager.beginTransaction(); DialpadFragment dialpadFragment = inCallActivity.getDialpadFragment(); if (dialpadFragment == null) { transaction.add( inCallActivity.getDialpadContainerId(), new DialpadFragment(), TAG_DIALPAD_FRAGMENT); } else { transaction.show(dialpadFragment); } transaction.commitAllowingStateLoss(); dialpadFragmentManager.executePendingTransactions(); Logger.get(inCallActivity).logScreenView(ScreenEvent.Type.INCALL_DIALPAD, inCallActivity); updateNavigationBar(true /* isDialpadVisible */); } private void performHideDialpadFragment() { FragmentManager fragmentManager = inCallActivity.getDialpadFragmentManager(); if (fragmentManager == null) { LogUtil.e( "InCallActivityCommon.performHideDialpadFragment", "child fragment manager is null"); return; } Fragment fragment = fragmentManager.findFragmentByTag(TAG_DIALPAD_FRAGMENT); if (fragment != null) { FragmentTransaction transaction = fragmentManager.beginTransaction(); transaction.hide(fragment); transaction.commitAllowingStateLoss(); fragmentManager.executePendingTransactions(); } updateNavigationBar(false /* isDialpadVisible */); } public void updateTaskDescription() { Resources resources = inCallActivity.getResources(); int color; if (resources.getBoolean(R.bool.is_layout_landscape)) { color = ResourcesCompat.getColor( resources, R.color.statusbar_background_color, inCallActivity.getTheme()); } else { color = InCallPresenter.getInstance().getThemeColorManager().getSecondaryColor(); } TaskDescription td = new TaskDescription(resources.getString(R.string.notification_ongoing_call), null, color); inCallActivity.setTaskDescription(td); } private void internalResolveIntent(Intent intent) { if (!intent.getAction().equals(Intent.ACTION_MAIN)) { return; } if (intent.hasExtra(INTENT_EXTRA_SHOW_DIALPAD)) { // SHOW_DIALPAD_EXTRA can be used here to specify whether the DTMF // dialpad should be initially visible. If the extra isn't // present at all, we just leave the dialpad in its previous state. boolean showDialpad = intent.getBooleanExtra(INTENT_EXTRA_SHOW_DIALPAD, false); LogUtil.i("InCallActivityCommon.internalResolveIntent", "SHOW_DIALPAD_EXTRA: " + showDialpad); relaunchedFromDialer(showDialpad); } DialerCall outgoingCall = CallList.getInstance().getOutgoingCall(); if (outgoingCall == null) { outgoingCall = CallList.getInstance().getPendingOutgoingCall(); } if (intent.getBooleanExtra(INTENT_EXTRA_NEW_OUTGOING_CALL, false)) { intent.removeExtra(INTENT_EXTRA_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, then ignore this code. if (CompatUtils.isMSIMCompatible() && InCallPresenter.isCallWithNoValidAccounts(outgoingCall)) { LogUtil.i( "InCallActivityCommon.internalResolveIntent", "call with no valid accounts, disconnecting"); outgoingCall.disconnect(); } inCallActivity.dismissKeyguard(true); } boolean didShowAccountSelectionDialog = maybeShowAccountSelectionDialog(); if (didShowAccountSelectionDialog) { inCallActivity.hideMainInCallFragment(); } } private boolean maybeShowAccountSelectionDialog() { DialerCall waitingForAccountCall = CallList.getInstance().getWaitingForAccountCall(); if (waitingForAccountCall == null) { return false; } Bundle extras = waitingForAccountCall.getIntentExtras(); List phoneAccountHandles; if (extras != null) { phoneAccountHandles = extras.getParcelableArrayList(android.telecom.Call.AVAILABLE_PHONE_ACCOUNTS); } else { phoneAccountHandles = new ArrayList<>(); } selectPhoneAccountDialogFragment = SelectPhoneAccountDialogFragment.newInstance( R.string.select_phone_account_for_calls, true, phoneAccountHandles, selectAccountListener, waitingForAccountCall.getId()); selectPhoneAccountDialogFragment.show( inCallActivity.getFragmentManager(), TAG_SELECT_ACCOUNT_FRAGMENT); return true; } /** @deprecated Only for temporary use during the deprecation of {@link InCallActivityCommon} */ @Deprecated @Nullable Dialog getErrorDialog() { return errorDialog; } /** @deprecated Only for temporary use during the deprecation of {@link InCallActivityCommon} */ @Deprecated void setErrorDialog(@Nullable Dialog errorDialog) { this.errorDialog = errorDialog; } /** @deprecated Only for temporary use during the deprecation of {@link InCallActivityCommon} */ @Deprecated @Nullable SelectPhoneAccountDialogFragment getSelectPhoneAccountDialogFragment() { return selectPhoneAccountDialogFragment; } /** @deprecated Only for temporary use during the deprecation of {@link InCallActivityCommon} */ @Deprecated void setSelectPhoneAccountDialogFragment( @Nullable SelectPhoneAccountDialogFragment selectPhoneAccountDialogFragment) { this.selectPhoneAccountDialogFragment = selectPhoneAccountDialogFragment; } /** @deprecated Only for temporary use during the deprecation of {@link InCallActivityCommon} */ @Deprecated InternationalCallOnWifiDialogFragment.Callback getCallbackForInternationalCallOnWifiDialog() { return internationalCallOnWifiCallback; } }