summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSantos Cordon <santoscordon@google.com>2013-09-24 20:44:19 +0000
committerAndroid (Google) Code Review <android-gerrit@google.com>2013-09-24 20:44:19 +0000
commit69e35e542e8d0a072da721ea758d3d4aa91c7ea0 (patch)
treee59392b2e09cf41e18ddcd5eccb8c0a7513ec218
parent3557608a38f672c49829d3b2c6e235d8d971a84d (diff)
parent9ccf74a1e34b0a08b8d74cbb5a494eea879fd15e (diff)
Merge "Add generic error code dialogs for failed calls." into klp-dev
-rw-r--r--InCallUI/src/com/android/incallui/AnswerPresenter.java5
-rw-r--r--InCallUI/src/com/android/incallui/CallList.java59
-rw-r--r--InCallUI/src/com/android/incallui/InCallActivity.java83
-rw-r--r--InCallUI/src/com/android/incallui/InCallPresenter.java101
4 files changed, 220 insertions, 28 deletions
diff --git a/InCallUI/src/com/android/incallui/AnswerPresenter.java b/InCallUI/src/com/android/incallui/AnswerPresenter.java
index e820929a0..b3deb641e 100644
--- a/InCallUI/src/com/android/incallui/AnswerPresenter.java
+++ b/InCallUI/src/com/android/incallui/AnswerPresenter.java
@@ -64,6 +64,11 @@ public class AnswerPresenter extends Presenter<AnswerPresenter.AnswerUi>
}
@Override
+ public void onDisconnect(Call call) {
+ // no-op
+ }
+
+ @Override
public void onIncomingCall(Call call) {
// TODO: Ui is being destroyed when the fragment detaches. Need clean up step to stop
// getting updates here.
diff --git a/InCallUI/src/com/android/incallui/CallList.java b/InCallUI/src/com/android/incallui/CallList.java
index 53288de03..ba123b0c1 100644
--- a/InCallUI/src/com/android/incallui/CallList.java
+++ b/InCallUI/src/com/android/incallui/CallList.java
@@ -83,10 +83,15 @@ public class CallList {
public void onDisconnect(Call call) {
Log.d(this, "onDisconnect: ", call);
- updateCallInMap(call);
+ boolean updated = updateCallInMap(call);
- notifyCallUpdateListeners(call);
- notifyListenersOfChange();
+ if (updated) {
+ // notify those listening for changes on this specific change
+ notifyCallUpdateListeners(call);
+
+ // notify those listening for all disconnects
+ notifyListenersOfDisconnect(call);
+ }
}
/**
@@ -232,7 +237,6 @@ public class CallList {
}
public Call getFirstCall() {
- // TODO: should we switch to a simple list and pull the first one?
Call result = getIncomingCall();
if (result == null) {
result = getOutgoingCall();
@@ -240,6 +244,12 @@ public class CallList {
if (result == null) {
result = getFirstCallWithState(Call.State.ACTIVE);
}
+ if (result == null) {
+ result = getDisconnectingCall();
+ }
+ if (result == null) {
+ result = getDisconnectedCall();
+ }
return result;
}
@@ -317,9 +327,21 @@ public class CallList {
}
}
- private void updateCallInMap(Call call) {
+ private void notifyListenersOfDisconnect(Call call) {
+ for (Listener listener : mListeners) {
+ listener.onDisconnect(call);
+ }
+ }
+
+ /**
+ * Updates the call entry in the local map.
+ * @return false if no call previously existed and no call was added, otherwise true.
+ */
+ private boolean updateCallInMap(Call call) {
Preconditions.checkNotNull(call);
+ boolean updated = false;
+
final Integer id = new Integer(call.getCallId());
if (call.getState() == Call.State.DISCONNECTED) {
@@ -334,12 +356,17 @@ public class CallList {
mHandler.sendMessageDelayed(msg, getDelayForDisconnect(call));
mCallMap.put(id, call);
+ updated = true;
}
} else if (!isCallDead(call)) {
mCallMap.put(id, call);
+ updated = true;
} else if (mCallMap.containsKey(id)) {
mCallMap.remove(id);
+ updated = true;
}
+
+ return updated;
}
private int getDelayForDisconnect(Call call) {
@@ -419,8 +446,28 @@ public class CallList {
* to the call list.
*/
public interface Listener {
- public void onCallListChange(CallList callList);
+ /**
+ * Called when a new incoming call comes in.
+ * This is the only method that gets called for incoming calls. Listeners
+ * that want to perform an action on incoming call should respond in this method
+ * because {@link #onCallListChange} does not automatically get called for
+ * incoming calls.
+ */
public void onIncomingCall(Call call);
+
+ /**
+ * Called anytime there are changes to the call list. The change can be switching call
+ * states, updating information, etc. This method will NOT be called for new incoming
+ * calls and for calls that switch to disconnected state. Listeners must add actions
+ * to those method implementations if they want to deal with those actions.
+ */
+ public void onCallListChange(CallList callList);
+
+ /**
+ * Called when a call switches to the disconnected state. This is the only method
+ * that will get called upon disconnection.
+ */
+ public void onDisconnect(Call call);
}
public interface CallUpdateListener {
diff --git a/InCallUI/src/com/android/incallui/InCallActivity.java b/InCallUI/src/com/android/incallui/InCallActivity.java
index dfe9876ad..08766d2c6 100644
--- a/InCallUI/src/com/android/incallui/InCallActivity.java
+++ b/InCallUI/src/com/android/incallui/InCallActivity.java
@@ -20,6 +20,10 @@ import com.android.services.telephony.common.Call;
import com.android.services.telephony.common.Call.State;
import android.app.Activity;
+import android.app.AlertDialog;
+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.os.Bundle;
@@ -37,12 +41,15 @@ public class InCallActivity extends Activity {
public static final String SHOW_DIALPAD_EXTRA = "InCallActivity.show_dialpad";
+ private static final int INVALID_RES_ID = -1;
+
private CallButtonFragment mCallButtonFragment;
private CallCardFragment mCallCardFragment;
private AnswerFragment mAnswerFragment;
private DialpadFragment mDialpadFragment;
private ConferenceManagerFragment mConferenceManagerFragment;
private boolean mIsForegroundActivity;
+ private AlertDialog mDialog;
/** Use to pass 'showDialpad' from {@link #onNewIntent} to {@link #onResume} */
private boolean mShowDialpadRequested;
@@ -148,8 +155,12 @@ public class InCallActivity extends Activity {
*/
@Override
public void finish() {
- Log.d(this, "finish()...");
- super.finish();
+ Log.i(this, "finish(). Dialog showing: " + (mDialog != null));
+
+ // skip finish if we are still showing a dialog.
+ if (mDialog == null) {
+ super.finish();
+ }
}
@Override
@@ -391,4 +402,72 @@ public class InCallActivity extends Activity {
}
return super.dispatchPopulateAccessibilityEvent(event);
}
+
+ public void maybeShowErrorDialogOnDisconnect(Call.DisconnectCause cause) {
+ Log.d(this, "maybeShowErrorDialogOnDisconnect");
+
+ if (!isFinishing()) {
+ final int resId = getResIdForDisconnectCause(cause);
+ if (resId != INVALID_RES_ID) {
+ showErrorDialog(resId);
+ }
+ }
+ }
+
+ public void dismissPendingDialogs() {
+ if (mDialog != null) {
+ mDialog.dismiss();
+ mDialog = null;
+ }
+ }
+
+ /**
+ * Utility function to bring up a generic "error" dialog.
+ */
+ private void showErrorDialog(int resId) {
+ final CharSequence msg = getResources().getText(resId);
+ Log.i(this, "Show Dialog: " + msg);
+
+ dismissPendingDialogs();
+
+ mDialog = new AlertDialog.Builder(this)
+ .setMessage(msg)
+ .setPositiveButton(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 int getResIdForDisconnectCause(Call.DisconnectCause cause) {
+ int resId = INVALID_RES_ID;
+
+ if (cause == Call.DisconnectCause.CALL_BARRED) {
+ resId = R.string.callFailed_cb_enabled;
+ } else if (cause == Call.DisconnectCause.FDN_BLOCKED) {
+ resId = R.string.callFailed_fdn_only;
+ } else if (cause == Call.DisconnectCause.CS_RESTRICTED) {
+ resId = R.string.callFailed_dsac_restricted;
+ } else if (cause == Call.DisconnectCause.CS_RESTRICTED_EMERGENCY) {
+ resId = R.string.callFailed_dsac_restricted_emergency;
+ } else if (cause == Call.DisconnectCause.CS_RESTRICTED_NORMAL) {
+ resId = R.string.callFailed_dsac_restricted_normal;
+ }
+
+ return resId;
+ }
+
+ private void onDialogDismissed() {
+ mDialog = null;
+ InCallPresenter.getInstance().onDismissDialog();
+ }
}
diff --git a/InCallUI/src/com/android/incallui/InCallPresenter.java b/InCallUI/src/com/android/incallui/InCallPresenter.java
index 47fe91194..02ac0bec3 100644
--- a/InCallUI/src/com/android/incallui/InCallPresenter.java
+++ b/InCallUI/src/com/android/incallui/InCallPresenter.java
@@ -119,6 +119,15 @@ public class InCallPresenter implements CallList.Listener {
attemptCleanup();
}
+ private void attemptFinishActivity() {
+ final boolean doFinish = (mInCallActivity != null && isActivityStarted());
+ Log.i(this, "Hide in call UI: " + doFinish);
+
+ if (doFinish) {
+ mInCallActivity.finish();
+ }
+ }
+
/**
* Called when the UI begins or ends. Starts the callstate callbacks if the UI just began.
* Attempts to tear down everything if the UI just ended. See #tearDown for more insight on
@@ -128,16 +137,6 @@ public class InCallPresenter implements CallList.Listener {
boolean updateListeners = false;
if (inCallActivity != null) {
- // When the UI comes up, we need to first check the state of the Service.
- // If the service is not attached, that means that a call probably connected and
- // then immediately disconnected before the UI was able to come up. A disconnected
- // service means we dont have calls, so start tearing down the UI instead.
- if (mServiceConnected == false) {
- inCallActivity.finish();
- attemptCleanup();
- return;
- }
-
if (mInCallActivity == null) {
updateListeners = true;
Log.i(this, "UI Initialized");
@@ -150,6 +149,24 @@ public class InCallPresenter implements CallList.Listener {
}
mInCallActivity = inCallActivity;
+
+ // By the time the UI finally comes up, the call may already be disconnected.
+ // If that's the case, we may need to show an error dialog.
+ if (mCallList != null && mCallList.getDisconnectedCall() != null) {
+ maybeShowErrorDialogOnDisconnect(mCallList.getDisconnectedCall());
+ }
+
+ // When the UI comes up, we need to first check the in-call state.
+ // If we are showing NO_CALLS, that means that a call probably connected and
+ // then immediately disconnected before the UI was able to come up.
+ // If we dont have any calls, start tearing down the UI instead.
+ // NOTE: This code relies on {@link #mInCallActivity} being set so we run it after
+ // it has been set.
+ if (mInCallState == InCallState.NO_CALLS) {
+ Log.i(this, "UI Intialized, but no calls left. shut down.");
+ attemptFinishActivity();
+ return;
+ }
} else {
Log.i(this, "UI Destroyed)");
updateListeners = true;
@@ -224,6 +241,18 @@ public class InCallPresenter implements CallList.Listener {
}
/**
+ * Called when a call becomes disconnected. Called everytime an existing call
+ * changes from being connected (incoming/outgoing/active) to disconnected.
+ */
+ @Override
+ public void onDisconnect(Call call) {
+ maybeShowErrorDialogOnDisconnect(call);
+
+ // We need to do the run the same code as onCallListChange.
+ onCallListChange(CallList.getInstance());
+ }
+
+ /**
* Given the call list, return the state in which the in-call screen should be.
*/
public static InCallState getPotentialStateFromCallList(CallList callList) {
@@ -359,6 +388,9 @@ public class InCallPresenter implements CallList.Listener {
// "Swap calls", or can be a no-op, depending on the current state
// of the Phone.
+ /**
+ * INCOMING CALL
+ */
final CallList calls = CallList.getInstance();
final Call incomingCall = calls.getIncomingCall();
Log.v(this, "incomingCall: " + incomingCall);
@@ -369,8 +401,10 @@ public class InCallPresenter implements CallList.Listener {
return true;
}
+ /**
+ * ACTIVE CALL
+ */
final Call activeCall = calls.getActiveCall();
-
if (activeCall != null) {
// TODO: This logic is repeated from CallButtonPresenter.java. We should
// consolidate this logic.
@@ -399,8 +433,10 @@ public class InCallPresenter implements CallList.Listener {
}
}
+ /**
+ * BACKGROUND CALL
+ */
final Call heldCall = calls.getBackgroundCall();
-
if (heldCall != null) {
// We have a hold call so presumeable it will always support HOLD...but
// there is no harm in double checking.
@@ -420,6 +456,30 @@ public class InCallPresenter implements CallList.Listener {
}
/**
+ * A dialog could have prevented in-call screen from being previously finished.
+ * This function checks to see if there should be any UI left and if not attempts
+ * to tear down the UI.
+ */
+ public void onDismissDialog() {
+ Log.i(this, "Dialog dismissed");
+ if (mInCallState == InCallState.NO_CALLS) {
+ attemptFinishActivity();
+ attemptCleanup();
+ }
+ }
+
+ /**
+ * For some disconnected causes, we show a dialog. This calls into the activity to show
+ * the dialog if appropriate for the call.
+ */
+ private void maybeShowErrorDialogOnDisconnect(Call call) {
+ // For newly disconnected calls, we may want to show a dialog on specific error conditions
+ if (isActivityStarted() && call.getState() == Call.State.DISCONNECTED) {
+ mInCallActivity.maybeShowErrorDialogOnDisconnect(call.getDisconnectCause());
+ }
+ }
+
+ /**
* When the state of in-call changes, this is the first method to get called. It determines if
* the UI needs to be started or finished depending on the new state and does it.
*/
@@ -486,16 +546,16 @@ public class InCallPresenter implements CallList.Listener {
showInCall(false);
} else if (startStartupSequence) {
Log.i(this, "Start Full Screen in call UI");
+
+ // We're about the bring up the in-call UI for an incoming call. If we still have
+ // dialogs up, we need to clear them out before showing incoming screen.
+ if (isActivityStarted()) {
+ mInCallActivity.dismissPendingDialogs();
+ }
mStatusBarNotifier.updateNotificationAndLaunchIncomingCallUi(newState, mCallList);
} else if (newState == InCallState.NO_CALLS) {
- Log.e(this, "Hide in call UI", new Exception());
-
// The new state is the no calls state. Tear everything down.
- if (mInCallActivity != null) {
- if (isActivityStarted()) {
- mInCallActivity.finish();
- }
- }
+ attemptFinishActivity();
}
return newState;
@@ -506,7 +566,8 @@ public class InCallPresenter implements CallList.Listener {
* down.
*/
private void attemptCleanup() {
- boolean shouldCleanup = (mInCallActivity == null && !mServiceConnected);
+ boolean shouldCleanup = (mInCallActivity == null && !mServiceConnected &&
+ mInCallState == InCallState.NO_CALLS);
Log.i(this, "attemptCleanup? " + shouldCleanup);
if (shouldCleanup) {