diff options
Diffstat (limited to 'src/com/android/server/telecom/CallsManager.java')
-rw-r--r-- | src/com/android/server/telecom/CallsManager.java | 553 |
1 files changed, 539 insertions, 14 deletions
diff --git a/src/com/android/server/telecom/CallsManager.java b/src/com/android/server/telecom/CallsManager.java index b94bf678..d7a919fa 100644 --- a/src/com/android/server/telecom/CallsManager.java +++ b/src/com/android/server/telecom/CallsManager.java @@ -25,7 +25,10 @@ import android.net.Uri; import android.os.Bundle; import android.os.Handler; import android.os.Looper; +import android.os.Message; import android.os.Process; +import android.os.RemoteException; +import android.os.ServiceManager; import android.os.SystemClock; import android.os.SystemProperties; import android.os.SystemVibrator; @@ -67,6 +70,7 @@ import com.android.server.telecom.components.ErrorDialogActivity; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; +import java.util.Iterator; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -75,6 +79,7 @@ import java.util.Objects; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; +import org.codeaurora.internal.IExtTelephony; /** * Singleton. * @@ -117,6 +122,9 @@ public class CallsManager extends Call.ListenerBase private static final int MAXIMUM_DIALING_CALLS = 1; private static final int MAXIMUM_OUTGOING_CALLS = 1; private static final int MAXIMUM_TOP_LEVEL_CALLS = 2; + private static final int MAXIMUM_DSDA_LIVE_CALLS = 2; + private static final int MAXIMUM_DSDA_HOLD_CALLS = 2; + private static final int MAXIMUM_DSDA_TOP_LEVEL_CALLS = 4; private static final int[] OUTGOING_CALL_STATES = {CallState.CONNECTING, CallState.SELECT_PHONE_ACCOUNT, CallState.DIALING}; @@ -198,7 +206,25 @@ public class CallsManager extends Call.ListenerBase private TelephonyManager.MultiSimVariants mRadioSimVariants = null; + private static final int LCH_PLAY_DTMF = 100; + private static final int LCH_STOP_DTMF = 101; + private static final int PHONE_START_DSDA_INCALL_TONE = 102; + private static final int SET_LOCAL_CALL_HOLD = 103; + private static final int LCH_DTMF_PERIODICITY = 3000; + private static final int LCH_DTMF_PERIOD = 500; + private static final String sSupervisoryCallHoldToneConfig = + SystemProperties.get("persist.radio.sch_tone", "none"); + private static final String ACTIVE_SUBSCRIPTION = "active_sub"; + private static InCallTonePlayer.Factory mPlayerFactory; + private String mLchSub = null; + + private InCallTonePlayer mLocalCallReminderTonePlayer = null; + private Runnable mStopTone; + private String mActiveSub = null; + private DsdaAdapter mDsdaAdapter = null; + + private HashMap<String, Boolean> mLchStatus = new HashMap<String, Boolean>(); /** * Initializes the required Telecom components. @@ -271,6 +297,7 @@ public class CallsManager extends Call.ListenerBase playerFactory, mRinger, new RingbackPlayer(playerFactory), mDtmfLocalTonePlayer); mHeadsetMediaButton = headsetMediaButtonFactory.create(context, this, mLock); + mPlayerFactory = playerFactory; mTtyManager = new TtyManager(context, mWiredHeadsetManager); mProximitySensorManager = proximitySensorManagerFactory.create(context, this); mPhoneStateBroadcaster = new PhoneStateBroadcaster(this); @@ -366,7 +393,7 @@ public class CallsManager extends Call.ListenerBase } if (result.shouldAllowCall) { - if (hasMaximumRingingCalls()) { + if (hasMaximumRingingCalls(incomingCall.getTargetPhoneAccount().getId())) { Log.i(this, "onCallFilteringCompleted: Call rejected! Exceeds maximum number of " + "ringing calls."); rejectCallAndLog(incomingCall); @@ -376,6 +403,7 @@ public class CallsManager extends Call.ListenerBase rejectCallAndLog(incomingCall); } else { addCall(incomingCall); + setActiveSubscription(incomingCall.getTargetPhoneAccount().getId()); } } else { if (result.shouldReject) { @@ -972,6 +1000,9 @@ public class CallsManager extends Call.ListenerBase com.android.internal.R.bool.config_requireCallCapableAccountForHandle); if (call.getTargetPhoneAccount() != null || call.isEmergencyCall()) { + if (!call.isEmergencyCall()) { + updateLchStatus(call.getTargetPhoneAccount().getId()); + } // If the account has been set, proceed to place the outgoing call. // Otherwise the connection will be initiated when the account is set by the user. call.startCreateConnection(mPhoneAccountRegistrar); @@ -1026,19 +1057,20 @@ public class CallsManager extends Call.ListenerBase if (!mCalls.contains(call)) { Log.i(this, "Request to answer a non-existent call %s", call); } else { - Call foregroundCall = getForegroundCall(); + Call activeCall = getFirstCallWithState(call.getTargetPhoneAccount() + .getId(), CallState.ACTIVE, CallState.DIALING); // If the foreground call is not the ringing call and it is currently isActive() or // STATE_DIALING, put it on hold before answering the call. - if (foregroundCall != null && foregroundCall != call && - (foregroundCall.isActive() || - foregroundCall.getState() == CallState.DIALING)) { - if (0 == (foregroundCall.getConnectionCapabilities() + if (activeCall != null && activeCall != call && + (activeCall.isActive() || + activeCall.getState() == CallState.DIALING)) { + if (0 == (activeCall.getConnectionCapabilities() & Connection.CAPABILITY_HOLD)) { // This call does not support hold. If it is from a different connection // service, then disconnect it, otherwise allow the connection service to // figure out the right states. - if (foregroundCall.getConnectionService() != call.getConnectionService()) { - foregroundCall.disconnect(); + if (activeCall.getConnectionService() != call.getConnectionService()) { + activeCall.disconnect(); } } else { Call heldCall = getHeldCall(); @@ -1049,8 +1081,8 @@ public class CallsManager extends Call.ListenerBase } Log.v(this, "Holding active/dialing call %s before answering incoming call %s.", - foregroundCall, call); - foregroundCall.hold(); + activeCall, call); + activeCall.hold(); } // TODO: Wait until we get confirmation of the active call being // on-hold before answering the new call. @@ -1060,7 +1092,7 @@ public class CallsManager extends Call.ListenerBase for (CallsManagerListener listener : mListeners) { listener.onIncomingCallAnswered(call); } - + updateLchStatus(call.getTargetPhoneAccount().getId()); // We do not update the UI until we get confirmation of the answer() through // {@link #markCallAsActive}. call.answer(videoState); @@ -1109,6 +1141,7 @@ public class CallsManager extends Call.ListenerBase for (CallsManagerListener listener : mListeners) { listener.onIncomingCallRejected(call, rejectWithMessage, textMessage); } + setActiveSubscription(getConversationSub()); call.reject(rejectWithMessage, textMessage); } } @@ -1208,8 +1241,13 @@ public class CallsManager extends Call.ListenerBase } else { Log.d(this, "unholding call: (%s)", call); for (Call c : mCalls) { + PhoneAccountHandle ph = call.getTargetPhoneAccount(); + PhoneAccountHandle ph1 = c.getTargetPhoneAccount(); // Only attempt to hold parent calls and not the individual children. - if (c != null && c.isAlive() && c != call && c.getParentCall() == null) { + // if 'c' is not for same subscription as call, then don't disturb 'c' + if (c != null && c.isAlive() && c != call && c.getParentCall() == null + && (ph != null && ph1 != null && + isSamePhAccIdOrSipId(ph.getId(), ph1.getId()))) { c.hold(); } } @@ -1304,6 +1342,15 @@ public class CallsManager extends Call.ListenerBase call.setViaNumber(viaNumber); } } + /** + * Returns true if the ids are same or one of the ids is sip id. + */ + private boolean isSamePhAccIdOrSipId(String id1, String id2) { + boolean ret = ((id1 != null && id2 != null) && + (id1.equals(id2) || id1.contains("sip") || id2.contains("sip"))); + Log.d(this, "isSamePhAccIdOrSipId: id1 = " + id1 + " id2 = " + id2 + " ret = " + ret); + return ret; + } /** Called by the in-call UI to change the mute state. */ void mute(boolean shouldMute) { @@ -1336,6 +1383,8 @@ public class CallsManager extends Call.ListenerBase if (!mCalls.contains(call)) { Log.i(this, "Attempted to add account to unknown call %s", call); } else { + Log.i(this, "phoneAccountSelected , id = %s", account.getId()); + updateLchStatus(account.getId()); call.setTargetPhoneAccount(account); if (!call.isNewOutgoingCallIntentBroadcastDone()) { @@ -1374,6 +1423,7 @@ public class CallsManager extends Call.ListenerBase void markCallAsDialing(Call call) { setCallState(call, CallState.DIALING, "dialing set explicitly"); maybeMoveToSpeakerPhone(call); + setActiveSubscription(call.getTargetPhoneAccount().getId()); } void markCallAsActive(Call call) { @@ -1393,7 +1443,35 @@ public class CallsManager extends Call.ListenerBase */ void markCallAsDisconnected(Call call, DisconnectCause disconnectCause) { call.setDisconnectCause(disconnectCause); + int prevState = call.getState(); setCallState(call, CallState.DISCONNECTED, "disconnected set explicitly"); + String lchSub = getLchSub(); + String subId = (call.getTargetPhoneAccount() == null) ? null : + call.getTargetPhoneAccount().getId(); + String subInConversation = getConversationSub(); + if (subId != null && subId.equals(mActiveSub) && + getFirstCallWithState(subId, CallState.RINGING) == null && + (subInConversation != null && !subInConversation.equals(mActiveSub))) { + Log.d(this,"Set active sub to conversation sub"); + switchToOtherActiveSub(subInConversation); + } else if ((subInConversation == null) && (lchSub != null) && + ((prevState == CallState.CONNECTING) || (prevState == + CallState.SELECT_PHONE_ACCOUNT)) && + (call.getState() == CallState.DISCONNECTED)) { + Log.d(this,"remove sub with call from LCH"); + updateLchStatus(lchSub); + setActiveSubscription(lchSub); + manageDsdaInCallTones(false); + } + if ((subId != null) && (mLchStatus.get(subId) == true)) { + Call activecall = getFirstCallWithState(subId, CallState.RINGING, CallState.DIALING, + CallState.ACTIVE, CallState.ON_HOLD); + Log.d(this,"activecall: " + activecall); + if (activecall == null) { + mLchStatus.put(subId, false); + manageDsdaInCallTones(false); + } + } } /** @@ -1401,6 +1479,11 @@ public class CallsManager extends Call.ListenerBase */ void markCallAsRemoved(Call call) { removeCall(call); + if (!hasAnyCalls()) { + updateLchStatus(null); + setActiveSubscription(null); + manageDsdaInCallTones(false); + } if (mLocallyDisconnectingCalls.contains(call)) { mLocallyDisconnectingCalls.remove(call); Call foregroundCall = mCallAudioManager.getPossiblyHeldForegroundCall(); @@ -1451,6 +1534,10 @@ public class CallsManager extends Call.ListenerBase return getFirstCallWithState(CallState.ACTIVE, CallState.ON_HOLD) != null; } + boolean hasActiveOrHoldingCall(String sub) { + return (getFirstCallWithState(sub, CallState.ACTIVE, CallState.ON_HOLD) != null); + } + boolean hasRingingCall() { return getFirstCallWithState(CallState.RINGING) != null; } @@ -1508,7 +1595,12 @@ public class CallsManager extends Call.ListenerBase // we could put InCallServices into a state where they are showing two calls but // also support add-call. Technically it's right, but overall looks better (UI-wise) // and acts better if we wait until the call is removed. - if (count >= MAXIMUM_TOP_LEVEL_CALLS) { + if (TelephonyManager.getDefault().getMultiSimConfiguration() + == TelephonyManager.MultiSimVariants.DSDA) { + if (count >= MAXIMUM_DSDA_TOP_LEVEL_CALLS) { + return false; + } + } else if (count >= MAXIMUM_TOP_LEVEL_CALLS) { return false; } } @@ -1552,7 +1644,7 @@ public class CallsManager extends Call.ListenerBase @VisibleForTesting public Call getFirstCallWithState(int... states) { - return getFirstCallWithState(null, states); + return getFirstCallWithState((Call) null, states); } /** @@ -1588,6 +1680,43 @@ public class CallsManager extends Call.ListenerBase return null; } + /** + * Returns the first call that it finds with the given states for given subscription. + * the states are treated as having priority order so that any call with the first + * state will be returned before any call with states listed later in the parameter list. + * + * @param subId check calls only on this subscription + * @param callToSkip Call that this method should skip while searching + */ + Call getFirstCallWithState(String subId, Call callToSkip, int... states) { + for (int currentState : states) { + // check the foreground first + Call foregroundCall = getForegroundCall(); + if (foregroundCall != null && foregroundCall.getState() == currentState + && foregroundCall.getTargetPhoneAccount() != null + && isSamePhAccIdOrSipId(foregroundCall.getTargetPhoneAccount().getId(), subId)) { + return foregroundCall; + } + + for (Call call : mCalls) { + if (Objects.equals(callToSkip, call)) { + continue; + } + + // Only operate on top-level calls + if (call.getParentCall() != null) { + continue; + } + + if (currentState == call.getState() && call.getTargetPhoneAccount() != null + && isSamePhAccIdOrSipId(call.getTargetPhoneAccount().getId(), subId)) { + return call; + } + } + } + return null; + } + Call createConferenceCall( String callId, PhoneAccountHandle phoneAccount, @@ -1772,6 +1901,7 @@ public class CallsManager extends Call.ListenerBase } Trace.endSection(); } + manageDsdaInCallTones(false); } private void updateCanAddCall() { @@ -1837,18 +1967,44 @@ public class CallsManager extends Call.ListenerBase return count; } + private int getNumCallsWithState(String subId, int... states) { + int count = 0; + for (int state : states) { + for (Call call : mCalls) { + if (call.getParentCall() == null && call.getState() == state + && call.getTargetPhoneAccount() != null + && isSamePhAccIdOrSipId(call.getTargetPhoneAccount().getId(), subId)) { + count++; + } + } + } + return count; + } + private boolean hasMaximumLiveCalls() { return MAXIMUM_LIVE_CALLS <= getNumCallsWithState(LIVE_CALL_STATES); } + private boolean hasMaximumLiveCalls(String subId) { + return MAXIMUM_LIVE_CALLS <= getNumCallsWithState(subId, LIVE_CALL_STATES); + } + private boolean hasMaximumHoldingCalls() { return MAXIMUM_HOLD_CALLS <= getNumCallsWithState(CallState.ON_HOLD); } + private boolean hasMaximumHoldingCalls(String subId) { + return MAXIMUM_HOLD_CALLS <= getNumCallsWithState(subId, CallState.ON_HOLD); + } + private boolean hasMaximumRingingCalls() { return MAXIMUM_RINGING_CALLS <= getNumCallsWithState(CallState.RINGING); } + private boolean hasMaximumRingingCalls(String subId) { + return MAXIMUM_RINGING_CALLS <= getNumCallsWithState(subId, CallState.RINGING); + } + private boolean hasMaximumOutgoingCalls() { return MAXIMUM_OUTGOING_CALLS <= getNumCallsWithState(OUTGOING_CALL_STATES); } @@ -1858,6 +2014,10 @@ public class CallsManager extends Call.ListenerBase } private boolean makeRoomForOutgoingCall(Call call, boolean isEmergency) { + if (TelephonyManager.getDefault().getMultiSimConfiguration() + == TelephonyManager.MultiSimVariants.DSDA) { + return makeRoomForOutgoingCallForDsda(call, isEmergency); + } if (hasMaximumLiveCalls()) { // NOTE: If the amount of live calls changes beyond 1, this logic will probably // have to change. @@ -1958,6 +2118,44 @@ public class CallsManager extends Call.ListenerBase return true; } + private boolean makeRoomForOutgoingCallForDsda(Call call, boolean isEmergency) { + if (isEmergency || (call.getState() == CallState.SELECT_PHONE_ACCOUNT)) { + return true; + } + + PhoneAccountHandle phAcc = call.getTargetPhoneAccount(); + if (phAcc == null) { + if (getNumCallsWithState(LIVE_CALL_STATES) == MAXIMUM_DSDA_LIVE_CALLS + && getNumCallsWithState(CallState.ON_HOLD) == MAXIMUM_DSDA_HOLD_CALLS) { + return false; + } else { + return true; + } + } + if (hasMaximumLiveCalls(phAcc.getId())) { + // NOTE: If the amount of live calls changes beyond 1, this logic will probably + // have to change. + Call liveCall = getFirstCallWithState(phAcc.getId(), call, LIVE_CALL_STATES); + + if (hasMaximumHoldingCalls(phAcc.getId())) { + // There is no more room for any more calls, unless it's an emergency. + return false; // No more room! + } + if (Objects.equals(liveCall.getTargetPhoneAccount(), call.getTargetPhoneAccount())) { + return true; + } + // Try to hold the live call before attempting the new outgoing call. + if (liveCall.can(Connection.CAPABILITY_HOLD)) { + liveCall.hold(); + return true; + } + + // The live call cannot be held so we're out of luck here. There's no room. + return false; + } + return true; + } + /** * Given a call, find the first non-null phone account handle of its children. * @@ -2139,4 +2337,331 @@ public class CallsManager extends Call.ListenerBase call.setIntentExtras(extras); } + + private final Handler mLchHandler = new LchHandler(); + private final class LchHandler extends Handler { + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case PHONE_START_DSDA_INCALL_TONE: + Log.d(this, "Start DSDA incall tones..."); + startDsdaInCallTones(); + break; + case LCH_PLAY_DTMF: + playLchDtmf(); + break; + case LCH_STOP_DTMF: + stopLchDtmf(); + break; + case SET_LOCAL_CALL_HOLD: + updateLchStatusToRil((String) msg.obj); + break; + } + } + } + + void switchToOtherActiveSub(String subId) { + if (TelephonyManager.getDefault().getMultiSimConfiguration() + != TelephonyManager.MultiSimVariants.DSDA) { + return; + } + Log.d(this, "switchToOtherActiveSub sub:" + subId); + setActiveSubscription(subId); + updateLchStatus(subId); + manageDsdaInCallTones(true); + } + + String getActiveSubscription() { + return mActiveSub; + } + + synchronized void setActiveSubscription(String subId) { + if (TelephonyManager.getDefault().getMultiSimConfiguration() + != TelephonyManager.MultiSimVariants.DSDA) { + return; + } + Log.d(this, "setActiveSubscription = " + subId); + if (subId == null) { + mActiveSub = null; + return; + } + if (subId.equals(mActiveSub)) { + Log.d(this, "setActiveSubscription not changed " + subId + " mActiveSub:" + mActiveSub); + return; + } + mActiveSub = subId; + Log.d(this, "setActiveSubscription changed " + mActiveSub); + for (Call call : mCalls) { + PhoneAccountHandle ph = call.getTargetPhoneAccount(); + if (ph != null && subId.equals(ph.getId())) { + Bundle extras = new Bundle(); + extras.putBoolean(ACTIVE_SUBSCRIPTION, true); + call.putExtras(Call.SOURCE_CONNECTION_SERVICE, extras); + } else { + Bundle extras = new Bundle(); + extras.putBoolean(ACTIVE_SUBSCRIPTION, false); + call.putExtras(Call.SOURCE_CONNECTION_SERVICE, extras); + } + } + } + + void manageDsdaInCallTones(boolean isSubSwitch) { + Log.d(this, " entered manageDsdaInCallTones "); + + // If there is no background active subscription available, stop playing the tones. + // Do not start/stop LCH/SCH tones when phone is in RINGING state. + if (getLchSub() != null && !hasRingingCall()) { + //If sub switch happens re-start the tones with a delay of 100msec. + if (isSubSwitch) { + Log.d(this, " manageDsdaInCallTones: re-start playing tones, lch sub = " + + getLchSub()); + reStartDsdaInCallTones(); + } else { + Log.d(this, " entered manageDsdaInCallTones "); + startDsdaInCallTones(); + } + } else if (getLchSub() == null) { + // if there is no sub in Lch state, then stop playing the tones + stopMSimInCallTones(); + } + } + + private void reStartDsdaInCallTones() { + Log.d(this, " reStartDsdaInCallTones"); + stopMSimInCallTones(); + /* Remove any pending PHONE_START_DSDA_INCALL_TONE messages from queue */ + mLchHandler.removeMessages(PHONE_START_DSDA_INCALL_TONE); + Message message = Message.obtain(mLchHandler, PHONE_START_DSDA_INCALL_TONE); + mLchHandler.sendMessageDelayed(message, 100); + } + + /** + * Returns the first call that it finds with the given states for given subscription. + * The states are treated as having priority order so that any call with the first + * state will be returned before any call with states listed later in the parameter list. + */ + Call getFirstCallWithState(String sub, int... states) { + for (int currentState : states) { + // check the foreground first + Call foregroundCall = getForegroundCall(); + if (foregroundCall != null && foregroundCall.getState() == currentState + && (foregroundCall.getTargetPhoneAccount() != null) + && isSamePhAccIdOrSipId(foregroundCall.getTargetPhoneAccount().getId(), + sub)) { + return foregroundCall; + } + + for (Call call : mCalls) { + if ((currentState == call.getState()) && + (call.getTargetPhoneAccount() != null) && + (isSamePhAccIdOrSipId(call.getTargetPhoneAccount().getId(), sub))) { + return call; + } + } + } + return null; + } + /** + * Check whether any other sub is in active state other than + * provided subscription, if yes return the other active sub. + * @return subscription which is active. + */ + private String getOtherActiveSub(String subscription) { + String otherSub = null;; + for (PhoneAccountHandle ph : getPhoneAccountRegistrar() + .getSimPhoneAccountsOfCurrentUser()) { + String sub = ph.getId(); + if (!sub.equals(subscription) && getFirstCallWithState(sub, CallState.CONNECTING, + CallState.DIALING, CallState.ACTIVE) != null) { + otherSub = sub; + } + } + return otherSub; + } + + private String getConversationSub() { + for (PhoneAccountHandle ph : getPhoneAccountRegistrar() + .getSimPhoneAccountsOfCurrentUser()) { + String sub = ph.getId(); + if ((mLchStatus.get(sub) == null || mLchStatus.get(sub) == false) + && getFirstCallWithState(sub, CallState.CONNECTING, + CallState.DIALING, CallState.ACTIVE) != null) { + return sub; + } + } + return null; + } + + private String getLchSub() { + Iterator<String> keySetIterator = mLchStatus.keySet().iterator(); + while(keySetIterator.hasNext()){ + String sub = keySetIterator.next(); + if (mLchStatus.get(sub)!= null && mLchStatus.get(sub)) { + return sub; + } + } + return null; + } + + private void playLchDtmf() { + if (mLchSub != null || mLchHandler.hasMessages(LCH_PLAY_DTMF)) { + // Ignore any redundant requests to start playing tones + return; + } + mLchSub = getLchSub(); + Log.d(this, " playLchDtmf... lch sub " + mLchSub); + if (mLchSub == null) return; + removeAnyPendingDtmfMsgs(); + char c = mContext.getResources() + .getString(R.string.lch_dtmf_key).charAt(0); + Call call = getNonRingingLiveCall(mLchSub); + if (call == null) { + mLchSub = null; + return; + } + call.playDtmfTone(c); + // Keep playing LCH DTMF tone to remote party on LCH call, with periodicity + // "LCH_DTMF_PERIODICITY" until call moves out of LCH. + mLchHandler.sendMessageDelayed(Message.obtain(mLchHandler, LCH_PLAY_DTMF), + LCH_DTMF_PERIODICITY); + mLchHandler.sendMessageDelayed(Message.obtain(mLchHandler, LCH_STOP_DTMF), LCH_DTMF_PERIOD); + } + + private Call getNonRingingLiveCall(String subId) { + return getFirstCallWithState(subId, CallState.DIALING, + CallState.ACTIVE, CallState.ON_HOLD); + } + + private void stopLchDtmf() { + if (mLchSub != null) { + // Ignore any redundant requests to stop playing tones + Call call = getNonRingingLiveCall(mLchSub); + Log.d(this, " stopLchDtmf... call: " + call + " mLchSub:" + mLchSub); + if (call == null) { + mLchSub = null; + return; + } + call.stopDtmfTone(); + } + mLchSub = null; + } + + private void startDsdaInCallTones() { + if (mLocalCallReminderTonePlayer == null) { + Log.d(this, " Play local call hold reminder tone "); + mLocalCallReminderTonePlayer = + mPlayerFactory.createPlayer(InCallTonePlayer.TONE_HOLD_RECALL); + mLocalCallReminderTonePlayer.start(); + } + if (sSupervisoryCallHoldToneConfig.equals("dtmf")) { + Log.d(this, " startDsdaInCallTones: Supervisory call hold tone over dtmf "); + playLchDtmf(); + } + } + + private void removeAnyPendingDtmfMsgs() { + mLchHandler.removeMessages(LCH_PLAY_DTMF); + mLchHandler.removeMessages(LCH_STOP_DTMF); + } + + protected void stopMSimInCallTones() { + if (mLocalCallReminderTonePlayer != null) { + Log.d(this, " stopMSimInCallTones: local call hold reminder tone "); + mLocalCallReminderTonePlayer.stopTone(); + mLocalCallReminderTonePlayer = null; + } + if (sSupervisoryCallHoldToneConfig.equals("dtmf")) { + Log.d(this, " stopMSimInCallTones: stop SCH Dtmf call hold tone "); + stopLchDtmf(); + /* Remove any previous dtmf nssages from queue */ + removeAnyPendingDtmfMsgs(); + } + } + + private void updateLchStatus (String subId) { + mLchHandler.obtainMessage(SET_LOCAL_CALL_HOLD, subId).sendToTarget(); + } + + /** + * Update the local call hold state for all subscriptions + * 1 -- if call on local hold, 0 -- if call is not on local hold + * + * @param subInConversation is the sub user is currently active in subsription. + * so if this sub is in LCH, then bring that sub out of LCH. + */ + private void updateLchStatusToRil(String subInConversation) { + String removeFromLch = null; + Log.d(this, "updateLchStatusToRil subInConversation: " + subInConversation); + if (subInConversation != null && subInConversation.contains("sip")) { + return; + } + for (PhoneAccountHandle ph : getPhoneAccountRegistrar() + .getSimPhoneAccountsOfCurrentUser()) { + String sub = ph.getId(); + if (sub != null && sub.contains("sip")) { + Log.d(this, "update lch. Skipping account: " + sub); + continue; + } + boolean lchState = false; + Boolean isLchEnabled = mLchStatus.get(sub); + isLchEnabled = (isLchEnabled == null) ? false : isLchEnabled; + if (subInConversation != null && hasActiveOrHoldingCall(sub) && + !sub.equals(subInConversation)) { + // if sub is not conversation sub and if it has an active + // voice call then update lchStatus as Active + lchState = true; + } + + // Update state only if the new state is different + if (lchState != isLchEnabled) { + Call call = getNonRingingLiveCall(sub); + Log.d(this, " setLocal Call Hold to = " + lchState + " sub:" + sub); + + if (lchState) { + mLchStatus.put(sub, true); + setLocalCallHold(sub, true); + } else { + removeFromLch = sub; + mLchStatus.put(sub, false); + } + } + } + if (removeFromLch != null) { + // Ensure to send LCH disable request at last, to make sure that during switch + // subscription, both subscriptions not to be in active(non-LCH) at any moment. + setLocalCallHold(removeFromLch, false); + } + } + + void setDsdaAdapter() { + if (mDsdaAdapter != null) { + return; + } + mDsdaAdapter = new DsdaAdapter(this); + IExtTelephony mExtTelephony = IExtTelephony.Stub.asInterface(ServiceManager + .getService("extphone")); + try { + Log.d(this, "setDsdaAdapter"); + mExtTelephony.setDsdaAdapter(mDsdaAdapter); + } catch (NullPointerException ex) { + Log.d(this, "setDsdaAdapter" + ex); + } catch (RemoteException ex) { + Log.d(this, "setDsdaAdapter" + ex); + } + } + + private void setLocalCallHold(String subscriptionId, boolean enable) { + IExtTelephony mExtTelephony = IExtTelephony.Stub.asInterface(ServiceManager + .getService("extphone")); + try { + Log.d(this, "setLocalCallHold" + subscriptionId); + mExtTelephony.setLocalCallHold(Integer.parseInt(subscriptionId), enable); + } catch (NullPointerException ex) { + Log.d(this, "setLocalCallHold" + ex); + } catch (RemoteException ex) { + Log.d(this, "setLocalCallHold" + ex); + } catch (NumberFormatException ex) { + Log.d(this, "setLocalCallHold" + ex); + } + } } |