blob: 00693641113ba4c2f6fbadb6aea6bf2b685da433 [file] [log] [blame]
/*
* Copyright (C) 2006 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.ActionBar;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.FragmentManager;
import android.app.FragmentTransaction;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.content.DialogInterface.OnCancelListener;
import android.content.Intent;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Point;
import android.net.Uri;
import android.os.Bundle;
import android.telecom.DisconnectCause;
import android.telecom.PhoneAccountHandle;
import android.telecom.TelecomManager;
import android.telephony.PhoneNumberUtils;
import android.text.TextUtils;
import android.view.MenuItem;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.view.KeyEvent;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.view.accessibility.AccessibilityEvent;
import com.android.phone.common.animation.AnimUtils;
import com.android.phone.common.animation.AnimationListenerAdapter;
import com.android.contacts.common.interactions.TouchPointManager;
import com.android.contacts.common.util.MaterialColorMapUtils;
import com.android.contacts.common.util.MaterialColorMapUtils.MaterialPalette;
import com.android.contacts.common.widget.SelectPhoneAccountDialogFragment;
import com.android.contacts.common.widget.SelectPhoneAccountDialogFragment.SelectPhoneAccountListener;
import com.android.incallui.Call.State;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
/**
* Phone app "in call" screen.
*/
public class InCallActivity extends Activity {
public static final String SHOW_DIALPAD_EXTRA = "InCallActivity.show_dialpad";
public static final String DIALPAD_TEXT_EXTRA = "InCallActivity.dialpad_text";
public static final String NEW_OUTGOING_CALL_EXTRA = "InCallActivity.new_outgoing_call";
public static final String SHOW_CIRCULAR_REVEAL_EXTRA = "InCallActivity.show_circular_reveal";
private CallButtonFragment mCallButtonFragment;
private CallCardFragment mCallCardFragment;
private AnswerFragment mAnswerFragment;
private DialpadFragment mDialpadFragment;
private ConferenceManagerFragment mConferenceManagerFragment;
private FragmentManager mChildFragmentManager;
private boolean mIsForegroundActivity;
private AlertDialog mDialog;
/** Use to pass 'showDialpad' from {@link #onNewIntent} to {@link #onResume} */
private boolean mShowDialpadRequested;
/** Use to determine if the dialpad should be animated on show. */
private boolean mAnimateDialpadOnShow;
/** Use to determine the DTMF Text which should be pre-populated in the dialpad. */
private String mDtmfText;
/** Use to pass parameters for showing the PostCharDialog to {@link #onResume} */
private boolean mShowPostCharWaitDialogOnResume;
private String mShowPostCharWaitDialogCallId;
private String mShowPostCharWaitDialogChars;
private boolean mIsLandscape;
private Animation mSlideIn;
private Animation mSlideOut;
private boolean mDismissKeyguard = false;
AnimationListenerAdapter mSlideOutListener = new AnimationListenerAdapter() {
@Override
public void onAnimationEnd(Animation animation) {
showDialpad(false);
}
};
/**
* Stores the current orientation of the activity. Used to determine if a change in orientation
* has occurred.
*/
private int mCurrentOrientation;
@Override
protected void onCreate(Bundle icicle) {
Log.d(this, "onCreate()... this = " + this);
super.onCreate(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;
getWindow().addFlags(flags);
// Setup action bar for the conference call manager.
requestWindowFeature(Window.FEATURE_ACTION_BAR_OVERLAY);
ActionBar actionBar = getActionBar();
if (actionBar != null) {
actionBar.setDisplayHomeAsUpEnabled(true);
actionBar.setDisplayShowTitleEnabled(true);
actionBar.hide();
}
// TODO(klp): Do we need to add this back when prox sensor is not available?
// lp.inputFeatures |= WindowManager.LayoutParams.INPUT_FEATURE_DISABLE_USER_ACTIVITY;
// Inflate everything in incall_screen.xml and add it to the screen.
setContentView(R.layout.incall_screen);
initializeInCall();
internalResolveIntent(getIntent());
mCurrentOrientation = getResources().getConfiguration().orientation;
mIsLandscape = getResources().getConfiguration().orientation
== Configuration.ORIENTATION_LANDSCAPE;
final boolean isRtl = TextUtils.getLayoutDirectionFromLocale(Locale.getDefault()) ==
View.LAYOUT_DIRECTION_RTL;
if (mIsLandscape) {
mSlideIn = AnimationUtils.loadAnimation(this,
isRtl ? R.anim.dialpad_slide_in_left : R.anim.dialpad_slide_in_right);
mSlideOut = AnimationUtils.loadAnimation(this,
isRtl ? R.anim.dialpad_slide_out_left : R.anim.dialpad_slide_out_right);
} else {
mSlideIn = AnimationUtils.loadAnimation(this, R.anim.dialpad_slide_in_bottom);
mSlideOut = AnimationUtils.loadAnimation(this, R.anim.dialpad_slide_out_bottom);
}
mSlideIn.setInterpolator(AnimUtils.EASE_IN);
mSlideOut.setInterpolator(AnimUtils.EASE_OUT);
mSlideOut.setAnimationListener(mSlideOutListener);
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 CallCardFragment has been inflated and is ready
// to receive it.
mShowDialpadRequested = icicle.getBoolean(SHOW_DIALPAD_EXTRA);
mAnimateDialpadOnShow = false;
mDtmfText = icicle.getString(DIALPAD_TEXT_EXTRA);
}
Log.d(this, "onCreate(): exit");
}
@Override
protected void onSaveInstanceState(Bundle out) {
out.putBoolean(SHOW_DIALPAD_EXTRA, mCallButtonFragment.isDialpadVisible());
if (mDialpadFragment != null) {
out.putString(DIALPAD_TEXT_EXTRA, mDialpadFragment.getDtmfText());
}
super.onSaveInstanceState(out);
}
@Override
protected void onStart() {
Log.d(this, "onStart()...");
super.onStart();
// setting activity should be last thing in setup process
InCallPresenter.getInstance().setActivity(this);
}
@Override
protected void onResume() {
Log.i(this, "onResume()...");
super.onResume();
mIsForegroundActivity = true;
InCallPresenter.getInstance().setThemeColors();
InCallPresenter.getInstance().onUiShowing(true);
if (mShowDialpadRequested) {
mCallButtonFragment.displayDialpad(true /* show */,
mAnimateDialpadOnShow /* animate */);
mShowDialpadRequested = false;
mAnimateDialpadOnShow = false;
if (mDialpadFragment != null) {
mDialpadFragment.setDtmfText(mDtmfText);
mDtmfText = null;
}
}
if (mShowPostCharWaitDialogOnResume) {
showPostCharWaitDialog(mShowPostCharWaitDialogCallId, mShowPostCharWaitDialogChars);
}
}
// onPause is guaranteed to be called when the InCallActivity goes
// in the background.
@Override
protected void onPause() {
Log.d(this, "onPause()...");
super.onPause();
mIsForegroundActivity = false;
if (mDialpadFragment != null ) {
mDialpadFragment.onDialerKeyUp(null);
}
InCallPresenter.getInstance().onUiShowing(false);
if (isFinishing()) {
InCallPresenter.getInstance().unsetActivity(this);
}
}
@Override
protected void onStop() {
Log.d(this, "onStop()...");
super.onStop();
}
@Override
protected void onDestroy() {
Log.d(this, "onDestroy()... this = " + this);
InCallPresenter.getInstance().unsetActivity(this);
super.onDestroy();
}
/**
* Returns true when theActivity is in foreground (between onResume and onPause).
*/
/* package */ boolean isForegroundActivity() {
return mIsForegroundActivity;
}
private boolean hasPendingErrorDialog() {
return mDialog != null;
}
/**
* Dismisses the in-call screen.
*
* We never *really* finish() the InCallActivity, since we don't want to get destroyed and then
* have to be re-created from scratch for the next call. Instead, we just move ourselves to the
* back of the activity stack.
*
* This also means that we'll no longer be reachable via the BACK button (since moveTaskToBack()
* puts us behind the Home app, but the home app doesn't allow the BACK key to move you any
* farther down in the history stack.)
*
* (Since the Phone app itself is never killed, this basically means that we'll keep a single
* InCallActivity instance around for the entire uptime of the device. This noticeably improves
* the UI responsiveness for incoming calls.)
*/
@Override
public void finish() {
Log.i(this, "finish(). Dialog showing: " + (mDialog != null));
// skip finish if we are still showing a dialog.
if (!hasPendingErrorDialog() && !mAnswerFragment.hasPendingDialogs()) {
super.finish();
}
}
@Override
protected void onNewIntent(Intent intent) {
Log.d(this, "onNewIntent: intent = " + intent);
// 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!)
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);
}
@Override
public void onBackPressed() {
Log.i(this, "onBackPressed");
// BACK is also used to exit out of any "special modes" of the
// in-call UI:
if (!mConferenceManagerFragment.isVisible() && !mCallCardFragment.isVisible()) {
return;
}
if (mDialpadFragment != null && mDialpadFragment.isVisible()) {
mCallButtonFragment.displayDialpad(false /* show */, true /* animate */);
return;
} else if (mConferenceManagerFragment.isVisible()) {
showConferenceCallManager(false);
return;
}
// Nothing special to do. Fall back to the default behavior.
super.onBackPressed();
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
final int itemId = item.getItemId();
if (itemId == android.R.id.home) {
onBackPressed();
return true;
}
return super.onOptionsItemSelected(item);
}
@Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
// push input to the dialer.
if (mDialpadFragment != null && (mDialpadFragment.isVisible()) &&
(mDialpadFragment.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 super.onKeyUp(keyCode, event);
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
switch (keyCode) {
case KeyEvent.KEYCODE_CALL:
boolean handled = InCallPresenter.getInstance().handleCallKey();
if (!handled) {
Log.w(this, "InCallActivity 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:
// toggle mute
TelecomAdapter.getInstance().mute(!AudioModeProvider.getInstance().getMute());
return true;
// Various testing/debugging features, enabled ONLY when VERBOSE == true.
case KeyEvent.KEYCODE_SLASH:
if (Log.VERBOSE) {
Log.v(this, "----------- InCallActivity View dump --------------");
// Dump starting from the top-level view of the entire activity:
Window w = this.getWindow();
View decorView = w.getDecorView();
Log.d(this, "View dump:" + decorView);
return true;
}
break;
case KeyEvent.KEYCODE_EQUALS:
// TODO: Dump phone state?
break;
}
if (event.getRepeatCount() == 0 && handleDialerKeyDown(keyCode, event)) {
return true;
}
return super.onKeyDown(keyCode, event);
}
private boolean handleDialerKeyDown(int keyCode, KeyEvent event) {
Log.v(this, "handleDialerKeyDown: keyCode " + keyCode + ", event " + 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.
if (mDialpadFragment != null && mDialpadFragment.isVisible()) {
return mDialpadFragment.onDialerKeyDown(event);
// TODO: If the dialpad isn't currently visible, maybe
// consider automatically bringing it up right now?
// (Just to make sure the user sees the digits widget...)
// But this probably isn't too critical since it's awkward to
// use the hard keyboard while in-call in the first place,
// especially now that the in-call UI is portrait-only...
}
return false;
}
@Override
public void onConfigurationChanged(Configuration config) {
InCallPresenter.getInstance().getProximitySensor().onConfigurationChanged(config);
Log.d(this, "onConfigurationChanged "+config.orientation);
// Check to see if the orientation changed to prevent triggering orientation change events
// for other configuration changes.
if (config.orientation != mCurrentOrientation) {
mCurrentOrientation = config.orientation;
InCallPresenter.getInstance().onDeviceRotationChange(
getWindowManager().getDefaultDisplay().getRotation());
InCallPresenter.getInstance().onDeviceOrientationChange(mCurrentOrientation);
}
super.onConfigurationChanged(config);
}
public CallButtonFragment getCallButtonFragment() {
return mCallButtonFragment;
}
public CallCardFragment getCallCardFragment() {
return mCallCardFragment;
}
private void internalResolveIntent(Intent intent) {
final String action = intent.getAction();
if (action.equals(intent.ACTION_MAIN)) {
// This action is the normal way to bring up the in-call UI.
//
// But we do check here for one extra that can come along with the
// ACTION_MAIN intent:
if (intent.hasExtra(SHOW_DIALPAD_EXTRA)) {
// 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.
final boolean showDialpad = intent.getBooleanExtra(SHOW_DIALPAD_EXTRA, false);
Log.d(this, "- internalResolveIntent: SHOW_DIALPAD_EXTRA: " + showDialpad);
relaunchedFromDialer(showDialpad);
}
if (intent.getBooleanExtra(NEW_OUTGOING_CALL_EXTRA, false)) {
intent.removeExtra(NEW_OUTGOING_CALL_EXTRA);
Call call = CallList.getInstance().getOutgoingCall();
if (call == null) {
call = CallList.getInstance().getPendingOutgoingCall();
}
Bundle extras = null;
if (call != null) {
extras = call.getTelecommCall().getDetails().getExtras();
}
if (extras == null) {
// Initialize the extras bundle to avoid NPE
extras = new Bundle();
}
Point touchPoint = null;
if (TouchPointManager.getInstance().hasValidPoint()) {
// Use the most immediate touch point in the InCallUi if available
touchPoint = TouchPointManager.getInstance().getPoint();
} else {
// Otherwise retrieve the touch point from the call intent
if (call != null) {
touchPoint = (Point) extras.getParcelable(TouchPointManager.TOUCH_POINT);
}
}
// This is only true in the case where an outgoing call is initiated by tapping
// on the "Select account dialog", in which case we skip the initial animation. In
// most other cases the circular reveal is done by OutgoingCallAnimationActivity.
final boolean showCircularReveal =
intent.getBooleanExtra(SHOW_CIRCULAR_REVEAL_EXTRA, false);
mCallCardFragment.animateForNewOutgoingCall(touchPoint, showCircularReveal);
/*
* If both a phone account handle and a list of phone accounts to choose from are
* missing, then disconnect the call because there is no way to place an outgoing
* call.
* The exception is emergency calls, which may be waiting for the ConnectionService
* to set the PhoneAccount during the PENDING_OUTGOING state.
*/
if (call != null && !isEmergencyCall(call)) {
final List<PhoneAccountHandle> phoneAccountHandles = extras
.getParcelableArrayList(android.telecom.Call.AVAILABLE_PHONE_ACCOUNTS);
if (call.getAccountHandle() == null &&
(phoneAccountHandles == null || phoneAccountHandles.isEmpty())) {
TelecomAdapter.getInstance().disconnectCall(call.getId());
}
}
dismissKeyguard(true);
}
Call pendingAccountSelectionCall = CallList.getInstance().getWaitingForAccountCall();
if (pendingAccountSelectionCall != null) {
mCallCardFragment.setVisible(false);
Bundle extras = pendingAccountSelectionCall
.getTelecommCall().getDetails().getExtras();
final List<PhoneAccountHandle> phoneAccountHandles;
if (extras != null) {
phoneAccountHandles = extras.getParcelableArrayList(
android.telecom.Call.AVAILABLE_PHONE_ACCOUNTS);
} else {
phoneAccountHandles = new ArrayList<>();
}
SelectPhoneAccountListener listener = new SelectPhoneAccountListener() {
@Override
public void onPhoneAccountSelected(PhoneAccountHandle selectedAccountHandle,
boolean setDefault) {
InCallPresenter.getInstance().handleAccountSelection(selectedAccountHandle,
setDefault);
}
@Override
public void onDialogDismissed() {
InCallPresenter.getInstance().cancelAccountSelection();
}
};
SelectPhoneAccountDialogFragment.showAccountDialog(getFragmentManager(),
R.string.select_phone_account_for_calls, true, phoneAccountHandles,
listener);
} else {
mCallCardFragment.setVisible(true);
}
return;
}
}
private boolean isEmergencyCall(Call call) {
final Uri handle = call.getHandle();
if (handle == null) {
return false;
}
return PhoneNumberUtils.isEmergencyNumber(handle.getSchemeSpecificPart());
}
private void relaunchedFromDialer(boolean showDialpad) {
mShowDialpadRequested = showDialpad;
mAnimateDialpadOnShow = true;
if (mShowDialpadRequested) {
// 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.
final Call call = CallList.getInstance().getActiveOrBackgroundCall();
if (call != null && call.getState() == State.ONHOLD) {
TelecomAdapter.getInstance().unholdCall(call.getId());
}
}
}
private void initializeInCall() {
if (mCallCardFragment == null) {
mCallCardFragment = (CallCardFragment) getFragmentManager()
.findFragmentById(R.id.callCardFragment);
}
mChildFragmentManager = mCallCardFragment.getChildFragmentManager();
if (mCallButtonFragment == null) {
mCallButtonFragment = (CallButtonFragment) mChildFragmentManager
.findFragmentById(R.id.callButtonFragment);
mCallButtonFragment.getView().setVisibility(View.INVISIBLE);
}
if (mAnswerFragment == null) {
mAnswerFragment = (AnswerFragment) mChildFragmentManager
.findFragmentById(R.id.answerFragment);
}
if (mConferenceManagerFragment == null) {
mConferenceManagerFragment = (ConferenceManagerFragment) getFragmentManager()
.findFragmentById(R.id.conferenceManagerFragment);
mConferenceManagerFragment.getView().setVisibility(View.INVISIBLE);
}
}
/**
* Simulates a user click to hide the dialpad. This will update the UI to show the call card,
* update the checked state of the dialpad button, and update the proximity sensor state.
*/
public void hideDialpadForDisconnect() {
mCallButtonFragment.displayDialpad(false /* show */, true /* animate */);
}
public void dismissKeyguard(boolean dismiss) {
if (mDismissKeyguard == dismiss) {
return;
}
mDismissKeyguard = dismiss;
if (dismiss) {
getWindow().addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);
} else {
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);
}
}
private void showDialpad(boolean showDialpad) {
// If the dialpad is being shown and it has not already been loaded, replace the dialpad
// placeholder with the actual fragment before continuing.
if (mDialpadFragment == null && showDialpad) {
final FragmentTransaction loadTransaction = mChildFragmentManager.beginTransaction();
View fragmentContainer = findViewById(R.id.dialpadFragmentContainer);
mDialpadFragment = new DialpadFragment();
loadTransaction.replace(fragmentContainer.getId(), mDialpadFragment,
DialpadFragment.class.getName());
loadTransaction.commitAllowingStateLoss();
mChildFragmentManager.executePendingTransactions();
}
final FragmentTransaction ft = mChildFragmentManager.beginTransaction();
if (showDialpad) {
ft.show(mDialpadFragment);
} else {
ft.hide(mDialpadFragment);
}
ft.commitAllowingStateLoss();
}
public void displayDialpad(boolean showDialpad, boolean animate) {
// If the dialpad is already visible, don't animate in. If it's gone, don't animate out.
if ((showDialpad && isDialpadVisible()) || (!showDialpad && !isDialpadVisible())) {
return;
}
// 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) {
showDialpad(showDialpad);
} else {
if (showDialpad) {
showDialpad(true);
mDialpadFragment.animateShowDialpad();
}
mCallCardFragment.onDialpadVisiblityChange(showDialpad);
mDialpadFragment.getView().startAnimation(showDialpad ? mSlideIn : mSlideOut);
}
InCallPresenter.getInstance().getProximitySensor().onDialpadVisible(showDialpad);
}
public boolean isDialpadVisible() {
return mDialpadFragment != null && mDialpadFragment.isVisible();
}
/**
* Hides or shows the conference manager fragment.
*
* @param show {@code true} if the conference manager should be shown, {@code false} if it
* should be hidden.
*/
public void showConferenceCallManager(boolean show) {
mConferenceManagerFragment.setVisible(show);
// Need to hide the call card fragment to ensure that accessibility service does not try to
// give focus to the call card when the conference manager is visible.
mCallCardFragment.getView().setVisibility(show ? View.GONE : View.VISIBLE);
}
public void showPostCharWaitDialog(String callId, String chars) {
if (isForegroundActivity()) {
final PostCharDialogFragment fragment = new PostCharDialogFragment(callId, chars);
fragment.show(getFragmentManager(), "postCharWait");
mShowPostCharWaitDialogOnResume = false;
mShowPostCharWaitDialogCallId = null;
mShowPostCharWaitDialogChars = null;
} else {
mShowPostCharWaitDialogOnResume = true;
mShowPostCharWaitDialogCallId = callId;
mShowPostCharWaitDialogChars = chars;
}
}
@Override
public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
if (mCallCardFragment != null) {
mCallCardFragment.dispatchPopulateAccessibilityEvent(event);
}
return super.dispatchPopulateAccessibilityEvent(event);
}
public void maybeShowErrorDialogOnDisconnect(DisconnectCause disconnectCause) {
Log.d(this, "maybeShowErrorDialogOnDisconnect");
if (!isFinishing() && !TextUtils.isEmpty(disconnectCause.getDescription())
&& (disconnectCause.getCode() == DisconnectCause.ERROR ||
disconnectCause.getCode() == DisconnectCause.RESTRICTED)) {
showErrorDialog(disconnectCause.getDescription());
}
}
public void dismissPendingDialogs() {
if (mDialog != null) {
mDialog.dismiss();
mDialog = null;
}
mAnswerFragment.dismissPendingDialogues();
}
/**
* Utility function to bring up a generic "error" dialog.
*/
private void showErrorDialog(CharSequence msg) {
Log.i(this, "Show Dialog: " + msg);
dismissPendingDialogs();
mDialog = new AlertDialog.Builder(this)
.setMessage(msg)
.setPositiveButton(android.R.string.ok, new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
onDialogDismissed();
}})
.setOnCancelListener(new OnCancelListener() {
@Override
public void onCancel(DialogInterface dialog) {
onDialogDismissed();
}})
.create();
mDialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
mDialog.show();
}
private void onDialogDismissed() {
mDialog = null;
InCallPresenter.getInstance().onDismissDialog();
}
}