Methods Summary |
---|
private void | acquireWakeLock()
log("acquireWakeLock");
mPartialWakeLock.acquire();
|
public void | cancelPostDial()
setPostDialState(PostDialState.CANCELLED);
|
boolean | compareTo(DriverCall c)
// On mobile originated (MO) calls, the phone number may have changed
// due to a SIM Toolkit call control modification.
//
// We assume we know when MO calls are created (since we created them)
// and therefore don't need to compare the phone number anyway.
if (! (mIsIncoming || c.isMT)) return true;
// A new call appearing by SRVCC may have invalid number
// if IMS service is not tightly coupled with cellular modem stack.
// Thus we prefer the preexisting handover connection instance.
if (mOrigConnection != null) return true;
// ... but we can compare phone numbers on MT calls, and we have
// no control over when they begin, so we might as well
String cAddress = PhoneNumberUtils.stringFromStringAndTOA(c.number, c.TOA);
return mIsIncoming == c.isMT && equalsHandlesNulls(mAddress, cAddress);
|
private void | createWakeLock(android.content.Context context)
PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
mPartialWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, LOG_TAG);
|
int | disconnectCauseFromCode(int causeCode)Maps RIL call disconnect code to {@link DisconnectCause}.
/**
* See 22.001 Annex F.4 for mapping of cause codes
* to local tones
*/
switch (causeCode) {
case CallFailCause.USER_BUSY:
return DisconnectCause.BUSY;
case CallFailCause.NO_CIRCUIT_AVAIL:
case CallFailCause.TEMPORARY_FAILURE:
case CallFailCause.SWITCHING_CONGESTION:
case CallFailCause.CHANNEL_NOT_AVAIL:
case CallFailCause.QOS_NOT_AVAIL:
case CallFailCause.BEARER_NOT_AVAIL:
return DisconnectCause.CONGESTION;
case CallFailCause.ACM_LIMIT_EXCEEDED:
return DisconnectCause.LIMIT_EXCEEDED;
case CallFailCause.CALL_BARRED:
return DisconnectCause.CALL_BARRED;
case CallFailCause.FDN_BLOCKED:
return DisconnectCause.FDN_BLOCKED;
case CallFailCause.UNOBTAINABLE_NUMBER:
return DisconnectCause.UNOBTAINABLE_NUMBER;
case CallFailCause.DIAL_MODIFIED_TO_USSD:
return DisconnectCause.DIAL_MODIFIED_TO_USSD;
case CallFailCause.DIAL_MODIFIED_TO_SS:
return DisconnectCause.DIAL_MODIFIED_TO_SS;
case CallFailCause.DIAL_MODIFIED_TO_DIAL:
return DisconnectCause.DIAL_MODIFIED_TO_DIAL;
case CallFailCause.ERROR_UNSPECIFIED:
case CallFailCause.NORMAL_CLEARING:
default:
GSMPhone phone = mOwner.mPhone;
int serviceState = phone.getServiceState().getState();
UiccCardApplication cardApp = phone.getUiccCardApplication();
AppState uiccAppState = (cardApp != null) ? cardApp.getState() :
AppState.APPSTATE_UNKNOWN;
if (serviceState == ServiceState.STATE_POWER_OFF) {
return DisconnectCause.POWER_OFF;
} else if (serviceState == ServiceState.STATE_OUT_OF_SERVICE
|| serviceState == ServiceState.STATE_EMERGENCY_ONLY ) {
return DisconnectCause.OUT_OF_SERVICE;
} else if (uiccAppState != AppState.APPSTATE_READY) {
return DisconnectCause.ICC_ERROR;
} else if (causeCode == CallFailCause.ERROR_UNSPECIFIED) {
if (phone.mSST.mRestrictedState.isCsRestricted()) {
return DisconnectCause.CS_RESTRICTED;
} else if (phone.mSST.mRestrictedState.isCsEmergencyRestricted()) {
return DisconnectCause.CS_RESTRICTED_EMERGENCY;
} else if (phone.mSST.mRestrictedState.isCsNormalRestricted()) {
return DisconnectCause.CS_RESTRICTED_NORMAL;
} else {
return DisconnectCause.ERROR_UNSPECIFIED;
}
} else if (causeCode == CallFailCause.NORMAL_CLEARING) {
return DisconnectCause.NORMAL;
} else {
// If nothing else matches, report unknown call drop reason
// to app, not NORMAL call end.
return DisconnectCause.ERROR_UNSPECIFIED;
}
}
|
public void | dispose()
|
static boolean | equalsHandlesNulls(java.lang.Object a, java.lang.Object b)
return (a == null) ? (b == null) : a.equals (b);
|
void | fakeHoldBeforeDial()Called when this Connection is in the foregroundCall
when a dial is initiated.
We know we're ACTIVE, and we know we're going to end up
HOLDING in the backgroundCall
if (mParent != null) {
mParent.detach(this);
}
mParent = mOwner.mBackgroundCall;
mParent.attachFake(this, GsmCall.State.HOLDING);
onStartedHolding();
|
protected void | finalize()
/**
* It is understood that This finializer is not guaranteed
* to be called and the release lock call is here just in
* case there is some path that doesn't call onDisconnect
* and or onConnectedInOrOut.
*/
if (mPartialWakeLock.isHeld()) {
Rlog.e(LOG_TAG, "[GSMConn] UNEXPECTED; mPartialWakeLock is held when finalizing.");
}
clearPostDialListeners();
releaseWakeLock();
|
public GsmCall | getCall()
return mParent;
|
public int | getDisconnectCause()
return mCause;
|
public long | getDisconnectTime()
return mDisconnectTime;
|
int | getGSMIndex()
if (mIndex >= 0) {
return mIndex + 1;
} else {
throw new CallStateException ("GSM index not yet assigned");
}
|
public long | getHoldDurationMillis()
if (getState() != GsmCall.State.HOLDING) {
// If not holding, return 0
return 0;
} else {
return SystemClock.elapsedRealtime() - mHoldingStartTime;
}
|
public int | getNumberPresentation()
return mNumberPresentation;
|
public Connection | getOrigConnection()
return mOrigConnection;
|
public PostDialState | getPostDialState()
return mPostDialState;
|
public int | getPreciseDisconnectCause()
return mPreciseCause;
|
public java.lang.String | getRemainingPostDialString()
if (mPostDialState == PostDialState.CANCELLED
|| mPostDialState == PostDialState.COMPLETE
|| mPostDialString == null
|| mPostDialString.length() <= mNextPostDialChar
) {
return "";
}
return mPostDialString.substring(mNextPostDialChar);
|
public GsmCall.State | getState()
if (mDisconnected) {
return GsmCall.State.DISCONNECTED;
} else {
return super.getState();
}
|
public UUSInfo | getUUSInfo()
return mUusInfo;
|
public void | hangup()
if (!mDisconnected) {
mOwner.hangup(this);
} else {
throw new CallStateException ("disconnected");
}
|
private boolean | isConnectingInOrOut()"connecting" means "has never been ACTIVE" for both incoming
and outgoing calls
return mParent == null || mParent == mOwner.mRingingCall
|| mParent.mState == GsmCall.State.DIALING
|| mParent.mState == GsmCall.State.ALERTING;
|
public boolean | isMultiparty()
if (mOrigConnection != null) {
return mOrigConnection.isMultiparty();
}
return false;
|
private void | log(java.lang.String msg)
Rlog.d(LOG_TAG, "[GSMConn] " + msg);
|
public void | migrateFrom(Connection c)
if (c == null) return;
super.migrateFrom(c);
this.mUusInfo = c.getUUSInfo();
this.setUserData(c.getUserData());
|
void | onConnectedInOrOut()An incoming or outgoing call has connected
mConnectTime = System.currentTimeMillis();
mConnectTimeReal = SystemClock.elapsedRealtime();
mDuration = 0;
// bug #678474: incoming call interpreted as missed call, even though
// it sounds like the user has picked up the call.
if (Phone.DEBUG_PHONE) {
log("onConnectedInOrOut: connectTime=" + mConnectTime);
}
if (!mIsIncoming) {
// outgoing calls only
processNextPostDialChar();
}
releaseWakeLock();
|
boolean | onDisconnect(int cause)Called when the radio indicates the connection has been disconnected.
boolean changed = false;
mCause = cause;
if (!mDisconnected) {
mIndex = -1;
mDisconnectTime = System.currentTimeMillis();
mDuration = SystemClock.elapsedRealtime() - mConnectTimeReal;
mDisconnected = true;
if (DBG) Rlog.d(LOG_TAG, "onDisconnect: cause=" + cause);
mOwner.mPhone.notifyDisconnect(this);
if (mParent != null) {
changed = mParent.connectionDisconnected(this);
}
mOrigConnection = null;
}
clearPostDialListeners();
releaseWakeLock();
return changed;
|
void | onHangupLocal()Called when this Connection is being hung up locally (eg, user pressed "end")
Note that at this point, the hangup request has been dispatched to the radio
but no response has yet been received so update() has not yet been called
mCause = DisconnectCause.LOCAL;
mPreciseCause = 0;
|
void | onRemoteDisconnect(int causeCode)
this.mPreciseCause = causeCode;
onDisconnect(disconnectCauseFromCode(causeCode));
|
void | onStartedHolding()
mHoldingStartTime = SystemClock.elapsedRealtime();
|
private GsmCall | parentFromDCState(DriverCall.State state)
switch (state) {
case ACTIVE:
case DIALING:
case ALERTING:
return mOwner.mForegroundCall;
//break;
case HOLDING:
return mOwner.mBackgroundCall;
//break;
case INCOMING:
case WAITING:
return mOwner.mRingingCall;
//break;
default:
throw new RuntimeException("illegal call state: " + state);
}
|
public void | proceedAfterWaitChar()
if (mPostDialState != PostDialState.WAIT) {
Rlog.w(LOG_TAG, "GsmConnection.proceedAfterWaitChar(): Expected "
+ "getPostDialState() to be WAIT but was " + mPostDialState);
return;
}
setPostDialState(PostDialState.STARTED);
processNextPostDialChar();
|
public void | proceedAfterWildChar(java.lang.String str)
if (mPostDialState != PostDialState.WILD) {
Rlog.w(LOG_TAG, "GsmConnection.proceedAfterWaitChar(): Expected "
+ "getPostDialState() to be WILD but was " + mPostDialState);
return;
}
setPostDialState(PostDialState.STARTED);
// make a new postDialString, with the wild char replacement string
// at the beginning, followed by the remaining postDialString.
StringBuilder buf = new StringBuilder(str);
buf.append(mPostDialString.substring(mNextPostDialChar));
mPostDialString = buf.toString();
mNextPostDialChar = 0;
if (Phone.DEBUG_PHONE) {
log("proceedAfterWildChar: new postDialString is " +
mPostDialString);
}
processNextPostDialChar();
|
private void | processNextPostDialChar()
char c = 0;
Registrant postDialHandler;
if (mPostDialState == PostDialState.CANCELLED) {
//Rlog.v("GSM", "##### processNextPostDialChar: postDialState == CANCELLED, bail");
return;
}
if (mPostDialString == null ||
mPostDialString.length() <= mNextPostDialChar) {
setPostDialState(PostDialState.COMPLETE);
// notifyMessage.arg1 is 0 on complete
c = 0;
} else {
boolean isValid;
setPostDialState(PostDialState.STARTED);
c = mPostDialString.charAt(mNextPostDialChar++);
isValid = processPostDialChar(c);
if (!isValid) {
// Will call processNextPostDialChar
mHandler.obtainMessage(EVENT_NEXT_POST_DIAL).sendToTarget();
// Don't notify application
Rlog.e("GSM", "processNextPostDialChar: c=" + c + " isn't valid!");
return;
}
}
notifyPostDialListenersNextChar(c);
// TODO: remove the following code since the handler no longer executes anything.
postDialHandler = mOwner.mPhone.mPostDialHandler;
Message notifyMessage;
if (postDialHandler != null
&& (notifyMessage = postDialHandler.messageForRegistrant()) != null) {
// The AsyncResult.result is the Connection object
PostDialState state = mPostDialState;
AsyncResult ar = AsyncResult.forMessage(notifyMessage);
ar.result = this;
ar.userObj = state;
// arg1 is the character that was/is being processed
notifyMessage.arg1 = c;
//Rlog.v("GSM", "##### processNextPostDialChar: send msg to postDialHandler, arg1=" + c);
notifyMessage.sendToTarget();
}
|
private boolean | processPostDialChar(char c)Performs the appropriate action for a post-dial char, but does not
notify application. returns false if the character is invalid and
should be ignored
if (PhoneNumberUtils.is12Key(c)) {
mOwner.mCi.sendDtmf(c, mHandler.obtainMessage(EVENT_DTMF_DONE));
} else if (c == PhoneNumberUtils.PAUSE) {
// From TS 22.101:
// It continues...
// Upon the called party answering the UE shall send the DTMF digits
// automatically to the network after a delay of 3 seconds( 20 ).
// The digits shall be sent according to the procedures and timing
// specified in 3GPP TS 24.008 [13]. The first occurrence of the
// "DTMF Control Digits Separator" shall be used by the ME to
// distinguish between the addressing digits (i.e. the phone number)
// and the DTMF digits. Upon subsequent occurrences of the
// separator,
// the UE shall pause again for 3 seconds ( 20 ) before sending
// any further DTMF digits.
mHandler.sendMessageDelayed(mHandler.obtainMessage(EVENT_PAUSE_DONE),
PAUSE_DELAY_MILLIS);
} else if (c == PhoneNumberUtils.WAIT) {
setPostDialState(PostDialState.WAIT);
} else if (c == PhoneNumberUtils.WILD) {
setPostDialState(PostDialState.WILD);
} else {
return false;
}
return true;
|
private void | releaseWakeLock()
synchronized(mPartialWakeLock) {
if (mPartialWakeLock.isHeld()) {
log("releaseWakeLock");
mPartialWakeLock.release();
}
}
|
public void | separate()
if (!mDisconnected) {
mOwner.separate(this);
} else {
throw new CallStateException ("disconnected");
}
|
private void | setPostDialState(PostDialState s)Set post dial state and acquire wake lock while switching to "started"
state, the wake lock will be released if state switches out of "started"
state or after WAKE_LOCK_TIMEOUT_MILLIS.
if (mPostDialState != PostDialState.STARTED
&& s == PostDialState.STARTED) {
acquireWakeLock();
Message msg = mHandler.obtainMessage(EVENT_WAKE_LOCK_TIMEOUT);
mHandler.sendMessageDelayed(msg, WAKE_LOCK_TIMEOUT_MILLIS);
} else if (mPostDialState == PostDialState.STARTED
&& s != PostDialState.STARTED) {
mHandler.removeMessages(EVENT_WAKE_LOCK_TIMEOUT);
releaseWakeLock();
}
mPostDialState = s;
notifyPostDialListeners();
|
boolean | update(DriverCall dc)
GsmCall newParent;
boolean changed = false;
boolean wasConnectingInOrOut = isConnectingInOrOut();
boolean wasHolding = (getState() == GsmCall.State.HOLDING);
newParent = parentFromDCState(dc.state);
//Ignore dc.number and dc.name in case of a handover connection
if (mOrigConnection != null) {
if (Phone.DEBUG_PHONE) log("update: mOrigConnection is not null");
} else {
log(" mNumberConverted " + mNumberConverted);
if (!equalsHandlesNulls(mAddress, dc.number) && (!mNumberConverted
|| !equalsHandlesNulls(mConvertedNumber, dc.number))) {
if (Phone.DEBUG_PHONE) log("update: phone # changed!");
mAddress = dc.number;
changed = true;
}
}
// A null cnapName should be the same as ""
if (TextUtils.isEmpty(dc.name)) {
if (!TextUtils.isEmpty(mCnapName)) {
changed = true;
mCnapName = "";
}
} else if (!dc.name.equals(mCnapName)) {
changed = true;
mCnapName = dc.name;
}
if (Phone.DEBUG_PHONE) log("--dssds----"+mCnapName);
mCnapNamePresentation = dc.namePresentation;
mNumberPresentation = dc.numberPresentation;
if (newParent != mParent) {
if (mParent != null) {
mParent.detach(this);
}
newParent.attach(this, dc);
mParent = newParent;
changed = true;
} else {
boolean parentStateChange;
parentStateChange = mParent.update (this, dc);
changed = changed || parentStateChange;
}
/** Some state-transition events */
if (Phone.DEBUG_PHONE) log(
"update: parent=" + mParent +
", hasNewParent=" + (newParent != mParent) +
", wasConnectingInOrOut=" + wasConnectingInOrOut +
", wasHolding=" + wasHolding +
", isConnectingInOrOut=" + isConnectingInOrOut() +
", changed=" + changed);
if (wasConnectingInOrOut && !isConnectingInOrOut()) {
onConnectedInOrOut();
}
if (changed && !wasHolding && (getState() == GsmCall.State.HOLDING)) {
// We've transitioned into HOLDING
onStartedHolding();
}
return changed;
|