void setUiTTYMode(int uiTtyMode, Message onComplete) { try { mImsManager.setUiTTYMode(mPhone.getContext(), mServiceId, uiTtyMode, onComplete); } catch (ImsException e) { loge("setTTYMode : " + e); mPhone.sendErrorResponse(onComplete, e); } }
private void processCallStateChange(ImsCall imsCall, ImsPhoneCall.State state, int cause) { if (DBG) log("processCallStateChange " + imsCall + " state=" + state + " cause=" + cause); if (imsCall == null) return; boolean changed = false; ImsPhoneConnection conn = findConnection(imsCall); if (conn == null) { // TODO : what should be done? return; } changed = conn.update(imsCall, state); if (state == ImsPhoneCall.State.DISCONNECTED) { changed = conn.onDisconnect(cause) || changed; // detach the disconnected connections conn.getCall().detach(conn); removeConnection(conn); } if (changed) { if (conn.getCall() == mHandoverCall) return; updatePhoneState(); mPhone.notifyPreciseCallStateChanged(); } }
void clearDisconnected() { if (DBG) log("clearDisconnected"); internalClearDisconnected(); updatePhoneState(); mPhone.notifyPreciseCallStateChanged(); }
@Override public void onCallResumeReceived(ImsCall imsCall) { if (DBG) log("onCallResumeReceived"); if (mOnHoldToneStarted) { mPhone.stopOnHoldTone(); mOnHoldToneStarted = false; } }
public void dispose() { if (DBG) log("dispose"); mRingingCall.dispose(); mBackgroundCall.dispose(); mForegroundCall.dispose(); mHandoverCall.dispose(); clearDisconnected(); mPhone.getContext().unregisterReceiver(mReceiver); }
private void handleEcmTimer(int action) { mPhone.handleTimerInEmergencyCallbackMode(action); switch (action) { case ImsPhone.CANCEL_ECM_TIMER: break; case ImsPhone.RESTART_ECM_TIMER: break; default: log("handleEcmTimer, unsupported action " + action); } }
/* package */ void hangup(ImsPhoneCall call) throws CallStateException { if (DBG) log("hangup call"); if (call.getConnections().size() == 0) { throw new CallStateException("no connections"); } ImsCall imsCall = call.getImsCall(); boolean rejectCall = false; if (call == mRingingCall) { if (Phone.DEBUG_PHONE) log("(ringing) hangup incoming"); rejectCall = true; } else if (call == mForegroundCall) { if (call.isDialingOrAlerting()) { if (Phone.DEBUG_PHONE) { log("(foregnd) hangup dialing or alerting..."); } } else { if (Phone.DEBUG_PHONE) { log("(foregnd) hangup foreground"); } // held call will be resumed by onCallTerminated } } else if (call == mBackgroundCall) { if (Phone.DEBUG_PHONE) { log("(backgnd) hangup waiting or background"); } } else { throw new CallStateException( "ImsPhoneCall " + call + "does not belong to ImsPhoneCallTracker " + this); } call.onHangupLocal(); try { if (imsCall != null) { if (rejectCall) imsCall.reject(ImsReasonInfo.CODE_USER_DECLINE); else imsCall.terminate(ImsReasonInfo.CODE_USER_TERMINATED); } else if (mPendingMO != null && call == mForegroundCall) { // is holding a foreground call mPendingMO.update(null, ImsPhoneCall.State.DISCONNECTED); mPendingMO.onDisconnect(); removeConnection(mPendingMO); mPendingMO = null; updatePhoneState(); removeMessages(EVENT_DIAL_PENDINGMO); } } catch (ImsException e) { throw new CallStateException(e.getMessage()); } mPhone.notifyPreciseCallStateChanged(); }
@Override public void onCallHoldReceived(ImsCall imsCall) { if (DBG) log("onCallHoldReceived"); ImsPhoneConnection conn = findConnection(imsCall); if (conn != null && conn.getState() == ImsPhoneCall.State.ACTIVE) { if (!mOnHoldToneStarted && ImsPhoneCall.isLocalTone(imsCall)) { mPhone.startOnHoldTone(); mOnHoldToneStarted = true; } } }
@Override public void onCallResumeFailed(ImsCall imsCall, ImsReasonInfo reasonInfo) { // TODO : What should be done? // If we are in the midst of swapping the FG and BG calls and we got a resume fail, we // need to swap back the FG and BG calls. if (mSwitchingFgAndBgCalls && imsCall == mCallExpectedToResume) { mForegroundCall.switchWith(mBackgroundCall); mCallExpectedToResume = null; mSwitchingFgAndBgCalls = false; } mPhone.notifySuppServiceFailed(Phone.SuppService.RESUME); }
private void getImsService() { if (DBG) log("getImsService"); mImsManager = ImsManager.getInstance(mPhone.getContext(), mPhone.getPhoneId()); try { mServiceId = mImsManager.open( ImsServiceClass.MMTEL, createIncomingCallPendingIntent(), mImsConnectionStateListener); // Get the ECBM interface and set IMSPhone's listener object for notifications getEcbmInterface().setEcbmStateListener(mPhone.mImsEcbmStateListener); if (mPhone.isInEcm()) { // Call exit ECBM which will invoke onECBMExited mPhone.exitEmergencyCallbackMode(); } int mPreferredTtyMode = Settings.Secure.getInt( mPhone.getContext().getContentResolver(), Settings.Secure.PREFERRED_TTY_MODE, Phone.TTY_MODE_OFF); mImsManager.setUiTTYMode(mPhone.getContext(), mServiceId, mPreferredTtyMode, null); } catch (ImsException e) { loge("getImsService: " + e); // Leave mImsManager as null, then CallStateException will be thrown when dialing mImsManager = null; } }
@Override public void handleMessage(Message msg) { AsyncResult ar; if (DBG) log("handleMessage what=" + msg.what); switch (msg.what) { case EVENT_HANGUP_PENDINGMO: if (mPendingMO != null) { mPendingMO.onDisconnect(); removeConnection(mPendingMO); mPendingMO = null; } updatePhoneState(); mPhone.notifyPreciseCallStateChanged(); break; case EVENT_RESUME_BACKGROUND: try { resumeWaitingOrHolding(); } catch (CallStateException e) { if (Phone.DEBUG_PHONE) { loge("handleMessage EVENT_RESUME_BACKGROUND exception=" + e); } } break; case EVENT_DIAL_PENDINGMO: dialInternal(mPendingMO, mClirMode, VideoProfile.VideoState.AUDIO_ONLY); break; case EVENT_EXIT_ECM_RESPONSE_CDMA: // no matter the result, we still do the same here if (pendingCallInEcm) { dialInternal(mPendingMO, pendingCallClirMode, pendingCallVideoState); pendingCallInEcm = false; } mPhone.unsetOnEcbModeExitResponse(this); break; } }
boolean canDial() { boolean ret; int serviceState = mPhone.getServiceState().getState(); String disableCall = SystemProperties.get(TelephonyProperties.PROPERTY_DISABLE_CALL, "false"); ret = (serviceState != ServiceState.STATE_POWER_OFF) && mPendingMO == null && !mRingingCall.isRinging() && !disableCall.equals("true") && (!mForegroundCall.getState().isAlive() || !mBackgroundCall.getState().isAlive()); return ret; }
ImsPhoneCallTracker(ImsPhone phone) { this.mPhone = phone; IntentFilter intentfilter = new IntentFilter(); intentfilter.addAction(ImsManager.ACTION_IMS_INCOMING_CALL); mPhone.getContext().registerReceiver(mReceiver, intentfilter); Thread t = new Thread() { public void run() { getImsService(); } }; t.start(); }
@Override public void onCallMerged(ImsCall call, boolean swapCalls) { if (DBG) log("onCallMerged"); mForegroundCall.merge(mBackgroundCall, mForegroundCall.getState()); if (swapCalls) { try { switchWaitingOrHoldingAndActive(); } catch (CallStateException e) { if (Phone.DEBUG_PHONE) { loge("Failed swap fg and bg calls on merge exception=" + e); } } } updatePhoneState(); mPhone.notifyPreciseCallStateChanged(); }
@Override public void onCallUssdMessageReceived(ImsCall call, int mode, String ussdMessage) { if (DBG) log("mImsUssdListener onCallUssdMessageReceived mode=" + mode); int ussdMode = -1; switch (mode) { case ImsCall.USSD_MODE_REQUEST: ussdMode = CommandsInterface.USSD_MODE_REQUEST; break; case ImsCall.USSD_MODE_NOTIFY: ussdMode = CommandsInterface.USSD_MODE_NOTIFY; break; } mPhone.onIncomingUSSD(ussdMode, ussdMessage); }
/** * onCallStartFailed will be invoked when: case 1) Dialing fails case 2) Ringing call is * disconnected by local or remote user */ @Override public void onCallStartFailed(ImsCall imsCall, ImsReasonInfo reasonInfo) { if (DBG) log("onCallStartFailed reasonCode=" + reasonInfo.getCode()); if (mPendingMO != null) { // To initiate dialing circuit-switched call if (reasonInfo.getCode() == ImsReasonInfo.CODE_LOCAL_CALL_CS_RETRY_REQUIRED && mBackgroundCall.getState() == ImsPhoneCall.State.IDLE && mRingingCall.getState() == ImsPhoneCall.State.IDLE) { mForegroundCall.detach(mPendingMO); removeConnection(mPendingMO); mPendingMO.finalize(); mPendingMO = null; mPhone.initiateSilentRedial(); return; } else { int cause = getDisconnectCauseFromReasonInfo(reasonInfo); processCallStateChange(imsCall, ImsPhoneCall.State.DISCONNECTED, cause); } mPendingMO = null; } }
private void updatePhoneState() { PhoneConstants.State oldState = mState; if (mRingingCall.isRinging()) { mState = PhoneConstants.State.RINGING; } else if (mPendingMO != null || !(mForegroundCall.isIdle() && mBackgroundCall.isIdle())) { mState = PhoneConstants.State.OFFHOOK; } else { mState = PhoneConstants.State.IDLE; } if (mState == PhoneConstants.State.IDLE && oldState != mState) { mVoiceCallEndedRegistrants.notifyRegistrants(new AsyncResult(null, null, null)); } else if (oldState == PhoneConstants.State.IDLE && oldState != mState) { mVoiceCallStartedRegistrants.notifyRegistrants(new AsyncResult(null, null, null)); } if (DBG) log("updatePhoneState oldState=" + oldState + ", newState=" + mState); if (mState != oldState) { mPhone.notifyPhoneStateChanged(); } }
/* package */ void sendUSSD(String ussdString, Message response) { if (DBG) log("sendUSSD"); try { if (mUssdSession != null) { mUssdSession.sendUssd(ussdString); AsyncResult.forMessage(response, null, null); response.sendToTarget(); return; } String[] callees = new String[] {ussdString}; ImsCallProfile profile = mImsManager.createCallProfile( mServiceId, ImsCallProfile.SERVICE_TYPE_NORMAL, ImsCallProfile.CALL_TYPE_VOICE); profile.setCallExtraInt(ImsCallProfile.EXTRA_DIALSTRING, ImsCallProfile.DIALSTRING_USSD); mUssdSession = mImsManager.makeCall(mServiceId, profile, callees, mImsUssdListener); } catch (ImsException e) { loge("sendUSSD : " + e); mPhone.sendErrorResponse(response, e); } }
private PendingIntent createIncomingCallPendingIntent() { Intent intent = new Intent(ImsManager.ACTION_IMS_INCOMING_CALL); intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND); return PendingIntent.getBroadcast( mPhone.getContext(), 0, intent, PendingIntent.FLAG_UPDATE_CURRENT); }
@Override public void onCallMergeFailed(ImsCall call, ImsReasonInfo reasonInfo) { if (DBG) log("onCallMergeFailed reasonInfo=" + reasonInfo); mPhone.notifySuppServiceFailed(Phone.SuppService.CONFERENCE); }
@Override public void onCallSessionTtyModeReceived(ImsCall call, int mode) { mPhone.onTtyModeReceived(mode); }
@Override public void onImsConnected() { if (DBG) log("onImsConnected"); mPhone.setServiceState(ServiceState.STATE_IN_SERVICE); mPhone.setImsRegistered(true); }
@Override public void onImsDisconnected() { if (DBG) log("onImsDisconnected"); mPhone.setServiceState(ServiceState.STATE_OUT_OF_SERVICE); mPhone.setImsRegistered(false); }
@Override public void onImsResumed() { if (DBG) log("onImsResumed"); mPhone.setServiceState(ServiceState.STATE_IN_SERVICE); }
@Override public void onImsSuspended() { if (DBG) log("onImsSuspended"); mPhone.setServiceState(ServiceState.STATE_OUT_OF_SERVICE); }
/** oirMode is one of the CLIR_ constants */ synchronized Connection dial(String dialString, int clirMode, int videoState) throws CallStateException { boolean isPhoneInEcmMode = SystemProperties.getBoolean(TelephonyProperties.PROPERTY_INECM_MODE, false); boolean isEmergencyNumber = PhoneNumberUtils.isEmergencyNumber(dialString); if (DBG) log("dial clirMode=" + clirMode); // note that this triggers call state changed notif clearDisconnected(); if (mImsManager == null) { throw new CallStateException("service not available"); } if (!canDial()) { throw new CallStateException("cannot dial in current state"); } if (isPhoneInEcmMode && isEmergencyNumber) { handleEcmTimer(ImsPhone.CANCEL_ECM_TIMER); } boolean holdBeforeDial = false; // The new call must be assigned to the foreground call. // That call must be idle, so place anything that's // there on hold if (mForegroundCall.getState() == ImsPhoneCall.State.ACTIVE) { if (mBackgroundCall.getState() != ImsPhoneCall.State.IDLE) { // we should have failed in !canDial() above before we get here throw new CallStateException("cannot dial in current state"); } // foreground call is empty for the newly dialed connection holdBeforeDial = true; switchWaitingOrHoldingAndActive(); } ImsPhoneCall.State fgState = ImsPhoneCall.State.IDLE; ImsPhoneCall.State bgState = ImsPhoneCall.State.IDLE; mClirMode = clirMode; synchronized (mSyncHold) { if (holdBeforeDial) { fgState = mForegroundCall.getState(); bgState = mBackgroundCall.getState(); // holding foreground call failed if (fgState == ImsPhoneCall.State.ACTIVE) { throw new CallStateException("cannot dial in current state"); } // holding foreground call succeeded if (bgState == ImsPhoneCall.State.HOLDING) { holdBeforeDial = false; } } mPendingMO = new ImsPhoneConnection( mPhone.getContext(), checkForTestEmergencyNumber(dialString), this, mForegroundCall); } addConnection(mPendingMO); if (!holdBeforeDial) { if ((!isPhoneInEcmMode) || (isPhoneInEcmMode && isEmergencyNumber)) { dialInternal(mPendingMO, clirMode, videoState); } else { try { getEcbmInterface().exitEmergencyCallbackMode(); } catch (ImsException e) { e.printStackTrace(); throw new CallStateException("service not available"); } mPhone.setOnEcbModeExitResponse(this, EVENT_EXIT_ECM_RESPONSE_CDMA, null); pendingCallClirMode = clirMode; pendingCallVideoState = videoState; pendingCallInEcm = true; } } updatePhoneState(); mPhone.notifyPreciseCallStateChanged(); return mPendingMO; }
Connection dial(String dialString, int videoState) throws CallStateException { SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(mPhone.getContext()); int oirMode = sp.getInt(PhoneBase.CLIR_KEY, CommandsInterface.CLIR_DEFAULT); return dial(dialString, oirMode, videoState); }