summaryrefslogtreecommitdiffstats
path: root/src/com
diff options
context:
space:
mode:
authorSandeep Kunta <skunta@codeaurora.org>2014-09-01 17:18:43 +0530
committerLinux Build Service Account <lnxbuild@localhost>2015-10-06 03:20:54 -0600
commitb2d5e04292cdd38c01e34eb7ea2ac3b059ca6c73 (patch)
treef9ce68a0029596fafc6f9f278c5ef50f839334aa /src/com
parenta01dabbd5818d283f811fff38417a274c130d7dd (diff)
downloadpackages_apps_InCallUI-b2d5e04292cdd38c01e34eb7ea2ac3b059ca6c73.tar.gz
packages_apps_InCallUI-b2d5e04292cdd38c01e34eb7ea2ac3b059ca6c73.tar.bz2
packages_apps_InCallUI-b2d5e04292cdd38c01e34eb7ea2ac3b059ca6c73.zip
MSIM: Add support for DSDA.
Add support to show calls from both subscriptions in a tabbed view format to user. when ever user switches sub, inform telecomm service that subscription is switched. Change-Id: I3bea71501ce159e189f75db58e710ffc94e8137c
Diffstat (limited to 'src/com')
-rw-r--r--src/com/android/incallui/AnswerPresenter.java138
-rw-r--r--src/com/android/incallui/Call.java45
-rw-r--r--src/com/android/incallui/CallButtonPresenter.java14
-rw-r--r--src/com/android/incallui/CallList.java208
-rw-r--r--src/com/android/incallui/ConferenceManagerFragment.java9
-rw-r--r--src/com/android/incallui/InCallActivity.java147
-rw-r--r--src/com/android/incallui/InCallPresenter.java35
-rw-r--r--src/com/android/incallui/InCallServiceImpl.java14
-rw-r--r--src/com/android/incallui/StatusBarNotifier.java10
-rw-r--r--src/com/android/incallui/TelecomAdapter.java8
10 files changed, 574 insertions, 54 deletions
diff --git a/src/com/android/incallui/AnswerPresenter.java b/src/com/android/incallui/AnswerPresenter.java
index 1468637c..505d2139 100644
--- a/src/com/android/incallui/AnswerPresenter.java
+++ b/src/com/android/incallui/AnswerPresenter.java
@@ -37,50 +37,69 @@ import java.util.List;
public class AnswerPresenter extends Presenter<AnswerPresenter.AnswerUi>
implements CallList.CallUpdateListener, InCallPresenter.InCallUiListener,
InCallPresenter.IncomingCallListener,
- CallList.Listener {
+ CallList.Listener, CallList.ActiveSubChangeListener {
private static final String TAG = AnswerPresenter.class.getSimpleName();
- private String mCallId;
- private Call mCall = null;
+ private String mCallId[] = new String[InCallServiceImpl.sPhoneCount];
+ private Call mCall[] = new Call[InCallServiceImpl.sPhoneCount];
+ private final CallList mCalls = CallList.getInstance();
private boolean mHasTextMessages = false;
@Override
public void onUiShowing(boolean showing) {
if (showing) {
- CallList.getInstance().addListener(this);
- final CallList calls = CallList.getInstance();
+ mCalls.addListener(this);
+ mCalls.addActiveSubChangeListener(this);
Call call;
- call = calls.getIncomingCall();
- if (call != null) {
- processIncomingCall(call);
+ // Consider incoming/waiting calls on both subscriptions
+ // for DSDA.
+ for (int i = 0; i < InCallServiceImpl.sPhoneCount; i++) {
+ int[] subId = mCalls.getSubId(i);
+ call = mCalls.getCallWithState(Call.State.INCOMING, 0, subId[0]);
+ if (call == null) {
+ call = mCalls.getCallWithState(Call.State.CALL_WAITING, 0, subId[0]);
+ }
+ if (call != null) {
+ processIncomingCall(call);
+ }
}
- call = calls.getVideoUpgradeRequestCall();
+ call = mCalls.getVideoUpgradeRequestCall();
Log.d(this, "getVideoUpgradeRequestCall call =" + call);
if (call != null) {
processVideoUpgradeRequestCall(call);
}
} else {
- CallList.getInstance().removeListener(this);
+ mCalls.removeListener(this);
// This is necessary because the activity can be destroyed while an incoming call exists.
// This happens when back button is pressed while incoming call is still being shown.
- if (mCallId != null) {
- CallList.getInstance().removeCallUpdateListener(mCallId, this);
+ for (int i = 0; i < InCallServiceImpl.sPhoneCount; i++) {
+ int[] subId = mCalls.getSubId(i);
+ Call call = mCalls.getCallWithState(Call.State.INCOMING, 0, subId[0]);
+ if (call == null) {
+ call = mCalls.getCallWithState(Call.State.CALL_WAITING, 0, subId[0]);
+ }
+ if (mCallId[i] != null && call == null) {
+ mCalls.removeCallUpdateListener(mCallId[i], this);
+ mCalls.removeActiveSubChangeListener(this);
+ }
}
}
}
@Override
public void onIncomingCall(InCallState oldState, InCallState newState, Call call) {
+ int subId = call.getSubId();
+ int phoneId = mCalls.getPhoneId(subId);
Log.d(this, "onIncomingCall: " + this);
- Call modifyCall = CallList.getInstance().getVideoUpgradeRequestCall();
+ Call modifyCall = mCalls.getVideoUpgradeRequestCall();
if (modifyCall != null) {
showAnswerUi(false);
Log.d(this, "declining upgrade request id: ");
- CallList.getInstance().removeCallUpdateListener(mCallId, this);
+ mCalls.removeCallUpdateListener(mCallId[phoneId], this);
InCallPresenter.getInstance().declineUpgradeRequest(getUi().getContext());
}
- if (!call.getId().equals(mCallId)) {
+ if (!call.getId().equals(mCallId[phoneId])) {
// A new call is coming in.
processIncomingCall(call);
}
@@ -105,7 +124,11 @@ public class AnswerPresenter extends Presenter<AnswerPresenter.AnswerUi>
if (!isUpgradePending) {
// Stop listening for updates.
- CallList.getInstance().removeCallUpdateListener(mCallId, this);
+ for (int i = 0; i < InCallServiceImpl.sPhoneCount; i++) {
+ if (mCallId[i] != null) {
+ mCalls.removeCallUpdateListener(mCallId[i], this);
+ }
+ }
showAnswerUi(false);
}
}
@@ -133,15 +156,17 @@ public class AnswerPresenter extends Presenter<AnswerPresenter.AnswerUi>
}
private void processIncomingCall(Call call) {
- mCallId = call.getId();
- mCall = call;
+ int subId = call.getSubId();
+ int phoneId = mCalls.getPhoneId(subId);
+ mCallId[phoneId] = call.getId();
+ mCall[phoneId] = call;
// Listen for call updates for the current call.
- CallList.getInstance().addCallUpdateListener(mCallId, this);
+ mCalls.addCallUpdateListener(mCallId[phoneId], this);
- Log.d(TAG, "Showing incoming for call id: " + mCallId + " " + this);
+ Log.d(TAG, "Showing incoming for call id: " + mCallId[phoneId] + " " + this);
if (showAnswerUi(true)) {
- final List<String> textMsgs = CallList.getInstance().getTextResponses(call.getId());
+ final List<String> textMsgs = mCalls.getTextResponses(call.getId());
configureAnswerTargetsForSms(call, textMsgs);
}
}
@@ -161,11 +186,13 @@ public class AnswerPresenter extends Presenter<AnswerPresenter.AnswerUi>
private void processVideoUpgradeRequestCall(Call call) {
Log.d(this, " processVideoUpgradeRequestCall call=" + call);
- mCallId = call.getId();
- mCall = call;
+ int subId = call.getSubId();
+ int phoneId = mCalls.getPhoneId(subId);
+ mCallId[phoneId] = call.getId();
+ mCall[phoneId] = call;
// Listen for call updates for the current call.
- CallList.getInstance().addCallUpdateListener(mCallId, this);
+ CallList.getInstance().addCallUpdateListener(mCallId[phoneId], this);
final int currentVideoState = call.getVideoState();
final int modifyToVideoState = call.getModifyToVideoState();
@@ -196,12 +223,14 @@ public class AnswerPresenter extends Presenter<AnswerPresenter.AnswerUi>
Log.d(this, "onCallStateChange() " + call + " " + this);
if (call.getState() != Call.State.INCOMING) {
boolean isUpgradePending = isVideoUpgradePending(call);
+ int subId = call.getSubId();
+ int phoneId = mCalls.getPhoneId(subId);
if (!isUpgradePending) {
// Stop listening for updates.
- CallList.getInstance().removeCallUpdateListener(mCallId, this);
+ mCalls.removeCallUpdateListener(mCallId[phoneId], this);
}
- final Call incall = CallList.getInstance().getIncomingCall();
+ final Call incall = mCalls.getIncomingCall();
if (incall != null || isUpgradePending) {
showAnswerUi(true);
} else {
@@ -210,25 +239,43 @@ public class AnswerPresenter extends Presenter<AnswerPresenter.AnswerUi>
mHasTextMessages = false;
} else if (!mHasTextMessages) {
- final List<String> textMsgs = CallList.getInstance().getTextResponses(call.getId());
+ final List<String> textMsgs = mCalls.getTextResponses(call.getId());
if (textMsgs != null) {
configureAnswerTargetsForSms(call, textMsgs);
}
}
}
+ // get active phoneId, for which call is visible to user
+ private int getActivePhoneId() {
+ int phoneId = -1;
+ if (InCallServiceImpl.isDsdaEnabled()) {
+ int subId = mCalls.getActiveSubId();
+ phoneId = mCalls.getPhoneId(subId);
+ } else {
+ for (int i = 0; i < mCall.length; i++) {
+ if (mCall[i] != null) {
+ phoneId = i;
+ }
+ }
+ }
+ return phoneId;
+ }
+
public void onAnswer(int videoState, Context context) {
- if (mCallId == null) {
+ int phoneId = getActivePhoneId();
+ Log.i(this, "onAnswer mCallId:" + mCallId + "phoneId:" + phoneId);
+ if (mCallId == null || phoneId == -1) {
return;
}
- if (mCall.getSessionModificationState()
+ if (mCall[phoneId].getSessionModificationState()
== Call.SessionModificationState.RECEIVED_UPGRADE_TO_VIDEO_REQUEST) {
Log.d(this, "onAnswer (upgradeCall) mCallId=" + mCallId + " videoState=" + videoState);
InCallPresenter.getInstance().acceptUpgradeRequest(videoState, context);
} else {
Log.d(this, "onAnswer (answerCall) mCallId=" + mCallId + " videoState=" + videoState);
- TelecomAdapter.getInstance().answerCall(mCall.getId(), videoState);
+ TelecomAdapter.getInstance().answerCall(mCall[phoneId].getId(), videoState);
}
}
@@ -237,12 +284,13 @@ public class AnswerPresenter extends Presenter<AnswerPresenter.AnswerUi>
* reject since it seems to be more prevalent.
*/
public void onDecline(Context context) {
- Log.d(this, "onDecline " + mCallId);
- if (mCall.getSessionModificationState()
+ int phoneId = getActivePhoneId();
+ Log.d(this, "onDecline mCallId:" + mCallId + "phoneId:" + phoneId);
+ if (mCall[phoneId].getSessionModificationState()
== Call.SessionModificationState.RECEIVED_UPGRADE_TO_VIDEO_REQUEST) {
InCallPresenter.getInstance().declineUpgradeRequest(context);
} else {
- TelecomAdapter.getInstance().rejectCall(mCall.getId(), false, null);
+ TelecomAdapter.getInstance().rejectCall(mCall[phoneId].getId(), false, null);
}
}
@@ -254,8 +302,9 @@ public class AnswerPresenter extends Presenter<AnswerPresenter.AnswerUi>
}
public void rejectCallWithMessage(String message) {
- Log.d(this, "sendTextToDefaultActivity()...");
- TelecomAdapter.getInstance().rejectCall(mCall.getId(), true, message);
+ int phoneId = getActivePhoneId();
+ Log.i(this, "sendTextToDefaultActivity()...phoneId:" + phoneId);
+ TelecomAdapter.getInstance().rejectCall(mCall[phoneId].getId(), true, message);
onDismissDialog();
}
@@ -302,4 +351,23 @@ public class AnswerPresenter extends Presenter<AnswerPresenter.AnswerUi>
public void configureMessageDialog(List<String> textResponses);
public Context getContext();
}
+
+ @Override
+ public void onActiveSubChanged(int subId) {
+ final Call call = mCalls.getIncomingCall();
+ int phoneId = CallList.getInstance().getPhoneId(subId);
+ if ((call != null) && (call.getId() == mCallId[phoneId])) {
+ Log.d(this, "Show incoming for call id: " + mCallId[phoneId] + " " + this);
+ if (showAnswerUi(true)) {
+ final List<String> textMsgs = mCalls.getTextResponses(
+ call.getId());
+ configureAnswerTargetsForSms(call, textMsgs);
+ }
+ } else if ((call == null) && (mCalls.hasAnyLiveCall(subId))) {
+ Log.d(this, "Hide incoming for call id: " + mCallId[phoneId] + " " + this);
+ showAnswerUi(false);
+ } else {
+ Log.d(this, "No incoming call present for sub = " + subId + " " + this);
+ }
+ }
}
diff --git a/src/com/android/incallui/Call.java b/src/com/android/incallui/Call.java
index ee73db2b..e73a4f47 100644
--- a/src/com/android/incallui/Call.java
+++ b/src/com/android/incallui/Call.java
@@ -30,6 +30,7 @@ import android.telecom.GatewayInfo;
import android.telecom.InCallService.VideoCall;
import android.telecom.PhoneAccountHandle;
import android.telecom.VideoProfile;
+import android.telephony.SubscriptionManager;
import android.text.TextUtils;
import java.util.ArrayList;
@@ -241,6 +242,7 @@ public class Call {
}
};
+ public boolean mIsActiveSub = false;
private android.telecom.Call mTelecommCall;
private final String mId;
private int mState = State.INVALID;
@@ -300,6 +302,7 @@ public class Call {
Log.d(this, "updateFromTelecommCall: " + mTelecommCall.toString());
setState(translateState(mTelecommCall.getState()));
setDisconnectCause(mTelecommCall.getDetails().getDisconnectCause());
+ mIsActiveSub = mTelecommCall.isActive();
if (mTelecommCall.getVideoCall() != null) {
if (mVideoCallCallback == null) {
@@ -416,9 +419,29 @@ public class Call {
int supportedCapabilities = mTelecommCall.getDetails().getCallCapabilities();
if ((capabilities & android.telecom.Call.Details.CAPABILITY_MERGE_CONFERENCE) != 0) {
+ if (InCallServiceImpl.isDsdaEnabled()) {
+ List<android.telecom.Call> conferenceableCalls =
+ mTelecommCall.getConferenceableCalls();
+ boolean hasConferenceableCall = false;
+ if (!conferenceableCalls.isEmpty()){
+ int subId = getSubId();
+ for (android.telecom.Call call : conferenceableCalls) {
+ PhoneAccountHandle phHandle = call.getDetails().getAccountHandle();
+ if ((phHandle != null) && ((Integer.parseInt(phHandle.getId())) == subId)) {
+ hasConferenceableCall = true;
+ break;
+ }
+ }
+ }
+ if (!hasConferenceableCall &&
+ ((android.telecom.Call.Details.CAPABILITY_MERGE_CONFERENCE
+ & supportedCapabilities) == 0)) {
+ // Cannot merge calls if there are no calls to merge with.
+ return false;
+ }
// We allow you to merge if the capabilities allow it or if it is a call with
// conferenceable calls.
- if (mTelecommCall.getConferenceableCalls().isEmpty() &&
+ } else if (mTelecommCall.getConferenceableCalls().isEmpty() &&
((android.telecom.Call.Details.CAPABILITY_MERGE_CONFERENCE
& supportedCapabilities) == 0)) {
// Cannot merge calls if there are no calls to merge with.
@@ -451,6 +474,22 @@ public class Call {
return mTelecommCall == null ? null : mTelecommCall.getDetails().getAccountHandle();
}
+ public int getSubId() {
+ PhoneAccountHandle ph = getAccountHandle();
+ if (ph != null) {
+ try {
+ if (ph.getId() != null ) {
+ return Integer.parseInt(getAccountHandle().getId());
+ }
+ } catch (NumberFormatException e) {
+ Log.w(this,"sub Id is not a number " + e);
+ }
+ return SubscriptionManager.getDefaultVoiceSubId();
+ } else {
+ return SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+ }
+ }
+
public VideoCall getVideoCall() {
return mTelecommCall == null ? null : mTelecommCall.getVideoCall();
}
@@ -562,7 +601,7 @@ public class Call {
}
return String.format(Locale.US, "[%s, %s, %s, children:%s, parent:%s, conferenceable:%s, " +
- "videoState:%s, mSessionModificationState:%d, VideoSettings:%s]",
+ "videoState:%s, mSessionModificationState:%d, VideoSettings:%s, mIsActivSub:%b]",
mId,
State.toString(getState()),
android.telecom.Call.Details
@@ -572,7 +611,7 @@ public class Call {
this.mTelecommCall.getConferenceableCalls(),
VideoProfile.videoStateToString(mTelecommCall.getDetails().getVideoState()),
mSessionModificationState,
- getVideoSettings());
+ getVideoSettings(), mIsActiveSub);
}
public String toSimpleString() {
diff --git a/src/com/android/incallui/CallButtonPresenter.java b/src/com/android/incallui/CallButtonPresenter.java
index e1f45f01..dfcaca30 100644
--- a/src/com/android/incallui/CallButtonPresenter.java
+++ b/src/com/android/incallui/CallButtonPresenter.java
@@ -22,6 +22,8 @@ import android.content.Context;
import android.os.Bundle;
import android.telecom.CallAudioState;
import android.telecom.InCallService.VideoCall;
+import android.telecom.PhoneAccount;
+import android.telecom.PhoneAccountHandle;
import android.telecom.VideoProfile;
import com.android.incallui.AudioModeProvider.AudioModeListener;
@@ -39,7 +41,7 @@ import java.util.Objects;
*/
public class CallButtonPresenter extends Presenter<CallButtonPresenter.CallButtonUi>
implements InCallStateListener, AudioModeListener, IncomingCallListener,
- InCallDetailsListener, CanAddCallListener, Listener {
+ InCallDetailsListener, CanAddCallListener, CallList.ActiveSubChangeListener, Listener {
private static final String KEY_AUTOMATICALLY_MUTED = "incall_key_automatically_muted";
private static final String KEY_PREVIOUS_MUTE_STATE = "incall_key_previous_mute_state";
@@ -64,6 +66,7 @@ public class CallButtonPresenter extends Presenter<CallButtonPresenter.CallButto
inCallPresenter.addDetailsListener(this);
inCallPresenter.addCanAddCallListener(this);
inCallPresenter.getInCallCameraManager().addCameraSelectionListener(this);
+ CallList.getInstance().addActiveSubChangeListener(this);
// Update the buttons state immediately for the current call
onStateChange(InCallState.NO_CALLS, inCallPresenter.getInCallState(),
@@ -80,6 +83,7 @@ public class CallButtonPresenter extends Presenter<CallButtonPresenter.CallButto
InCallPresenter.getInstance().removeDetailsListener(this);
InCallPresenter.getInstance().getInCallCameraManager().removeCameraSelectionListener(this);
InCallPresenter.getInstance().removeCanAddCallListener(this);
+ CallList.getInstance().removeActiveSubChangeListener(this);
}
@Override
@@ -380,7 +384,6 @@ public class CallButtonPresenter extends Presenter<CallButtonPresenter.CallButto
final boolean isCallOnHold = call.getState() == Call.State.ONHOLD;
final boolean useExt = QtiCallUtils.useExt(ui.getContext());
-
final boolean showAddCall = TelecomAdapter.getInstance().canAddCall();
final boolean showMerge = call.can(
android.telecom.Call.Details.CAPABILITY_MERGE_CONFERENCE);
@@ -465,4 +468,11 @@ public class CallButtonPresenter extends Presenter<CallButtonPresenter.CallButto
}
getUi().setCameraSwitched(!isUsingFrontFacingCamera);
}
+
+ public void onActiveSubChanged(int subId) {
+ InCallState state = InCallPresenter.getInstance()
+ .getPotentialStateFromCallList(CallList.getInstance());
+
+ onStateChange(null, state, CallList.getInstance());
+ }
}
diff --git a/src/com/android/incallui/CallList.java b/src/com/android/incallui/CallList.java
index c0014bdf..5b1855d7 100644
--- a/src/com/android/incallui/CallList.java
+++ b/src/com/android/incallui/CallList.java
@@ -24,8 +24,12 @@ import android.telecom.PhoneAccount;
import com.android.contacts.common.testing.NeededForTesting;
import com.google.common.base.Preconditions;
+import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
+import android.telecom.PhoneAccountHandle;
+import android.telephony.SubscriptionManager;
+import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
@@ -46,6 +50,8 @@ public class CallList {
private static final int DISCONNECTED_CALL_LONG_TIMEOUT_MS = 5000;
private static final int EVENT_DISCONNECTED_TIMEOUT = 1;
+ private static final int EVENT_NOTIFY_CHANGE = 2;
+
private static CallList sInstance = new CallList();
@@ -63,6 +69,9 @@ public class CallList {
.newHashMap();
private final Set<Call> mPendingDisconnectCalls = Collections.newSetFromMap(
new ConcurrentHashMap<Call, Boolean>(8, 0.9f, 1));
+ private int mSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+ private final ArrayList<ActiveSubChangeListener> mActiveSubChangeListeners =
+ Lists.newArrayList();
/**
* Static singleton accessor method.
@@ -102,6 +111,18 @@ public class CallList {
}
}
+ int getPhoneId(int subId) {
+ int phoneId = SubscriptionManager.getPhoneId(subId);
+ if (phoneId >= InCallServiceImpl.sPhoneCount || phoneId < 0) {
+ phoneId = 0;
+ }
+ return phoneId;
+ }
+
+ int[] getSubId(int phoneId) {
+ return SubscriptionManager.getSubId(phoneId);
+ }
+
/**
* Called when a single call disconnects.
*/
@@ -119,6 +140,18 @@ public class CallList {
* Called when a single call has changed.
*/
public void onIncoming(Call call, List<String> textMessages) {
+ Log.d(this, "onIncoming - " + call);
+
+ // Update active subscription from call object. it will be set by
+ // Telecomm service for incoming call and whenever active sub changes.
+ if (call.mIsActiveSub) {
+ int sub = Integer.parseInt(call.getAccountHandle().getId());
+ Log.d(this, "onIncoming - sub:" + sub + " mSubId:" + mSubId);
+ if (sub != mSubId) {
+ setActiveSubId(sub);
+ }
+ }
+
if (updateCallInMap(call)) {
Log.i(this, "onIncoming - " + call);
}
@@ -140,6 +173,19 @@ public class CallList {
*/
public void onUpdate(Call call) {
Trace.beginSection("onUpdate");
+ PhoneAccountHandle ph = call.getAccountHandle();
+ Log.d(this, "onUpdate - " + call + " ph:" + ph);
+ try {
+ if (call.mIsActiveSub && ph != null) {
+ int sub = Integer.parseInt(ph.getId());
+ Log.d(this, "onUpdate - sub:" + sub + " mSubId:" + mSubId);
+ if(sub != mSubId) {
+ setActiveSubId(sub);
+ }
+ }
+ } catch (NumberFormatException e) {
+ Log.w(this,"Sub Id is not a number " + e);
+ }
onUpdateCall(call);
notifyGenericListeners();
Trace.endSection();
@@ -356,6 +402,13 @@ public class CallList {
* TODO: Improve this logic to sort by call time.
*/
public Call getCallWithState(int state, int positionToFind) {
+ // if DSDA is enabled call getCallWithState with active subscription.
+ if (state != Call.State.SELECT_PHONE_ACCOUNT && getActiveSubId()
+ != SubscriptionManager.INVALID_SUBSCRIPTION_ID
+ && InCallServiceImpl.isDsdaEnabled()) {
+ return getCallWithState(state, positionToFind, getActiveSubId());
+ }
+
Call retval = null;
int position = 0;
for (Call call : mCallById.values()) {
@@ -559,6 +612,13 @@ public class CallList {
Log.d(this, "EVENT_DISCONNECTED_TIMEOUT ", msg.obj);
finishDisconnectedCall((Call) msg.obj);
break;
+ case EVENT_NOTIFY_CHANGE:
+ Log.d(this, "EVENT_NOTIFY_CHANGE: ");
+ notifyGenericListeners();
+ for (ActiveSubChangeListener listener : mActiveSubChangeListeners) {
+ listener.onActiveSubChanged(getActiveSubId());
+ }
+ break;
default:
Log.wtf(this, "Message not expected: " + msg.what);
break;
@@ -612,4 +672,152 @@ public class CallList {
*/
public void onSessionModificationStateChange(int sessionModificationState);
}
+
+ /**
+ * Called when active subscription changes.
+ */
+ void onActiveSubChanged(int activeSub) {
+ Log.d(this, "onActiveSubChanged = " + activeSub);
+ if (hasAnyLiveCall(activeSub)) {
+ setActiveSubId(activeSub);
+ }
+ }
+
+ int getActiveSubId() {
+ return mSubId;
+ }
+
+ /**
+ * Called to update the latest active subscription id, and also it
+ * notifies the registred clients about subscription change information.
+ */
+ void setActiveSubId(int subId) {
+ if (subId != mSubId) {
+ Log.d(this, "setActiveSubId, oldActiveSubId = " + mSubId +
+ " newActiveSubId = " + subId);
+ mSubId = subId;
+ final Message msg = mHandler.obtainMessage(EVENT_NOTIFY_CHANGE, null);
+ mHandler.sendMessage(msg);
+ }
+ }
+
+ /**
+ * Returns true, if any voice call is ACTIVE on the provided subscription.
+ */
+ boolean hasAnyLiveCall(int subId) {
+ for (Call call : mCallById.values()) {
+ PhoneAccountHandle ph = call.getAccountHandle();
+ try {
+ if (!isCallDead(call) && ph != null && (Integer.parseInt(ph.getId()) == subId)) {
+ Log.d(this, "hasAnyLiveCall sub = " + subId);
+ return true;
+ }
+ } catch (NumberFormatException e) {
+ Log.w(this,"Sub Id is not a number " + e);
+ }
+ }
+ Log.d(this, "no active call ");
+ return false;
+ }
+
+ /**
+ * Returns true, if any call is ACTIVE
+ */
+ boolean hasAnyLiveCall() {
+ for (Call call : mCallById.values()) {
+ if (!isCallDead(call)) {
+ Log.d(this, "hasAnyLiveCall call = " + call);
+ return true;
+ }
+ }
+ Log.d(this, "no active call ");
+ return false;
+ }
+
+ /**
+ * This method checks whether any other subscription currently has active voice
+ * call other than current active subscription, if yes it makes that other
+ * subscription as active subscription i.e user visible subscription.
+ * @param retainLch whether to retain the LCH state of the other active sub
+ */
+ boolean switchToOtherActiveSub() {
+ int activeSub = getActiveSubId();
+ boolean subSwitched = false;
+
+ for (int i = 0; i < InCallServiceImpl.sPhoneCount; i++) {
+ int[] subId = getSubId(i);
+ if ((subId[0] != activeSub) && hasAnyLiveCall(subId[0])) {
+ Log.d(this, "switchToOtherActiveSub, subId = " + subId[0]);
+ subSwitched = true;
+ TelecomAdapter.getInstance().switchToOtherActiveSub(
+ String.valueOf(subId[0]));
+ setActiveSubId(subId[0]);
+ break;
+ }
+ }
+ return subSwitched;
+ }
+
+ /**
+ * Method to check if there is any live call in a sub other than the one supplied.
+ * @param currentSub The subscription to exclude while checking for active calls.
+ */
+ boolean isAnyOtherSubActive(int currentSub) {
+ boolean result = false;
+ if(!InCallServiceImpl.isDsdaEnabled()) {
+ return false;
+ }
+
+ for (int phoneId = 0; phoneId < InCallServiceImpl.sPhoneCount;
+ phoneId++) {
+ int[] subId = getSubId(phoneId);
+
+ if ((subId[0] != currentSub) && hasAnyLiveCall(subId[0])) {
+ Log.d(this, "Live call found on another sub = " + subId[0]);
+ result = true;
+ break;
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Returns the [position]th call which belongs to provided subscription and
+ * found in the call map with the specified state.
+ */
+ Call getCallWithState(int state, int positionToFind, int subId) {
+ Call retval = null;
+ int position = 0;
+ for (Call call : mCallById.values()) {
+ PhoneAccountHandle ph = call.getAccountHandle();
+ try {
+ if ((call.getState() == state) && ((ph == null) ||
+ (ph != null && (Integer.parseInt(ph.getId()) == subId)))) {
+ if (position >= positionToFind) {
+ retval = call;
+ break;
+ } else {
+ position++;
+ }
+ }
+ } catch (NumberFormatException e) {
+ Log.w(this,"Sub Id is not a number " + e);
+ }
+ }
+ return retval;
+ }
+
+ void addActiveSubChangeListener(ActiveSubChangeListener listener) {
+ Preconditions.checkNotNull(listener);
+ mActiveSubChangeListeners.add(listener);
+ }
+
+ void removeActiveSubChangeListener(ActiveSubChangeListener listener) {
+ Preconditions.checkNotNull(listener);
+ mActiveSubChangeListeners.remove(listener);
+ }
+
+ interface ActiveSubChangeListener {
+ public void onActiveSubChanged(int subId);
+ }
}
diff --git a/src/com/android/incallui/ConferenceManagerFragment.java b/src/com/android/incallui/ConferenceManagerFragment.java
index f5f52fcb..aaf41ade 100644
--- a/src/com/android/incallui/ConferenceManagerFragment.java
+++ b/src/com/android/incallui/ConferenceManagerFragment.java
@@ -98,10 +98,13 @@ public class ConferenceManagerFragment
public void onVisibilityChanged(boolean isVisible) {
mIsVisible = isVisible;
ActionBar actionBar = getActivity().getActionBar();
+ boolean isDsdaEnabled = InCallServiceImpl.isDsdaEnabled();
if (isVisible) {
actionBar.setTitle(R.string.manageConferenceLabel);
actionBar.setElevation(mActionBarElevation);
- actionBar.setHideOffset(0);
+ if (!isDsdaEnabled) {
+ actionBar.setHideOffset(0);
+ }
actionBar.show();
final CallList calls = CallList.getInstance();
@@ -111,7 +114,9 @@ public class ConferenceManagerFragment
mConferenceParticipantList.requestFocus();
} else {
actionBar.setElevation(0);
- actionBar.setHideOffset(actionBar.getHeight());
+ if (!isDsdaEnabled) {
+ actionBar.setHideOffset(actionBar.getHeight());
+ }
}
}
diff --git a/src/com/android/incallui/InCallActivity.java b/src/com/android/incallui/InCallActivity.java
index 2f3020f2..7466c82d 100644
--- a/src/com/android/incallui/InCallActivity.java
+++ b/src/com/android/incallui/InCallActivity.java
@@ -17,6 +17,8 @@
package com.android.incallui;
import android.app.ActionBar;
+import android.app.FragmentTransaction;
+import android.app.ActionBar.Tab;
import android.app.Activity;
import android.app.ActivityManager;
import android.app.AlertDialog;
@@ -30,6 +32,7 @@ import android.content.DialogInterface.OnClickListener;
import android.content.DialogInterface.OnCancelListener;
import android.content.Intent;
import android.content.res.Configuration;
+import android.content.res.TypedArray;
import android.graphics.Point;
import android.hardware.SensorManager;
import android.os.Bundle;
@@ -48,6 +51,8 @@ import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.view.accessibility.AccessibilityEvent;
+import android.widget.ImageView;
+import android.widget.TextView;
import com.android.phone.common.animation.AnimUtils;
import com.android.phone.common.animation.AnimationListenerAdapter;
@@ -116,6 +121,13 @@ public class InCallActivity extends Activity implements FragmentDisplayManager {
private Animation mSlideOut;
private boolean mDismissKeyguard = false;
+ private final int TAB_COUNT_ONE = 1;
+ private final int TAB_COUNT_TWO = 2;
+ private final int TAB_POSITION_FIRST = 0;
+
+ private Tab[] mDsdaTab = new Tab[TAB_COUNT_TWO];
+ private boolean[] mDsdaTabAdd = {false, false};
+
AnimationListenerAdapter mSlideOutListener = new AnimationListenerAdapter() {
@Override
public void onAnimationEnd(Animation animation) {
@@ -149,14 +161,19 @@ public class InCallActivity extends Activity implements FragmentDisplayManager {
| 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();
+ boolean isDsdaEnabled = InCallServiceImpl.isDsdaEnabled();
+ if (isDsdaEnabled) {
+ requestWindowFeature(Window.FEATURE_ACTION_BAR);
+ getActionBar().setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
+ getActionBar().setDisplayShowTitleEnabled(false);
+ getActionBar().setDisplayShowHomeEnabled(false);
+ } else {
+ requestWindowFeature(Window.FEATURE_ACTION_BAR_OVERLAY);
+ if (getActionBar() != null) {
+ getActionBar().setDisplayHomeAsUpEnabled(true);
+ getActionBar().setDisplayShowTitleEnabled(true);
+ getActionBar().hide();
+ }
}
// TODO(klp): Do we need to add this back when prox sensor is not available?
@@ -216,6 +233,9 @@ public class InCallActivity extends Activity implements FragmentDisplayManager {
mInCallOrientationEventListener = new InCallOrientationEventListener(this);
+ if (isDsdaEnabled ) {
+ initializeDsdaSwitchTab();
+ }
Log.d(this, "onCreate(): exit");
}
@@ -859,6 +879,117 @@ public class InCallActivity extends Activity implements FragmentDisplayManager {
}
}
+ private void initializeDsdaSwitchTab() {
+ int phoneCount = InCallServiceImpl.sPhoneCount;
+ ActionBar bar = getActionBar();
+ View[] mDsdaTabLayout = new View[phoneCount];
+ TypedArray icons = getResources().obtainTypedArray(R.array.sim_icons);
+ int[] subString = {R.string.sub_1, R.string.sub_2};
+
+ for (int i = 0; i < phoneCount; i++) {
+ mDsdaTabLayout[i] = getLayoutInflater()
+ .inflate(R.layout.msim_tab_sub_info, null);
+
+ ((ImageView)mDsdaTabLayout[i].findViewById(R.id.tabSubIcon))
+ .setBackground(icons.getDrawable(i));
+
+ ((TextView)mDsdaTabLayout[i].findViewById(R.id.tabSubText))
+ .setText(subString[i]);
+
+ mDsdaTab[i] = bar.newTab().setCustomView(mDsdaTabLayout[i])
+ .setTabListener(new TabListener(i));
+ }
+ }
+
+ public void updateDsdaTab() {
+ int phoneCount = InCallServiceImpl.sPhoneCount;
+ ActionBar bar = getActionBar();
+
+ for (int i = 0; i < phoneCount; i++) {
+ int[] subId = CallList.getInstance().getSubId(i);
+ if (subId != null && CallList.getInstance().hasAnyLiveCall(subId[0])) {
+ if (!mDsdaTabAdd[i]) {
+ addDsdaTab(i);
+ }
+ } else {
+ removeDsdaTab(i);
+ }
+ }
+
+ updateDsdaTabSelection();
+ }
+
+ private void addDsdaTab(int subId) {
+ ActionBar bar = getActionBar();
+ int tabCount = bar.getTabCount();
+
+ if (tabCount < subId) {
+ bar.addTab(mDsdaTab[subId], false);
+ } else {
+ bar.addTab(mDsdaTab[subId], subId, false);
+ }
+ mDsdaTabAdd[subId] = true;
+ Log.d(this, "addDsdaTab, subId = " + subId + " tab count = " + tabCount);
+ }
+
+ private void removeDsdaTab(int subId) {
+ ActionBar bar = getActionBar();
+ int tabCount = bar.getTabCount();
+
+ for (int i = 0; i < tabCount; i++) {
+ if (bar.getTabAt(i).equals(mDsdaTab[subId])) {
+ bar.removeTab(mDsdaTab[subId]);
+ mDsdaTabAdd[subId] = false;
+ return;
+ }
+ }
+ Log.d(this, "removeDsdaTab, subId = " + subId + " tab count = " + tabCount);
+ }
+
+ private void updateDsdaTabSelection() {
+ ActionBar bar = getActionBar();
+ int barCount = bar.getTabCount();
+
+ if (barCount == TAB_COUNT_ONE) {
+ bar.selectTab(bar.getTabAt(TAB_POSITION_FIRST));
+ } else if (barCount == TAB_COUNT_TWO) {
+ int phoneId = CallList.getInstance().getPhoneId(CallList
+ .getInstance().getActiveSubId());
+ bar.selectTab(bar.getTabAt(phoneId));
+ }
+ }
+
+ private class TabListener implements ActionBar.TabListener {
+ int mPhoneId;
+
+ public TabListener(int phoneId) {
+ mPhoneId = phoneId;
+ }
+
+ public void onTabSelected(Tab tab, FragmentTransaction ft) {
+ ActionBar bar = getActionBar();
+ int tabCount = bar.getTabCount();
+ Log.d(this, "onTabSelected mPhoneId:" + mPhoneId);
+ //Don't setActiveSubscription if tab count is 1.This is to avoid
+ //setting active subscription automatically when call on one sub
+ //ends and it's corresponding tab is removed.For such cases active
+ //subscription will be set by InCallPresenter.attemptFinishActivity.
+ int[] subId = CallList.getInstance().getSubId(mPhoneId);
+ if (tabCount != TAB_COUNT_ONE && CallList.getInstance().hasAnyLiveCall(subId[0])
+ && (CallList.getInstance().getActiveSubId() != subId[0])) {
+ Log.d(this, "Switch to other active sub: " + subId[0]);
+ TelecomAdapter.getInstance().switchToOtherActiveSub(
+ String.valueOf(subId[0]));
+ }
+ }
+
+ public void onTabUnselected(Tab tab, FragmentTransaction ft) {
+ }
+
+ public void onTabReselected(Tab tab, FragmentTransaction ft) {
+ }
+ }
+
/**
* Enables the OrientationEventListener if enable flag is true. Disables it if enable is
* false
diff --git a/src/com/android/incallui/InCallPresenter.java b/src/com/android/incallui/InCallPresenter.java
index f4b5e751..3bf468f5 100644
--- a/src/com/android/incallui/InCallPresenter.java
+++ b/src/com/android/incallui/InCallPresenter.java
@@ -268,6 +268,14 @@ public class InCallPresenter implements CallList.Listener,
private void attemptFinishActivity() {
final boolean doFinish = (mInCallActivity != null && isActivityStarted());
Log.i(this, "Hide in call UI: " + doFinish);
+
+ if ((mCallList != null)
+ && (InCallServiceImpl.isDsdaEnabled())
+ && !(mCallList.hasAnyLiveCall(mCallList.getActiveSubId()))) {
+ Log.d(this, "Switch active sub");
+ if (mCallList.switchToOtherActiveSub()) return;
+ }
+
if (doFinish) {
mInCallActivity.setExcludeFromRecents(true);
mInCallActivity.finish();
@@ -459,6 +467,9 @@ public class InCallPresenter implements CallList.Listener,
callList.getOutgoingCall() != null;
mInCallActivity.dismissKeyguard(hasCall);
}
+ if (InCallServiceImpl.isDsdaEnabled() && (mInCallActivity != null)) {
+ mInCallActivity.updateDsdaTab();
+ }
}
/**
@@ -477,6 +488,10 @@ public class InCallPresenter implements CallList.Listener,
for (IncomingCallListener listener : mIncomingCallListeners) {
listener.onIncomingCall(oldState, mInCallState, call);
}
+
+ if (InCallServiceImpl.isDsdaEnabled() && (mInCallActivity != null)) {
+ mInCallActivity.updateDsdaTab();
+ }
}
@Override
@@ -1086,9 +1101,11 @@ public class InCallPresenter implements CallList.Listener,
// TODO: Consider a proper state machine implementation
+ boolean isAnyOtherSubActive = InCallState.INCOMING == newState &&
+ mCallList.isAnyOtherSubActive(mCallList.getActiveSubId());
// If the state isn't changing we have already done any starting/stopping of activities in
// a previous pass...so lets cut out early
- if (newState == mInCallState) {
+ if ((newState == mInCallState) && !(mInCallActivity == null && isAnyOtherSubActive)) {
return newState;
}
@@ -1152,6 +1169,13 @@ public class InCallPresenter implements CallList.Listener,
showCallUi |= InCallState.PENDING_OUTGOING == newState && mainUiNotVisible
&& isCallWithNoValidAccounts(mCallList.getPendingOutgoingCall());
+ // Handle transition from InCallState.WAITING_FOR_ACCOUNT to InCallState.INCALL and
+ // and there is a call alive, this case can come for DSDA and hence we should show
+ // UI in such case.
+ showCallUi |= (newState == InCallState.INCALL) &&
+ (mInCallState == InCallState.WAITING_FOR_ACCOUNT) && (mCallList.hasLiveCall() ||
+ (mCallList.getBackgroundCall() != null));
+
// The only time that we have an instance of mInCallActivity and it isn't started is
// when it is being destroyed. In that case, lets avoid bringing up another instance of
// the activity. When it is finally destroyed, we double check if we should bring it back
@@ -1254,6 +1278,7 @@ public class InCallPresenter implements CallList.Listener,
}
private boolean startUi(InCallState inCallState) {
+ final Call incomingCall = mCallList.getIncomingCall();
boolean isCallWaiting = mCallList.getActiveCall() != null &&
mCallList.getIncomingCall() != null;
@@ -1264,7 +1289,13 @@ public class InCallPresenter implements CallList.Listener,
// There should be no jank from this since the screen is already off and will remain so
// until our new activity is up.
- if (isCallWaiting) {
+ // In addition to call waiting scenario, we need to force finish() in case of DSDA when
+ // we get an incoming call on one sub and there is a live call in other sub and screen
+ // is off.
+ boolean anyOtherSubActive = (incomingCall != null &&
+ mCallList.isAnyOtherSubActive(mCallList.getActiveSubId()));
+ Log.d(this, "Start UI " + " anyOtherSubActive:" + anyOtherSubActive);
+ if (isCallWaiting || anyOtherSubActive) {
if (mProximitySensor.isScreenReallyOff() && isActivityStarted()) {
Log.i(this, "Restarting InCallActivity to turn screen on for call waiting");
mInCallActivity.finish();
diff --git a/src/com/android/incallui/InCallServiceImpl.java b/src/com/android/incallui/InCallServiceImpl.java
index 89fa1326..ca080570 100644
--- a/src/com/android/incallui/InCallServiceImpl.java
+++ b/src/com/android/incallui/InCallServiceImpl.java
@@ -22,6 +22,7 @@ import android.os.IBinder;
import android.telecom.Call;
import android.telecom.CallAudioState;
import android.telecom.InCallService;
+import android.telephony.TelephonyManager;
/**
* Used to receive updates about calls from the Telecomm component. This service is bound to
@@ -31,6 +32,9 @@ import android.telecom.InCallService;
*/
public class InCallServiceImpl extends InCallService {
+ static TelephonyManager mTelephonyManager;
+ static int sPhoneCount;
+
@Override
public void onCallAudioStateChanged(CallAudioState audioState) {
AudioModeProvider.getInstance().onAudioStateChanged(audioState);
@@ -61,6 +65,8 @@ public class InCallServiceImpl extends InCallService {
@Override
public IBinder onBind(Intent intent) {
final Context context = getApplicationContext();
+ mTelephonyManager = TelephonyManager.from(context);
+ sPhoneCount = mTelephonyManager.getPhoneCount();
final ContactInfoCache contactInfoCache = ContactInfoCache.getInstance(context);
InCallPresenter.getInstance().setUp(
getApplicationContext(),
@@ -87,6 +93,14 @@ public class InCallServiceImpl extends InCallService {
return false;
}
+ static boolean isDsdaEnabled() {
+ if (mTelephonyManager.getMultiSimConfiguration()
+ == TelephonyManager.MultiSimVariants.DSDA) {
+ return true;
+ }
+ return false;
+ }
+
private void tearDown() {
Log.v(this, "tearDown");
// Tear down the InCall system
diff --git a/src/com/android/incallui/StatusBarNotifier.java b/src/com/android/incallui/StatusBarNotifier.java
index 863ce41b..667a0db2 100644
--- a/src/com/android/incallui/StatusBarNotifier.java
+++ b/src/com/android/incallui/StatusBarNotifier.java
@@ -593,12 +593,18 @@ public class StatusBarNotifier implements InCallPresenter.InCallStateListener,
// If a call is onhold during an incoming call, the call actually comes in as
// INCOMING. For that case *and* traditional call-waiting, we want to
// cancel the notification.
+
+ // For DSDA, we want to cancel the notification if we get an incoming call on
+ // one sub and there is a live call on another sub.
+ CallList callList = CallList.getInstance();
boolean isCallWaiting = (call.getState() == Call.State.CALL_WAITING ||
(call.getState() == Call.State.INCOMING &&
- CallList.getInstance().getBackgroundCall() != null));
+ (callList.getBackgroundCall() != null ||
+ callList.isAnyOtherSubActive(callList.getActiveSubId()))));
if (isCallWaiting) {
- Log.i(this, "updateInCallNotification: call-waiting! force relaunch...");
+ Log.i(this, "configureFullScreenIntent: call-waiting or dsda incoming call!"
+ + " force relaunch. Active sub:" + callList.getActiveSubId());
// Cancel the IN_CALL_NOTIFICATION immediately before
// (re)posting it; this seems to force the
// NotificationManager to launch the fullScreenIntent.
diff --git a/src/com/android/incallui/TelecomAdapter.java b/src/com/android/incallui/TelecomAdapter.java
index e4a39af1..14ce7c8d 100644
--- a/src/com/android/incallui/TelecomAdapter.java
+++ b/src/com/android/incallui/TelecomAdapter.java
@@ -120,6 +120,14 @@ final class TelecomAdapter implements InCallServiceListener {
}
}
+ void switchToOtherActiveSub(String subId) {
+ if (mInCallService != null) {
+ mInCallService.switchToOtherActiveSub(subId);
+ } else {
+ Log.e(this, "error switchToOtherActiveSub, mPhone is null");
+ }
+ }
+
void separateCall(String callId) {
android.telecom.Call call = getTelecommCallById(callId);
if (call != null) {