void conference() { if (DBG) log("conference"); ImsCall fgImsCall = mForegroundCall.getImsCall(); if (fgImsCall == null) { log("conference no foreground ims call"); return; } ImsCall bgImsCall = mBackgroundCall.getImsCall(); if (bgImsCall == null) { log("conference no background ims call"); return; } // Keep track of the connect time of the earliest call so that it can be set on the // {@code ImsConference} when it is created. long conferenceConnectTime = Math.min( mForegroundCall.getEarliestConnectTime(), mBackgroundCall.getEarliestConnectTime()); ImsPhoneConnection foregroundConnection = mForegroundCall.getFirstConnection(); if (foregroundConnection != null) { foregroundConnection.setConferenceConnectTime(conferenceConnectTime); } try { fgImsCall.merge(bgImsCall); } catch (ImsException e) { log("conference " + e.getMessage()); } }
void switchWaitingOrHoldingAndActive() throws CallStateException { if (DBG) log("switchWaitingOrHoldingAndActive"); if (mRingingCall.getState() == ImsPhoneCall.State.INCOMING) { throw new CallStateException("cannot be in the incoming state"); } if (mForegroundCall.getState() == ImsPhoneCall.State.ACTIVE) { ImsCall imsCall = mForegroundCall.getImsCall(); if (imsCall == null) { throw new CallStateException("no ims call"); } // Swap the ImsCalls pointed to by the foreground and background ImsPhoneCalls. // If hold or resume later fails, we will swap them back. mSwitchingFgAndBgCalls = true; mCallExpectedToResume = mBackgroundCall.getImsCall(); mForegroundCall.switchWith(mBackgroundCall); // Hold the foreground call; once the foreground call is held, the background call will // be resumed. try { imsCall.hold(); } catch (ImsException e) { mForegroundCall.switchWith(mBackgroundCall); throw new CallStateException(e.getMessage()); } } else if (mBackgroundCall.getState() == ImsPhoneCall.State.HOLDING) { resumeWaitingOrHolding(); } }
/** * Accepts a call with the specified video state. The video state is the video state that the user * has agreed upon in the InCall UI. * * @param videoState The video State * @throws CallStateException */ void acceptCall(int videoState) throws CallStateException { if (DBG) log("acceptCall"); if (mForegroundCall.getState().isAlive() && mBackgroundCall.getState().isAlive()) { throw new CallStateException("cannot accept call"); } if ((mRingingCall.getState() == ImsPhoneCall.State.WAITING) && mForegroundCall.getState().isAlive()) { setMute(false); switchWaitingOrHoldingAndActive(); } else if (mRingingCall.getState().isRinging()) { if (DBG) log("acceptCall: incoming..."); // Always unmute when answering a new call setMute(false); try { ImsCall imsCall = mRingingCall.getImsCall(); if (imsCall != null) { imsCall.accept(ImsCallProfile.getCallTypeFromVideoState(videoState)); } else { throw new CallStateException("no valid ims call"); } } catch (ImsException e) { throw new CallStateException("cannot accept call"); } } else { throw new CallStateException("phone not ringing"); } }
/* package */ void sendDtmf(char c, Message result) { if (DBG) log("sendDtmf"); ImsCall imscall = mForegroundCall.getImsCall(); if (imscall != null) { imscall.sendDtmf(c, result); } }
/*package*/ void stopDtmf() { if (DBG) log("stopDtmf"); ImsCall imscall = mForegroundCall.getImsCall(); if (imscall != null) { imscall.stopDtmf(); } else { loge("stopDtmf : no foreground call"); } }
/* 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 onReceive(Context context, Intent intent) { if (intent.getAction().equals(ImsManager.ACTION_IMS_INCOMING_CALL)) { if (DBG) log("onReceive : incoming call intent"); if (mImsManager == null) return; if (mServiceId < 0) return; try { // Network initiated USSD will be treated by mImsUssdListener boolean isUssd = intent.getBooleanExtra(ImsManager.EXTRA_USSD, false); if (isUssd) { if (DBG) log("onReceive : USSD"); mUssdSession = mImsManager.takeCall(mServiceId, intent, mImsUssdListener); if (mUssdSession != null) { mUssdSession.accept(ImsCallProfile.CALL_TYPE_VOICE); } return; } // Normal MT call ImsCall imsCall = mImsManager.takeCall(mServiceId, intent, mImsCallListener); ImsPhoneConnection conn = new ImsPhoneConnection( mPhone.getContext(), imsCall, ImsPhoneCallTracker.this, mRingingCall); addConnection(conn); IImsVideoCallProvider imsVideoCallProvider = imsCall.getCallSession().getVideoCallProvider(); if (imsVideoCallProvider != null) { ImsVideoCallProviderWrapper imsVideoCallProviderWrapper = new ImsVideoCallProviderWrapper(imsVideoCallProvider); conn.setVideoProvider(imsVideoCallProviderWrapper); } if ((mForegroundCall.getState() != ImsPhoneCall.State.IDLE) || (mBackgroundCall.getState() != ImsPhoneCall.State.IDLE)) { conn.update(imsCall, ImsPhoneCall.State.WAITING); } mPhone.notifyNewRingingConnection(conn); mPhone.notifyIncomingRing(); updatePhoneState(); mPhone.notifyPreciseCallStateChanged(); } catch (ImsException e) { loge("onReceive : exception " + e); } catch (RemoteException e) { } } }
/* package */ void cancelUSSD() { if (mUssdSession == null) return; try { mUssdSession.terminate(ImsReasonInfo.CODE_USER_TERMINATED); } catch (ImsException e) { } }
private void dialInternal(ImsPhoneConnection conn, int clirMode, int videoState) { if (conn == null) { return; } if (conn.getAddress() == null || conn.getAddress().length() == 0 || conn.getAddress().indexOf(PhoneNumberUtils.WILD) >= 0) { // Phone number is invalid conn.setDisconnectCause(DisconnectCause.INVALID_NUMBER); sendEmptyMessageDelayed(EVENT_HANGUP_PENDINGMO, TIMEOUT_HANGUP_PENDINGMO); return; } // Always unmute when initiating a new call setMute(false); int serviceType = PhoneNumberUtils.isEmergencyNumber(conn.getAddress()) ? ImsCallProfile.SERVICE_TYPE_EMERGENCY : ImsCallProfile.SERVICE_TYPE_NORMAL; int callType = ImsCallProfile.getCallTypeFromVideoState(videoState); // TODO(vt): Is this sufficient? At what point do we know the video state of the call? conn.setVideoState(videoState); try { String[] callees = new String[] {conn.getAddress()}; ImsCallProfile profile = mImsManager.createCallProfile(mServiceId, serviceType, callType); profile.setCallExtraInt(ImsCallProfile.EXTRA_OIR, clirMode); ImsCall imsCall = mImsManager.makeCall(mServiceId, profile, callees, mImsCallListener); conn.setImsCall(imsCall); IImsVideoCallProvider imsVideoCallProvider = imsCall.getCallSession().getVideoCallProvider(); if (imsVideoCallProvider != null) { ImsVideoCallProviderWrapper imsVideoCallProviderWrapper = new ImsVideoCallProviderWrapper(imsVideoCallProvider); conn.setVideoProvider(imsVideoCallProviderWrapper); } } catch (ImsException e) { loge("dialInternal : " + e); conn.setDisconnectCause(DisconnectCause.ERROR_UNSPECIFIED); sendEmptyMessageDelayed(EVENT_HANGUP_PENDINGMO, TIMEOUT_HANGUP_PENDINGMO); } catch (RemoteException e) { } }
/* package */ void resumeWaitingOrHolding() throws CallStateException { if (DBG) log("resumeWaitingOrHolding"); try { if (mForegroundCall.getState().isAlive()) { // resume foreground call after holding background call // they were switched before holding ImsCall imsCall = mForegroundCall.getImsCall(); if (imsCall != null) imsCall.resume(); } else if (mRingingCall.getState() == ImsPhoneCall.State.WAITING) { // accept waiting call after holding background call ImsCall imsCall = mRingingCall.getImsCall(); if (imsCall != null) imsCall.accept(ImsCallProfile.CALL_TYPE_VOICE); } else { // Just resume background call. // To distinguish resuming call with swapping calls // we do not switch calls.here // ImsPhoneConnection.update will chnage the parent when completed ImsCall imsCall = mBackgroundCall.getImsCall(); if (imsCall != null) imsCall.resume(); } } catch (ImsException e) { throw new CallStateException(e.getMessage()); } }
@Override public void onCallTerminated(ImsCall imsCall, ImsReasonInfo reasonInfo) { if (DBG) log("mImsUssdListener onCallTerminated reasonCode=" + reasonInfo.getCode()); if (imsCall == mUssdSession) { mUssdSession = null; if (mPendingUssd != null) { CommandException ex = new CommandException(CommandException.Error.GENERIC_FAILURE); AsyncResult.forMessage(mPendingUssd, null, ex); mPendingUssd.sendToTarget(); mPendingUssd = null; } } imsCall.close(); }
/* 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); } }