am 3d7606aa
: SIP: enhance timeout and registration status feedback.
Merge commit '3d7606aa607b24817e37c264f2141ed7b2d50be0' into gingerbread-plus-aosp * commit '3d7606aa607b24817e37c264f2141ed7b2d50be0': SIP: enhance timeout and registration status feedback.
This commit is contained in:
@ -27,6 +27,7 @@ import android.net.NetworkInfo;
|
||||
import android.net.sip.ISipService;
|
||||
import android.net.sip.ISipSession;
|
||||
import android.net.sip.ISipSessionListener;
|
||||
import android.net.sip.SipErrorCode;
|
||||
import android.net.sip.SipManager;
|
||||
import android.net.sip.SipProfile;
|
||||
import android.net.sip.SipSessionAdapter;
|
||||
@ -528,6 +529,8 @@ public final class SipService extends ISipService.Stub {
|
||||
private int mBackoff = 1;
|
||||
private boolean mRegistered;
|
||||
private long mExpiryTime;
|
||||
private SipErrorCode mErrorCode;
|
||||
private String mErrorMessage;
|
||||
|
||||
private String getAction() {
|
||||
return toString();
|
||||
@ -551,15 +554,25 @@ public final class SipService extends ISipService.Stub {
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
stop(false);
|
||||
}
|
||||
|
||||
private void stopButKeepStates() {
|
||||
stop(true);
|
||||
}
|
||||
|
||||
private void stop(boolean keepStates) {
|
||||
if (mSession == null) return;
|
||||
if (mConnected) mSession.unregister();
|
||||
if (mConnected && mRegistered) mSession.unregister();
|
||||
mTimer.cancel(this);
|
||||
if (mKeepAliveProcess != null) {
|
||||
mKeepAliveProcess.stop();
|
||||
mKeepAliveProcess = null;
|
||||
}
|
||||
mSession = null;
|
||||
mRegistered = false;
|
||||
if (!keepStates) {
|
||||
mSession = null;
|
||||
mRegistered = false;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isStopped() {
|
||||
@ -568,20 +581,33 @@ public final class SipService extends ISipService.Stub {
|
||||
|
||||
public void setListener(ISipSessionListener listener) {
|
||||
Log.v(TAG, "setListener(): " + listener);
|
||||
mProxy.setListener(listener);
|
||||
if (mSession == null) return;
|
||||
synchronized (SipService.this) {
|
||||
mProxy.setListener(listener);
|
||||
if (mSession == null) return;
|
||||
|
||||
try {
|
||||
if ((mSession != null) && SipSessionState.REGISTERING.equals(
|
||||
mSession.getState())) {
|
||||
mProxy.onRegistering(mSession);
|
||||
} else if (mRegistered) {
|
||||
int duration = (int)
|
||||
(mExpiryTime - SystemClock.elapsedRealtime());
|
||||
mProxy.onRegistrationDone(mSession, duration);
|
||||
try {
|
||||
SipSessionState state = (mSession == null)
|
||||
? SipSessionState.READY_TO_CALL
|
||||
: Enum.valueOf(
|
||||
SipSessionState.class, mSession.getState());
|
||||
if ((state == SipSessionState.REGISTERING)
|
||||
|| (state == SipSessionState.DEREGISTERING)) {
|
||||
mProxy.onRegistering(mSession);
|
||||
} else if (mRegistered) {
|
||||
int duration = (int)
|
||||
(mExpiryTime - SystemClock.elapsedRealtime());
|
||||
mProxy.onRegistrationDone(mSession, duration);
|
||||
} else if (mErrorCode != null) {
|
||||
if (mErrorCode == SipErrorCode.TIME_OUT) {
|
||||
mProxy.onRegistrationTimeout(mSession);
|
||||
} else {
|
||||
mProxy.onRegistrationFailed(mSession,
|
||||
mErrorCode.toString(), mErrorMessage);
|
||||
}
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
Log.w(TAG, "setListener(): " + t);
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
Log.w(TAG, "setListener(): " + t);
|
||||
}
|
||||
}
|
||||
|
||||
@ -590,6 +616,8 @@ public final class SipService extends ISipService.Stub {
|
||||
}
|
||||
|
||||
public void run() {
|
||||
mErrorCode = null;
|
||||
mErrorMessage = null;
|
||||
Log.v(TAG, " ~~~ registering");
|
||||
synchronized (SipService.this) {
|
||||
if (mConnected && !isStopped()) mSession.register(EXPIRY_TIME);
|
||||
@ -634,11 +662,7 @@ public final class SipService extends ISipService.Stub {
|
||||
synchronized (SipService.this) {
|
||||
if (!isStopped() && (session != mSession)) return;
|
||||
mRegistered = false;
|
||||
try {
|
||||
mProxy.onRegistering(session);
|
||||
} catch (Throwable t) {
|
||||
Log.w(TAG, "onRegistering()", t);
|
||||
}
|
||||
mProxy.onRegistering(session);
|
||||
}
|
||||
}
|
||||
|
||||
@ -647,11 +671,9 @@ public final class SipService extends ISipService.Stub {
|
||||
Log.v(TAG, "onRegistrationDone(): " + session + ": " + mSession);
|
||||
synchronized (SipService.this) {
|
||||
if (!isStopped() && (session != mSession)) return;
|
||||
try {
|
||||
mProxy.onRegistrationDone(session, duration);
|
||||
} catch (Throwable t) {
|
||||
Log.w(TAG, "onRegistrationDone()", t);
|
||||
}
|
||||
|
||||
mProxy.onRegistrationDone(session, duration);
|
||||
|
||||
if (isStopped()) return;
|
||||
|
||||
if (duration > 0) {
|
||||
@ -687,19 +709,25 @@ public final class SipService extends ISipService.Stub {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRegistrationFailed(ISipSession session, String className,
|
||||
String message) {
|
||||
public void onRegistrationFailed(ISipSession session,
|
||||
String errorCodeString, String message) {
|
||||
SipErrorCode errorCode =
|
||||
Enum.valueOf(SipErrorCode.class, errorCodeString);
|
||||
Log.v(TAG, "onRegistrationFailed(): " + session + ": " + mSession
|
||||
+ ": " + className + ": " + message);
|
||||
+ ": " + errorCode + ": " + message);
|
||||
synchronized (SipService.this) {
|
||||
if (!isStopped() && (session != mSession)) return;
|
||||
try {
|
||||
mProxy.onRegistrationFailed(session, className, message);
|
||||
} catch (Throwable t) {
|
||||
Log.w(TAG, "onRegistrationFailed(): " + t);
|
||||
}
|
||||
mErrorCode = errorCode;
|
||||
mErrorMessage = message;
|
||||
mProxy.onRegistrationFailed(session, errorCode.toString(),
|
||||
message);
|
||||
|
||||
if (!isStopped()) onError();
|
||||
if (errorCode == SipErrorCode.INVALID_CREDENTIALS) {
|
||||
Log.d(TAG, " pause auto-registration");
|
||||
stopButKeepStates();
|
||||
} else if (!isStopped()) {
|
||||
onError();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -708,11 +736,8 @@ public final class SipService extends ISipService.Stub {
|
||||
Log.v(TAG, "onRegistrationTimeout(): " + session + ": " + mSession);
|
||||
synchronized (SipService.this) {
|
||||
if (!isStopped() && (session != mSession)) return;
|
||||
try {
|
||||
mProxy.onRegistrationTimeout(session);
|
||||
} catch (Throwable t) {
|
||||
Log.w(TAG, "onRegistrationTimeout(): " + t);
|
||||
}
|
||||
mErrorCode = SipErrorCode.TIME_OUT;
|
||||
mProxy.onRegistrationTimeout(session);
|
||||
|
||||
if (!isStopped()) {
|
||||
mRegistered = false;
|
||||
|
@ -412,13 +412,7 @@ class SipSessionGroup implements SipListener {
|
||||
processCommand(command);
|
||||
} catch (SipException e) {
|
||||
Log.w(TAG, "command error: " + command, e);
|
||||
// TODO: find a better way to do this
|
||||
if ((command instanceof RegisterCommand)
|
||||
|| (command == DEREGISTER)) {
|
||||
onRegistrationFailed(e);
|
||||
} else {
|
||||
onError(e);
|
||||
}
|
||||
onError(e);
|
||||
}
|
||||
}
|
||||
}).start();
|
||||
@ -480,7 +474,9 @@ class SipSessionGroup implements SipListener {
|
||||
|
||||
private void processCommand(EventObject command) throws SipException {
|
||||
if (!process(command)) {
|
||||
throw new SipException("wrong state to execute: " + command);
|
||||
onError(SipErrorCode.IN_PROGRESS,
|
||||
"cannot initiate a new transaction to execute: "
|
||||
+ command);
|
||||
}
|
||||
}
|
||||
|
||||
@ -562,11 +558,8 @@ class SipSessionGroup implements SipListener {
|
||||
if (evt instanceof TimeoutEvent) {
|
||||
processTimeout((TimeoutEvent) evt);
|
||||
} else {
|
||||
Log.d(TAG, "Transaction terminated:" + this);
|
||||
if (!SipSessionState.IN_CALL.equals(mState)) {
|
||||
removeSipSession(this);
|
||||
}
|
||||
return true;
|
||||
processTransactionTerminated(
|
||||
(TransactionTerminatedEvent) evt);
|
||||
}
|
||||
return true;
|
||||
} else if (evt instanceof DialogTerminatedEvent) {
|
||||
@ -585,6 +578,20 @@ class SipSessionGroup implements SipListener {
|
||||
}
|
||||
}
|
||||
|
||||
private void processTransactionTerminated(
|
||||
TransactionTerminatedEvent event) {
|
||||
switch (mState) {
|
||||
case IN_CALL:
|
||||
case READY_TO_CALL:
|
||||
Log.d(TAG, "Transaction terminated; do nothing");
|
||||
break;
|
||||
default:
|
||||
Log.d(TAG, "Transaction terminated early: " + this);
|
||||
onError(SipErrorCode.TRANSACTION_TERMINTED,
|
||||
"transaction terminated");
|
||||
}
|
||||
}
|
||||
|
||||
private void processTimeout(TimeoutEvent event) {
|
||||
Log.d(TAG, "processing Timeout..." + event);
|
||||
Transaction current = event.isServerTransaction()
|
||||
@ -600,25 +607,26 @@ class SipSessionGroup implements SipListener {
|
||||
return;
|
||||
}
|
||||
switch (mState) {
|
||||
case REGISTERING:
|
||||
case DEREGISTERING:
|
||||
reset();
|
||||
mProxy.onRegistrationTimeout(this);
|
||||
break;
|
||||
case INCOMING_CALL:
|
||||
case INCOMING_CALL_ANSWERING:
|
||||
case OUTGOING_CALL_CANCELING:
|
||||
endCallOnError(SipErrorCode.TIME_OUT, event.toString());
|
||||
break;
|
||||
case PINGING:
|
||||
reset();
|
||||
mReRegisterFlag = true;
|
||||
mState = SipSessionState.READY_TO_CALL;
|
||||
break;
|
||||
case REGISTERING:
|
||||
case DEREGISTERING:
|
||||
reset();
|
||||
mProxy.onRegistrationTimeout(this);
|
||||
break;
|
||||
case INCOMING_CALL:
|
||||
case INCOMING_CALL_ANSWERING:
|
||||
case OUTGOING_CALL:
|
||||
case OUTGOING_CALL_CANCELING:
|
||||
onError(SipErrorCode.TIME_OUT, event.toString());
|
||||
break;
|
||||
case PINGING:
|
||||
reset();
|
||||
mReRegisterFlag = true;
|
||||
mState = SipSessionState.READY_TO_CALL;
|
||||
break;
|
||||
|
||||
default:
|
||||
// do nothing
|
||||
break;
|
||||
default:
|
||||
Log.d(TAG, " do nothing");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -665,7 +673,7 @@ class SipSessionGroup implements SipListener {
|
||||
} else {
|
||||
Log.w(TAG, "peer did not respect our rport request");
|
||||
}
|
||||
mState = SipSessionState.READY_TO_CALL;
|
||||
reset();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@ -687,7 +695,6 @@ class SipSessionGroup implements SipListener {
|
||||
switch (statusCode) {
|
||||
case Response.OK:
|
||||
SipSessionState state = mState;
|
||||
reset();
|
||||
onRegistrationDone((state == SipSessionState.REGISTERING)
|
||||
? getExpiryTime(((ResponseEvent) evt).getResponse())
|
||||
: -1);
|
||||
@ -698,15 +705,13 @@ class SipSessionGroup implements SipListener {
|
||||
case Response.PROXY_AUTHENTICATION_REQUIRED:
|
||||
if (!handleAuthentication(event)) {
|
||||
Log.v(TAG, "Incorrect username/password");
|
||||
reset();
|
||||
onRegistrationFailed(SipErrorCode.INVALID_CREDENTIALS,
|
||||
"incorrect username or password");
|
||||
}
|
||||
return true;
|
||||
default:
|
||||
if (statusCode >= 500) {
|
||||
reset();
|
||||
onRegistrationFailed(createCallbackException(response));
|
||||
onRegistrationFailed(response);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -720,7 +725,6 @@ class SipSessionGroup implements SipListener {
|
||||
String nonce = getNonceFromResponse(response);
|
||||
if (((nonce != null) && nonce.equals(mLastNonce)) ||
|
||||
(nonce == mLastNonce)) {
|
||||
Log.v(TAG, "Incorrect username/password");
|
||||
return false;
|
||||
} else {
|
||||
mClientTransaction = mSipHelper.handleChallenge(
|
||||
@ -906,7 +910,7 @@ class SipSessionGroup implements SipListener {
|
||||
}
|
||||
|
||||
if (statusCode >= 400) {
|
||||
onError(createCallbackException(response));
|
||||
onError(response);
|
||||
return true;
|
||||
}
|
||||
} else if (evt instanceof TransactionTerminatedEvent) {
|
||||
@ -954,10 +958,6 @@ class SipSessionGroup implements SipListener {
|
||||
response.getReasonPhrase(), response.getStatusCode());
|
||||
}
|
||||
|
||||
private Exception createCallbackException(Response response) {
|
||||
return new SipException(createErrorMessage(response));
|
||||
}
|
||||
|
||||
private void establishCall() {
|
||||
mState = SipSessionState.IN_CALL;
|
||||
mInCall = true;
|
||||
@ -965,22 +965,22 @@ class SipSessionGroup implements SipListener {
|
||||
}
|
||||
|
||||
private void fallbackToPreviousInCall(Throwable exception) {
|
||||
mState = SipSessionState.IN_CALL;
|
||||
exception = getRootCause(exception);
|
||||
mProxy.onCallChangeFailed(this, getErrorCode(exception).toString(),
|
||||
fallbackToPreviousInCall(getErrorCode(exception),
|
||||
exception.toString());
|
||||
}
|
||||
|
||||
private void fallbackToPreviousInCall(SipErrorCode errorCode,
|
||||
String message) {
|
||||
mState = SipSessionState.IN_CALL;
|
||||
mProxy.onCallChangeFailed(this, errorCode.toString(), message);
|
||||
}
|
||||
|
||||
private void endCallNormally() {
|
||||
reset();
|
||||
mProxy.onCallEnded(this);
|
||||
}
|
||||
|
||||
private void endCallOnError(Throwable exception) {
|
||||
exception = getRootCause(exception);
|
||||
endCallOnError(getErrorCode(exception), exception.toString());
|
||||
}
|
||||
|
||||
private void endCallOnError(SipErrorCode errorCode, String message) {
|
||||
reset();
|
||||
mProxy.onError(this, errorCode.toString(), message);
|
||||
@ -991,26 +991,34 @@ class SipSessionGroup implements SipListener {
|
||||
mProxy.onCallBusy(this);
|
||||
}
|
||||
|
||||
private void onError(Throwable exception) {
|
||||
if (mInCall) {
|
||||
fallbackToPreviousInCall(exception);
|
||||
} else {
|
||||
endCallOnError(exception);
|
||||
private void onError(SipErrorCode errorCode, String message) {
|
||||
switch (mState) {
|
||||
case REGISTERING:
|
||||
case DEREGISTERING:
|
||||
onRegistrationFailed(errorCode, message);
|
||||
break;
|
||||
default:
|
||||
if (mInCall) {
|
||||
fallbackToPreviousInCall(errorCode, message);
|
||||
} else {
|
||||
endCallOnError(errorCode, message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void onError(Throwable exception) {
|
||||
exception = getRootCause(exception);
|
||||
onError(getErrorCode(exception), exception.toString());
|
||||
}
|
||||
|
||||
private void onError(Response response) {
|
||||
if (mInCall) {
|
||||
fallbackToPreviousInCall(createCallbackException(response));
|
||||
int statusCode = response.getStatusCode();
|
||||
if (!mInCall && ((statusCode == Response.TEMPORARILY_UNAVAILABLE)
|
||||
|| (statusCode == Response.BUSY_HERE))) {
|
||||
endCallOnBusy();
|
||||
} else {
|
||||
int statusCode = response.getStatusCode();
|
||||
if ((statusCode == Response.TEMPORARILY_UNAVAILABLE)
|
||||
|| (statusCode == Response.BUSY_HERE)) {
|
||||
endCallOnBusy();
|
||||
} else {
|
||||
endCallOnError(getErrorCode(statusCode),
|
||||
createErrorMessage(response));
|
||||
}
|
||||
onError(getErrorCode(statusCode), createErrorMessage(response));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1053,19 +1061,29 @@ class SipSessionGroup implements SipListener {
|
||||
}
|
||||
|
||||
private void onRegistrationDone(int duration) {
|
||||
reset();
|
||||
mProxy.onRegistrationDone(this, duration);
|
||||
}
|
||||
|
||||
private void onRegistrationFailed(SipErrorCode errorCode,
|
||||
String message) {
|
||||
reset();
|
||||
mProxy.onRegistrationFailed(this, errorCode.toString(), message);
|
||||
}
|
||||
|
||||
private void onRegistrationFailed(Throwable exception) {
|
||||
reset();
|
||||
exception = getRootCause(exception);
|
||||
onRegistrationFailed(getErrorCode(exception),
|
||||
exception.toString());
|
||||
}
|
||||
|
||||
private void onRegistrationFailed(Response response) {
|
||||
reset();
|
||||
int statusCode = response.getStatusCode();
|
||||
onRegistrationFailed(getErrorCode(statusCode),
|
||||
createErrorMessage(response));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -40,6 +40,7 @@ public abstract class Connection {
|
||||
MMI, /* not presently used; dial() returns null */
|
||||
INVALID_NUMBER, /* invalid dial string */
|
||||
INVALID_CREDENTIALS, /* invalid credentials */
|
||||
TIMED_OUT, /* client timed out */
|
||||
LOST_SIGNAL,
|
||||
LIMIT_EXCEEDED, /* eg GSM ACM limit exceeded */
|
||||
INCOMING_REJECTED, /* an incoming call that was rejected */
|
||||
|
@ -826,7 +826,8 @@ public class SipPhone extends SipPhoneBase {
|
||||
onError(Connection.DisconnectCause.INVALID_NUMBER);
|
||||
break;
|
||||
case TIME_OUT:
|
||||
onError(Connection.DisconnectCause.CONGESTION);
|
||||
case TRANSACTION_TERMINTED:
|
||||
onError(Connection.DisconnectCause.TIMED_OUT);
|
||||
break;
|
||||
case INVALID_CREDENTIALS:
|
||||
onError(Connection.DisconnectCause.INVALID_CREDENTIALS);
|
||||
|
@ -31,6 +31,9 @@ public enum SipErrorCode {
|
||||
/** When server responds with an error. */
|
||||
SERVER_ERROR,
|
||||
|
||||
/** When transaction is terminated unexpectedly. */
|
||||
TRANSACTION_TERMINTED,
|
||||
|
||||
/** When some error occurs on the device, possibly due to a bug. */
|
||||
CLIENT_ERROR,
|
||||
|
||||
@ -41,5 +44,8 @@ public enum SipErrorCode {
|
||||
INVALID_REMOTE_URI,
|
||||
|
||||
/** When invalid credentials are provided. */
|
||||
INVALID_CREDENTIALS;
|
||||
INVALID_CREDENTIALS,
|
||||
|
||||
/** The client is in a transaction and cannot initiate a new one. */
|
||||
IN_PROGRESS;
|
||||
}
|
||||
|
Reference in New Issue
Block a user