Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3d7606aa authored by Hung-ying Tyan's avatar Hung-ying Tyan
Browse files

SIP: enhance timeout and registration status feedback.

http://b/issue?id=2984419
http://b/issue?id=2991065

Change-Id: I2d3b1dd3a70079ff347f7256f4684aea07847f4e
parent 25b52a2f
Loading
Loading
Loading
Loading
+64 −39
Original line number Diff line number Diff line
@@ -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,16 +554,26 @@ 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;
            }
            if (!keepStates) {
                mSession = null;
                mRegistered = false;
            }
        }

        private boolean isStopped() {
            return (mSession == null);
@@ -568,28 +581,43 @@ public final class SipService extends ISipService.Stub {

        public void setListener(ISipSessionListener listener) {
            Log.v(TAG, "setListener(): " + listener);
            synchronized (SipService.this) {
                mProxy.setListener(listener);
                if (mSession == null) return;

                try {
                if ((mSession != null) && SipSessionState.REGISTERING.equals(
                        mSession.getState())) {
                    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);
                }
            }
        }

        public boolean isRegistered() {
            return mRegistered;
        }

        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);
                }
            }
        }

@@ -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);
                }

                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 (errorCode == SipErrorCode.INVALID_CREDENTIALS) {
                    Log.d(TAG, "   pause auto-registration");
                    stopButKeepStates();
                } else if (!isStopped()) {
                    onError();
                }

                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 {
                mErrorCode = SipErrorCode.TIME_OUT;
                mProxy.onRegistrationTimeout(session);
                } catch (Throwable t) {
                    Log.w(TAG, "onRegistrationTimeout(): " + t);
                }

                if (!isStopped()) {
                    mRegistered = false;
+82 −64
Original line number Diff line number Diff line
@@ -412,15 +412,9 @@ 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);
                        }
                    }
                    }
            }).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()
@@ -607,8 +614,9 @@ class SipSessionGroup implements SipListener {
                    break;
                case INCOMING_CALL:
                case INCOMING_CALL_ANSWERING:
                case OUTGOING_CALL:
                case OUTGOING_CALL_CANCELING:
                endCallOnError(SipErrorCode.TIME_OUT, event.toString());
                    onError(SipErrorCode.TIME_OUT, event.toString());
                    break;
                case PINGING:
                    reset();
@@ -617,7 +625,7 @@ class SipSessionGroup implements SipListener {
                    break;

                default:
                // do nothing
                    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) {
        private void onError(SipErrorCode errorCode, String message) {
            switch (mState) {
                case REGISTERING:
                case DEREGISTERING:
                    onRegistrationFailed(errorCode, message);
                    break;
                default:
                    if (mInCall) {
                fallbackToPreviousInCall(exception);
                        fallbackToPreviousInCall(errorCode, message);
                    } else {
                endCallOnError(exception);
                        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));
            } else {
            int statusCode = response.getStatusCode();
                if ((statusCode == Response.TEMPORARILY_UNAVAILABLE)
                        || (statusCode == Response.BUSY_HERE)) {
            if (!mInCall && ((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));
        }
    }

    /**
+1 −0
Original line number Diff line number Diff line
@@ -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 */
+2 −1
Original line number Diff line number Diff line
@@ -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);
+7 −1
Original line number Diff line number Diff line
@@ -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;
}