summaryrefslogtreecommitdiff
path: root/InCallUI
diff options
context:
space:
mode:
authorSantos Cordon <santoscordon@google.com>2013-08-07 12:12:58 -0700
committerSantos Cordon <santoscordon@google.com>2013-08-07 20:20:25 -0700
commit82f5d003e675dfd56735c745744c3d968883b23c (patch)
tree7ea0a275fc17cc457744e868f8faed9e714ea9ee /InCallUI
parent950e3df8ac744daf2a890d279566bdba424710f9 (diff)
Add UI to show when the Call disconnects.
When the call disconnects, we need to show UI for a short time before existing the UI. Change-Id: Iee648b8c54ee4b5ea09cfaec508e1bf8fb8f1643
Diffstat (limited to 'InCallUI')
-rwxr-xr-xInCallUI/res/values/strings.xml49
-rw-r--r--InCallUI/src/com/android/incallui/AnswerFragment.java1
-rw-r--r--InCallUI/src/com/android/incallui/CallButtonFragment.java1
-rw-r--r--InCallUI/src/com/android/incallui/CallCardFragment.java111
-rw-r--r--InCallUI/src/com/android/incallui/CallCardPresenter.java59
-rw-r--r--InCallUI/src/com/android/incallui/CallHandlerService.java6
-rw-r--r--InCallUI/src/com/android/incallui/CallList.java68
-rw-r--r--InCallUI/src/com/android/incallui/InCallPresenter.java3
-rw-r--r--InCallUI/src/com/android/incallui/Logger.java16
9 files changed, 294 insertions, 20 deletions
diff --git a/InCallUI/res/values/strings.xml b/InCallUI/res/values/strings.xml
index 2ecc84270..882102a7e 100755
--- a/InCallUI/res/values/strings.xml
+++ b/InCallUI/res/values/strings.xml
@@ -32,6 +32,55 @@
<!-- Incoming call screen, string when called from a pay phone -->
<string name="payphone">Pay phone</string>
+ <!-- In-call screen: call failure reason (busy) -->
+ <string name="callFailed_userBusy">Line busy</string>
+ <!-- In-call screen: call failure reason (network congestion) -->
+ <string name="callFailed_congestion">Network busy</string>
+ <!-- In-call screen: call failure reason (client timed out) -->
+ <string name="callFailed_timedOut">No response, timed out</string>
+ <!-- In-call screen: call failure reason (server unreachable) -->
+ <string name="callFailed_server_unreachable">Server unreachable</string>
+ <!-- In-call screen: call failure reason (peer unreachable) -->
+ <string name="callFailed_number_unreachable">Number unreachable</string>
+ <!-- In-call screen: call failure reason (incorrect username or password) -->
+ <string name="callFailed_invalid_credentials">Incorrect username or password</string>
+ <!-- In-call screen: call failure reason (calling from out of network is not allowed) -->
+ <string name="callFailed_out_of_network">Called from out-of-network</string>
+ <!-- In-call screen: call failure reason (server error) -->
+ <string name="callFailed_server_error">Server error. Try again later.</string>
+ <!-- In-call screen: call failure reason (no signal) -->
+ <string name="callFailed_noSignal">No signal</string>
+ <!-- In-call screen: call failure reason (GSM ACM limit exceeded) -->
+ <string name="callFailed_limitExceeded">ACM limit exceeded</string>
+ <!-- In-call screen: call failure reason (radio is off) -->
+ <string name="callFailed_powerOff">Radio off</string>
+ <!-- In-call screen: call failure reason (SIM error) -->
+ <string name="callFailed_simError">No SIM or SIM error</string>
+ <!-- In-call screen: call failure reason (out of service) -->
+ <string name="callFailed_outOfService">Out of service area</string>
+ <!-- In-call screen: call failure reason (call denied because of current FDN setting) -->
+ <string name="callFailed_fdn_only">Outgoing calls are restricted by FDN.</string>
+ <!-- In-call screen: call failure reason (call denied because call barring is on) -->
+ <string name="callFailed_cb_enabled">You can\'t make outgoing calls while call barring is on.</string>
+ <!-- In-call screen: call failure reason (call denied because domain specific access control is on) -->
+ <string name="callFailed_dsac_restricted">All calls are restricted by access control.</string>
+ <!-- In-call screen: call failure reason (Emergency call denied because domain specific access control is on)-->
+ <string name="callFailed_dsac_restricted_emergency">Emergency calls are restricted by access control.</string>
+ <!-- In-call screen: call failure reason (Normal call denied because domain specific access control is on)-->
+ <string name="callFailed_dsac_restricted_normal">Normal calls are restricted by access control.</string>
+ <!-- In-call screen: call failure reason (Dialed number doesn't exist) -->
+ <string name="callFailed_unobtainable_number">Invalid number</string>
+ <!-- In-call screen: status label for a conference call -->
+ <string name="confCall">Conference call</string>
+ <!-- In-call screen: call lost dialog text -->
+ <string name="call_lost">Call has been lost.</string>
+
+ <!-- Positive button label ("OK") used in several dialogs in the phone UI [CHAR LIMIT=10] -->
+ <string name="ok">OK</string>
+
+ <!-- MMI dialog strings -->
+ <!-- Dialog label when an MMI code starts running -->
+
<!-- "Audio mode" popup menu: Item label to select the speakerphone [CHAR LIMIT=25] -->
<string name="audio_mode_speaker">Speaker</string>
<!-- "Audio mode" popup menu: Item label to select the handset earpiece [CHAR LIMIT=25] -->
diff --git a/InCallUI/src/com/android/incallui/AnswerFragment.java b/InCallUI/src/com/android/incallui/AnswerFragment.java
index 79247c56c..d1a1df0a6 100644
--- a/InCallUI/src/com/android/incallui/AnswerFragment.java
+++ b/InCallUI/src/com/android/incallui/AnswerFragment.java
@@ -70,6 +70,7 @@ public class AnswerFragment extends BaseFragment<AnswerPresenter> implements
@Override
public void onDestroyView() {
+ super.onDestroyView();
getPresenter().onUiUnready(this);
}
diff --git a/InCallUI/src/com/android/incallui/CallButtonFragment.java b/InCallUI/src/com/android/incallui/CallButtonFragment.java
index 175fe4d95..1b9465de7 100644
--- a/InCallUI/src/com/android/incallui/CallButtonFragment.java
+++ b/InCallUI/src/com/android/incallui/CallButtonFragment.java
@@ -119,6 +119,7 @@ public class CallButtonFragment extends BaseFragment<CallButtonPresenter>
@Override
public void onDestroyView() {
+ super.onDestroyView();
getPresenter().onUiUnready(this);
}
diff --git a/InCallUI/src/com/android/incallui/CallCardFragment.java b/InCallUI/src/com/android/incallui/CallCardFragment.java
index d4782c5fe..19c32f4fd 100644
--- a/InCallUI/src/com/android/incallui/CallCardFragment.java
+++ b/InCallUI/src/com/android/incallui/CallCardFragment.java
@@ -22,6 +22,7 @@ import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.text.TextUtils;
+import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -29,6 +30,8 @@ import android.view.ViewStub;
import android.widget.ImageView;
import android.widget.TextView;
+import com.android.services.telephony.common.Call;
+
/**
* Fragment for call card.
*/
@@ -39,8 +42,7 @@ public class CallCardFragment extends BaseFragment<CallCardPresenter>
private TextView mNumberLabel;
private TextView mName;
private ImageView mPhoto;
-
-
+ private TextView mCallStateLabel;
private ViewStub mSecondaryCallInfo;
private TextView mSecondaryCallName;
@@ -63,6 +65,7 @@ public class CallCardFragment extends BaseFragment<CallCardPresenter>
mNumberLabel = (TextView) view.findViewById(R.id.label);
mSecondaryCallInfo = (ViewStub) view.findViewById(R.id.secondary_call_info);
mPhoto = (ImageView) view.findViewById(R.id.photo);
+ mCallStateLabel = (TextView) view.findViewById(R.id.callStateLabel);
// This method call will begin the callbacks on CallCardUi. We need to ensure
// everything needed for the callbacks is set up before this is called.
@@ -71,6 +74,7 @@ public class CallCardFragment extends BaseFragment<CallCardPresenter>
@Override
public void onDestroyView() {
+ super.onDestroyView();
getPresenter().onUiUnready(this);
}
@@ -139,6 +143,109 @@ public class CallCardFragment extends BaseFragment<CallCardPresenter>
}
}
+ @Override
+ public void setCallState(int state, Call.DisconnectCause cause) {
+ String callStateLabel = null;
+
+ // States other than disconnected not yet supported
+ if (state == Call.State.DISCONNECTED) {
+ callStateLabel = getCallFailedString(cause);
+ }
+
+ Logger.d(this, "setCallState ", callStateLabel);
+
+ if (!TextUtils.isEmpty(callStateLabel)) {
+ mCallStateLabel.setVisibility(View.VISIBLE);
+ mCallStateLabel.setText(callStateLabel);
+ } else {
+ mCallStateLabel.setVisibility(View.GONE);
+ // Gravity is aligned left when receiving an incoming call in landscape.
+ // In that rare case, the gravity needs to be reset to the right.
+ // Also, setText("") is used since there is a delay in making the view GONE,
+ // so the user will otherwise see the text jump to the right side before disappearing.
+ if(mCallStateLabel.getGravity() != Gravity.END) {
+ mCallStateLabel.setText("");
+ mCallStateLabel.setGravity(Gravity.END);
+ }
+ }
+ }
+
+ /**
+ * Maps the disconnect cause to a resource string.
+ */
+ private String getCallFailedString(Call.DisconnectCause cause) {
+ int resID = R.string.card_title_call_ended;
+
+ // TODO: The card *title* should probably be "Call ended" in all
+ // cases, but if the DisconnectCause was an error condition we should
+ // probably also display the specific failure reason somewhere...
+
+ switch (cause) {
+ case BUSY:
+ resID = R.string.callFailed_userBusy;
+ break;
+
+ case CONGESTION:
+ resID = R.string.callFailed_congestion;
+ break;
+
+ case TIMED_OUT:
+ resID = R.string.callFailed_timedOut;
+ break;
+
+ case SERVER_UNREACHABLE:
+ resID = R.string.callFailed_server_unreachable;
+ break;
+
+ case NUMBER_UNREACHABLE:
+ resID = R.string.callFailed_number_unreachable;
+ break;
+
+ case INVALID_CREDENTIALS:
+ resID = R.string.callFailed_invalid_credentials;
+ break;
+
+ case SERVER_ERROR:
+ resID = R.string.callFailed_server_error;
+ break;
+
+ case OUT_OF_NETWORK:
+ resID = R.string.callFailed_out_of_network;
+ break;
+
+ case LOST_SIGNAL:
+ case CDMA_DROP:
+ resID = R.string.callFailed_noSignal;
+ break;
+
+ case LIMIT_EXCEEDED:
+ resID = R.string.callFailed_limitExceeded;
+ break;
+
+ case POWER_OFF:
+ resID = R.string.callFailed_powerOff;
+ break;
+
+ case ICC_ERROR:
+ resID = R.string.callFailed_simError;
+ break;
+
+ case OUT_OF_SERVICE:
+ resID = R.string.callFailed_outOfService;
+ break;
+
+ case INVALID_NUMBER:
+ case UNOBTAINABLE_NUMBER:
+ resID = R.string.callFailed_unobtainable_number;
+ break;
+
+ default:
+ resID = R.string.card_title_call_ended;
+ break;
+ }
+ return this.getView().getContext().getString(resID);
+ }
+
private void showAndInitializeSecondaryCallInfo() {
mSecondaryCallInfo.setVisibility(View.VISIBLE);
diff --git a/InCallUI/src/com/android/incallui/CallCardPresenter.java b/InCallUI/src/com/android/incallui/CallCardPresenter.java
index 5f67a51e2..d97c22e57 100644
--- a/InCallUI/src/com/android/incallui/CallCardPresenter.java
+++ b/InCallUI/src/com/android/incallui/CallCardPresenter.java
@@ -75,17 +75,12 @@ public class CallCardPresenter extends Presenter<CallCardPresenter.CallCardUi> i
} else if (state == InCallState.OUTGOING) {
primary = callList.getOutgoingCall();
- // Safe to assume that the primary call is valid since we would not be in the
- // OUTGOING state without an outgoing call.
- secondary = callList.getBackgroundCall();
+ // getCallToDisplay doesn't go through outgoing or incoming calls. It will return the
+ // highest priority call to display as the secondary call.
+ secondary = getCallToDisplay(callList, null);
} else if (state == InCallState.INCALL) {
- primary = callList.getActiveCall();
- if (primary != null) {
- secondary = callList.getBackgroundCall();
- } else {
- primary = callList.getBackgroundCall();
- secondary = callList.getSecondBackgroundCall();
- }
+ primary = getCallToDisplay(callList, null);
+ secondary = getCallToDisplay(callList, primary);
}
Logger.d(this, "Primary call: " + primary);
@@ -96,6 +91,14 @@ public class CallCardPresenter extends Presenter<CallCardPresenter.CallCardUi> i
null, this);
updateDisplayByCallerInfo(primary, primaryCallInfo, primary.getNumberPresentation(), true);
+ if (primary != null) {
+ ui.setNumber(primary.getNumber());
+ ui.setCallState(primary.getState(), primary.getDisconnectCause());
+ } else {
+ ui.setNumber("");
+ ui.setCallState(Call.State.INVALID, Call.DisconnectCause.UNKNOWN);
+ }
+
// Set secondary call data
if (secondary != null) {
ui.setSecondaryCallInfo(true, secondary.getNumber());
@@ -104,6 +107,41 @@ public class CallCardPresenter extends Presenter<CallCardPresenter.CallCardUi> i
}
}
+ /**
+ * Get the highest priority call to display.
+ * Goes through the calls and chooses which to return based on priority of which type of call
+ * to display to the user. Callers can use the "ignore" feature to get the second best call
+ * by passing a previously found primary call as ignore.
+ *
+ * @param ignore A call to ignore if found.
+ */
+ private Call getCallToDisplay(CallList callList, Call ignore) {
+
+ // Disconnected calls get primary position to let user know quickly
+ // what call has disconnected. Disconnected calls are very short lived.
+ Call retval = callList.getDisconnectedCall();
+ if (retval != null && retval != ignore) {
+ return retval;
+ }
+
+ // Active calls come second. An active call always gets precedent.
+ retval = callList.getActiveCall();
+ if (retval != null && retval != ignore) {
+ return retval;
+ }
+
+ // Then we go to background call (calls on hold)
+ retval = callList.getBackgroundCall();
+ if (retval != null && retval != ignore) {
+ return retval;
+ }
+
+ // Lastly, we go to a second background call.
+ retval = callList.getSecondBackgroundCall();
+
+ return retval;
+ }
+
public interface CallCardUi extends Ui {
// TODO(klp): Consider passing in the Call object directly in these methods.
void setVisible(boolean on);
@@ -115,6 +153,7 @@ public class CallCardPresenter extends Presenter<CallCardPresenter.CallCardUi> i
void setImage(Drawable drawable);
void setImage(Bitmap bitmap);
void setSecondaryCallInfo(boolean show, String number);
+ void setCallState(int state, Call.DisconnectCause cause);
}
@Override
diff --git a/InCallUI/src/com/android/incallui/CallHandlerService.java b/InCallUI/src/com/android/incallui/CallHandlerService.java
index f0d98b2ed..0b2be5663 100644
--- a/InCallUI/src/com/android/incallui/CallHandlerService.java
+++ b/InCallUI/src/com/android/incallui/CallHandlerService.java
@@ -42,6 +42,7 @@ public class CallHandlerService extends Service {
private static final int ON_UPDATE_CALL_WITH_TEXT_RESPONSES = 3;
private static final int ON_AUDIO_MODE = 4;
private static final int ON_SUPPORTED_AUDIO_MODE = 5;
+ private static final int ON_DISCONNECT_CALL = 6;
private CallList mCallList;
@@ -79,7 +80,7 @@ public class CallHandlerService extends Service {
@Override
public void onDisconnect(Call call) {
Logger.d(CallHandlerService.this, "onDisconnected");
- mMainHandler.sendMessage(mMainHandler.obtainMessage(ON_UPDATE_CALL, 0, 0, call));
+ mMainHandler.sendMessage(mMainHandler.obtainMessage(ON_DISCONNECT_CALL, 0, 0, call));
}
@Override
@@ -149,6 +150,9 @@ public class CallHandlerService extends Service {
case ON_UPDATE_CALL_WITH_TEXT_RESPONSES:
mCallList.onUpdate((AbstractMap.SimpleEntry<Call, List<String> >) msg.obj);
break;
+ case ON_DISCONNECT_CALL:
+ mCallList.onDisconnect((Call) msg.obj);
+ break;
case ON_AUDIO_MODE:
mAudioModeProvider.onAudioModeChange(msg.arg1);
break;
diff --git a/InCallUI/src/com/android/incallui/CallList.java b/InCallUI/src/com/android/incallui/CallList.java
index 5ea4fc559..bd631ce9f 100644
--- a/InCallUI/src/com/android/incallui/CallList.java
+++ b/InCallUI/src/com/android/incallui/CallList.java
@@ -23,6 +23,9 @@ import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
+import android.os.Handler;
+import android.os.Message;
+
import com.android.services.telephony.common.Call;
import java.util.AbstractMap;
@@ -39,6 +42,10 @@ import java.util.Set;
*/
public class CallList {
+ private static final int DISCONNECTED_CALL_TIMEOUT_MS = 3000;
+
+ private static final int EVENT_DISCONNECTED_TIMEOUT = 1;
+
private static CallList sInstance;
private final HashMap<Integer, Call> mCallMap = Maps.newHashMap();
@@ -66,7 +73,17 @@ public class CallList {
* Called when a single call has changed.
*/
public void onUpdate(Call call) {
- Logger.d(this, "onUpdate - " + call);
+ Logger.d(this, "onUpdate - ", call);
+
+ updateCallInMap(call);
+ notifyListenersOfChange();
+ }
+
+ /**
+ * Called when a single call disconnects.
+ */
+ public void onDisconnect(Call call) {
+ Logger.d(this, "onDisconnect: ", call);
updateCallInMap(call);
@@ -141,6 +158,10 @@ public class CallList {
return getFirstCallWithState(Call.State.ONHOLD);
}
+ public Call getDisconnectedCall() {
+ return getFirstCallWithState(Call.State.DISCONNECTED);
+ }
+
public Call getSecondBackgroundCall() {
return getCallWithState(Call.State.ONHOLD, 1);
}
@@ -200,7 +221,7 @@ public class CallList {
}
}
- Logger.d(this, "Found call: " + retval);
+ Logger.v(this, "Found call: ", retval);
return retval;
}
@@ -219,7 +240,21 @@ public class CallList {
final Integer id = new Integer(call.getCallId());
- if (!isCallDead(call)) {
+ if (call.getState() == Call.State.DISCONNECTED) {
+ // For disconnected calls, we want to keep them alive for a few seconds so that the UI
+ // has a chance to display anything it needs when a call is disconnected.
+
+ // Set up a timer to destroy the call after X seconds.
+ Message msg = mHandler.obtainMessage(EVENT_DISCONNECTED_TIMEOUT, call);
+ boolean sent = mHandler.sendMessageDelayed(msg, DISCONNECTED_CALL_TIMEOUT_MS);
+
+ Logger.d(this, "Retval from sendMessageDelayed: ", Boolean.toString(sent));
+
+ // Don't add disconnected calls that do not already exist in the map
+ if (mCallMap.containsKey(id)) {
+ mCallMap.put(id, call);
+ }
+ } else if (!isCallDead(call)) {
mCallMap.put(id, call);
} else if (mCallMap.containsKey(id)) {
mCallMap.remove(id);
@@ -246,6 +281,33 @@ public class CallList {
}
/**
+ * Sets up a call for deletion and notifies listeners of change.
+ */
+ private void finishDisconnectedCall(Call call) {
+ call.setState(Call.State.IDLE);
+ updateCallInMap(call);
+ notifyListenersOfChange();
+ }
+
+ /**
+ * Handles the timeout for destroying disconnected calls.
+ */
+ private Handler mHandler = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case EVENT_DISCONNECTED_TIMEOUT:
+ Logger.d(this, "EVENT_DISCONNECTED_TIMEOUT ", msg.obj);
+ finishDisconnectedCall((Call) msg.obj);
+ break;
+ default:
+ Logger.wtf(this, "Message not expected: " + msg.what);
+ break;
+ }
+ }
+ };
+
+ /**
* Listener interface for any class that wants to be notified of changes
* to the call list.
*/
diff --git a/InCallUI/src/com/android/incallui/InCallPresenter.java b/InCallUI/src/com/android/incallui/InCallPresenter.java
index 72a880a70..63f0aa524 100644
--- a/InCallUI/src/com/android/incallui/InCallPresenter.java
+++ b/InCallUI/src/com/android/incallui/InCallPresenter.java
@@ -105,7 +105,8 @@ public class InCallPresenter implements CallList.Listener {
} else if (callList.getOutgoingCall() != null) {
newState = InCallState.OUTGOING;
} else if (callList.getActiveCall() != null ||
- callList.getBackgroundCall() != null) {
+ callList.getBackgroundCall() != null ||
+ callList.getDisconnectedCall() != null) {
newState = InCallState.INCALL;
}
diff --git a/InCallUI/src/com/android/incallui/Logger.java b/InCallUI/src/com/android/incallui/Logger.java
index 5f628d296..e7cbe2025 100644
--- a/InCallUI/src/com/android/incallui/Logger.java
+++ b/InCallUI/src/com/android/incallui/Logger.java
@@ -41,9 +41,9 @@ import android.util.Log;
}
}
- public static void v(String tag, String msg) {
- if (VERBOSE) {
- Log.v(TAG, tag + msg);
+ public static void d(Object obj, String str1, Object str2) {
+ if (DEBUG) {
+ Log.d(TAG, getPrefix(obj) + str1 + str2);
}
}
@@ -61,6 +61,12 @@ import android.util.Log;
Log.e(TAG, tag + msg);
}
+ public static void v(Object obj, String str1, Object str2) {
+ if (VERBOSE) {
+ Log.d(TAG, getPrefix(obj) + str1 + str2);
+ }
+ }
+
public static void e(Object obj, String msg, Exception e) {
Log.e(TAG, getPrefix(obj) + msg, e);
}
@@ -77,6 +83,10 @@ import android.util.Log;
Log.i(TAG, getPrefix(obj) + msg);
}
+ public static void wtf(Object obj, String msg) {
+ Log.wtf(TAG, getPrefix(obj) + msg);
+ }
+
private static String getPrefix(Object obj) {
return (obj == null ? "" : (obj.getClass().getSimpleName() + " - "));
}