blob: a2467dd72925a982624c9a36718e7e81d9cad5f8 [file] [log] [blame]
/*
* 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.AlertDialog;
import android.app.Dialog;
import android.app.DialogFragment;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnCancelListener;
import android.content.DialogInterface.OnDismissListener;
import android.content.Intent;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.os.Bundle;
import android.support.annotation.IntDef;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
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.DisconnectCause;
import android.telecom.PhoneAccountHandle;
import android.text.TextUtils;
import android.util.Pair;
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 android.widget.CheckBox;
import android.widget.Toast;
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.CompatUtils;
import com.android.dialer.logging.Logger;
import com.android.dialer.logging.nano.ScreenEvent;
import com.android.dialer.util.ViewUtil;
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.wifi.EnableWifiCallingPrompt;
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";
@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 final InCallActivity inCallActivity;
private boolean dismissKeyguard;
private boolean showPostCharWaitDialogOnResume;
private String showPostCharWaitDialogCallId;
private String showPostCharWaitDialogChars;
private Dialog dialog;
private InCallOrientationEventListener inCallOrientationEventListener;
private Animation dialpadSlideInAnimation;
private Animation dialpadSlideOutAnimation;
private boolean animateDialpadOnShow;
private String dtmfTextToPreopulate;
@DialpadRequestType private int showDialpadRequest = DIALPAD_REQUEST_NONE;
private 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();
}
}
};
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) {
// set this flag so this activity will stay in front of the keyguard
// Have the WindowManager filter out touch events that are "too fat".
int flags =
WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
| WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
| WindowManager.LayoutParams.FLAG_IGNORE_CHEEK_PRESSES;
inCallActivity.getWindow().addFlags(flags);
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();
}
});
if (icicle != null) {
// 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);
}
}
inCallOrientationEventListener = new InCallOrientationEventListener(inCallActivity);
}
public void onSaveInstanceState(Bundle out) {
// TODO: The dialpad fragment should handle this as part of its own state
out.putBoolean(INTENT_EXTRA_SHOW_DIALPAD, isDialpadVisible());
DialpadFragment dialpadFragment = getDialpadFragment();
if (dialpadFragment != null) {
out.putString(DIALPAD_TEXT_KEY, dialpadFragment.getDtmfText());
}
}
public void onStart() {
// setting activity should be last thing in setup process
InCallPresenter.getInstance().setActivity(inCallActivity);
enableInCallOrientationEventListener(
inCallActivity.getRequestedOrientation()
== InCallOrientationEventListener.ACTIVITY_PREFERENCE_ALLOW_ROTATION);
InCallPresenter.getInstance().onActivityStarted();
}
public void 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 = getDialpadFragment();
if (dialpadFragment != null) {
dialpadFragment.setDtmfText(dtmfTextToPreopulate);
dtmfTextToPreopulate = null;
}
} else {
LogUtil.i("InCallActivityCommon.onResume", "force hide dialpad");
if (getDialpadFragment() != null) {
inCallActivity.showDialpadFragment(false /* show */, false /* animate */);
}
}
showDialpadRequest = DIALPAD_REQUEST_NONE;
}
if (showPostCharWaitDialogOnResume) {
showPostCharWaitDialog(showPostCharWaitDialogCallId, showPostCharWaitDialogChars);
}
CallList.getInstance()
.onInCallUiShown(
inCallActivity.getIntent().getBooleanExtra(INTENT_EXTRA_FOR_FULL_SCREEN, false));
}
// onPause is guaranteed to be called when the InCallActivity goes
// in the background.
public void onPause() {
DialpadFragment dialpadFragment = getDialpadFragment();
if (dialpadFragment != null) {
dialpadFragment.onDialerKeyUp(null);
}
InCallPresenter.getInstance().onUiShowing(false);
if (inCallActivity.isFinishing()) {
InCallPresenter.getInstance().unsetActivity(inCallActivity);
}
}
public void onStop() {
enableInCallOrientationEventListener(false);
InCallPresenter.getInstance().updateIsChangingConfigurations();
InCallPresenter.getInstance().onActivityStopped();
}
public void onDestroy() {
InCallPresenter.getInstance().unsetActivity(inCallActivity);
InCallPresenter.getInstance().updateIsChangingConfigurations();
}
public void onNewIntent(Intent intent) {
LogUtil.i("InCallActivityCommon.onNewIntent", "");
// 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.
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 = 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 = 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;
}
return event.getRepeatCount() == 0 && handleDialerKeyDown(keyCode, event);
}
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 = getDialpadFragment();
if (dialpadFragment != null && dialpadFragment.isVisible()) {
return dialpadFragment.onDialerKeyDown(event);
}
return false;
}
public void dismissKeyguard(boolean dismiss) {
if (dismissKeyguard == dismiss) {
return;
}
dismissKeyguard = dismiss;
if (dismiss) {
inCallActivity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);
} else {
inCallActivity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);
}
}
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;
}
}
public void maybeShowErrorDialogOnDisconnect(DisconnectCause cause) {
LogUtil.i(
"InCallActivityCommon.maybeShowErrorDialogOnDisconnect", "disconnect cause: %s", cause);
if (!inCallActivity.isFinishing()) {
if (EnableWifiCallingPrompt.shouldShowPrompt(cause)) {
Pair<Dialog, CharSequence> pair =
EnableWifiCallingPrompt.createDialog(inCallActivity, cause);
showErrorDialog(pair.first, pair.second);
} else if (shouldShowDisconnectErrorDialog(cause)) {
Pair<Dialog, CharSequence> pair = getDisconnectErrorDialog(inCallActivity, cause);
showErrorDialog(pair.first, pair.second);
}
}
}
/**
* 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 dismissPendingDialogs() {
if (dialog != null) {
dialog.dismiss();
dialog = null;
}
}
private static boolean shouldShowDisconnectErrorDialog(@NonNull DisconnectCause cause) {
return !TextUtils.isEmpty(cause.getDescription())
&& (cause.getCode() == DisconnectCause.ERROR
|| cause.getCode() == DisconnectCause.RESTRICTED);
}
private static Pair<Dialog, CharSequence> getDisconnectErrorDialog(
@NonNull Context context, @NonNull DisconnectCause cause) {
CharSequence message = cause.getDescription();
Dialog dialog =
new AlertDialog.Builder(context)
.setMessage(message)
.setPositiveButton(android.R.string.ok, null)
.create();
return new Pair<>(dialog, message);
}
private void showErrorDialog(Dialog dialog, CharSequence message) {
LogUtil.i("InCallActivityCommon.showErrorDialog", "message: %s", message);
inCallActivity.dismissPendingDialogs();
// Show toast if apps is in background when dialog won't be visible.
if (!inCallActivity.isVisible()) {
Toast.makeText(inCallActivity.getApplicationContext(), message, Toast.LENGTH_LONG).show();
return;
}
this.dialog = dialog;
dialog.setOnDismissListener(
new OnDismissListener() {
@Override
public void onDismiss(DialogInterface dialog) {
LogUtil.i("InCallActivityCommon.showErrorDialog", "dialog dismissed");
onDialogDismissed();
}
});
dialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
dialog.show();
}
private void onDialogDismissed() {
dialog = null;
CallList.getInstance().onErrorDialogDismissed();
InCallPresenter.getInstance().onDismissDialog();
}
public void enableInCallOrientationEventListener(boolean enable) {
if (enable) {
inCallOrientationEventListener.enable(true);
} else {
inCallOrientationEventListener.disable();
}
}
public void setExcludeFromRecents(boolean exclude) {
List<AppTask> 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);
}
}
}
public void showWifiToLteHandoverToast(DialerCall call) {
if (call.hasShownWiFiToLteHandoverToast()) {
return;
}
Toast.makeText(
inCallActivity, R.string.video_call_wifi_to_lte_handover_toast, Toast.LENGTH_LONG)
.show();
call.setHasShownWiFiToLteHandoverToast();
}
public void showWifiFailedDialog(final DialerCall call) {
if (call.showWifiHandoverAlertAsToast()) {
LogUtil.i("InCallActivityCommon.showWifiFailedDialog", "as toast");
Toast.makeText(
inCallActivity, R.string.video_call_lte_to_wifi_failed_message, Toast.LENGTH_SHORT)
.show();
return;
}
dismissPendingDialogs();
AlertDialog.Builder builder =
new AlertDialog.Builder(inCallActivity)
.setTitle(R.string.video_call_lte_to_wifi_failed_title);
// This allows us to use the theme of the dialog instead of the activity
View dialogCheckBoxView =
View.inflate(builder.getContext(), R.layout.video_call_lte_to_wifi_failed, null);
final CheckBox wifiHandoverFailureCheckbox =
(CheckBox) dialogCheckBoxView.findViewById(R.id.video_call_lte_to_wifi_failed_checkbox);
wifiHandoverFailureCheckbox.setChecked(false);
dialog =
builder
.setView(dialogCheckBoxView)
.setMessage(R.string.video_call_lte_to_wifi_failed_message)
.setOnCancelListener(
new OnCancelListener() {
@Override
public void onCancel(DialogInterface dialog) {
onDialogDismissed();
}
})
.setPositiveButton(
android.R.string.ok,
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int id) {
call.setDoNotShowDialogForHandoffToWifiFailure(
wifiHandoverFailureCheckbox.isChecked());
dialog.cancel();
onDialogDismissed();
}
})
.create();
LogUtil.i("InCallActivityCommon.showWifiFailedDialog", "as dialog");
dialog.show();
}
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 = 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);
getDialpadFragment().animateShowDialpad();
}
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 = 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);
}
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();
}
}
public boolean isDialpadVisible() {
DialpadFragment dialpadFragment = getDialpadFragment();
return dialpadFragment != null && dialpadFragment.isVisible();
}
/** Returns the {@link DialpadFragment} that's shown by this activity, or {@code null} */
@Nullable
private DialpadFragment getDialpadFragment() {
FragmentManager fragmentManager = inCallActivity.getDialpadFragmentManager();
if (fragmentManager == null) {
return null;
}
return (DialpadFragment) fragmentManager.findFragmentByTag(TAG_DIALPAD_FRAGMENT);
}
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);
}
public boolean hasPendingDialogs() {
return dialog != null;
}
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();
}
boolean isNewOutgoingCall = false;
if (intent.getBooleanExtra(INTENT_EXTRA_NEW_OUTGOING_CALL, false)) {
isNewOutgoingCall = true;
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();
}
dismissKeyguard(true);
}
boolean didShowAccountSelectionDialog = maybeShowAccountSelectionDialog();
inCallActivity.onResolveIntent(outgoingCall, isNewOutgoingCall, didShowAccountSelectionDialog);
}
private boolean maybeShowAccountSelectionDialog() {
DialerCall call = CallList.getInstance().getWaitingForAccountCall();
if (call == null) {
return false;
}
Bundle extras = call.getIntentExtras();
List<PhoneAccountHandle> phoneAccountHandles;
if (extras != null) {
phoneAccountHandles =
extras.getParcelableArrayList(android.telecom.Call.AVAILABLE_PHONE_ACCOUNTS);
} else {
phoneAccountHandles = new ArrayList<>();
}
DialogFragment dialogFragment =
SelectPhoneAccountDialogFragment.newInstance(
R.string.select_phone_account_for_calls,
true,
phoneAccountHandles,
selectAccountListener,
call.getId());
dialogFragment.show(inCallActivity.getFragmentManager(), TAG_SELECT_ACCOUNT_FRAGMENT);
return true;
}
}