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

Commit ca3c24db authored by Hung-ying Tyan's avatar Hung-ying Tyan Committed by Android (Google) Code Review
Browse files

Merge "SIP: add SipErrorCode for error feedback." into gingerbread

parents 506d724c 903e1031
Loading
Loading
Loading
Loading
+115 −26
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@ import gov.nist.javax.sip.message.SIPMessage;
import android.net.sip.ISipSession;
import android.net.sip.ISipSessionListener;
import android.net.sip.SessionDescription;
import android.net.sip.SipErrorCode;
import android.net.sip.SipProfile;
import android.net.sip.SipSessionAdapter;
import android.net.sip.SipSessionState;
@@ -34,6 +35,7 @@ import android.util.Log;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.DatagramSocket;
import java.net.UnknownHostException;
import java.text.ParseException;
import java.util.Collection;
import java.util.EventObject;
@@ -60,6 +62,7 @@ import javax.sip.TimeoutEvent;
import javax.sip.Transaction;
import javax.sip.TransactionState;
import javax.sip.TransactionTerminatedEvent;
import javax.sip.TransactionUnavailableException;
import javax.sip.address.Address;
import javax.sip.address.SipURI;
import javax.sip.header.CSeqHeader;
@@ -77,6 +80,7 @@ import javax.sip.message.Response;
class SipSessionGroup implements SipListener {
    private static final String TAG = "SipSession";
    private static final String ANONYMOUS = "anonymous";
    private static final String SERVER_ERROR_PREFIX = "Response: ";
    private static final int EXPIRY_TIME = 3600;

    private static final EventObject DEREGISTER = new EventObject("Deregister");
@@ -282,7 +286,7 @@ class SipSessionGroup implements SipListener {
                Log.d(TAG, "event not processed: " + event);
            }
        } catch (Throwable e) {
            Log.e(TAG, "event process error: " + event, e);
            Log.w(TAG, "event process error: " + event, e);
            session.onError(e);
        }
    }
@@ -407,6 +411,7 @@ class SipSessionGroup implements SipListener {
                        try {
                            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)) {
@@ -603,7 +608,7 @@ class SipSessionGroup implements SipListener {
            case INCOMING_CALL:
            case INCOMING_CALL_ANSWERING:
            case OUTGOING_CALL_CANCELING:
                endCallOnError(new SipException("timed out"));
                endCallOnError(SipErrorCode.TIME_OUT, event.toString());
                break;
            case PINGING:
                reset();
@@ -691,15 +696,11 @@ class SipSessionGroup implements SipListener {
                    return true;
                case Response.UNAUTHORIZED:
                case Response.PROXY_AUTHENTICATION_REQUIRED:
                    String nonce = getNonceFromResponse(response);
                    if (((nonce != null) && nonce.equals(mLastNonce)) ||
                            (nonce == mLastNonce)) {
                    if (!handleAuthentication(event)) {
                        Log.v(TAG, "Incorrect username/password");
                        reset();
                        onRegistrationFailed(createCallbackException(response));
                    } else {
                        mSipHelper.handleChallenge(event, getAccountManager());
                        mLastNonce = nonce;
                        onRegistrationFailed(SipErrorCode.INVALID_CREDENTIALS,
                                "incorrect username or password");
                    }
                    return true;
                default:
@@ -713,6 +714,23 @@ class SipSessionGroup implements SipListener {
            return false;
        }

        private boolean handleAuthentication(ResponseEvent event)
                throws SipException {
            Response response = event.getResponse();
            String nonce = getNonceFromResponse(response);
            if (((nonce != null) && nonce.equals(mLastNonce)) ||
                    (nonce == mLastNonce)) {
                Log.v(TAG, "Incorrect username/password");
                return false;
            } else {
                mClientTransaction = mSipHelper.handleChallenge(
                        event, getAccountManager());
                mDialog = mClientTransaction.getDialog();
                mLastNonce = nonce;
                return true;
            }
        }

        private AccountManager getAccountManager() {
            return new AccountManager() {
                public UserCredentials getCredentials(ClientTransaction
@@ -833,14 +851,12 @@ class SipSessionGroup implements SipListener {
                    establishCall();
                    return true;
                case Response.PROXY_AUTHENTICATION_REQUIRED:
                    mClientTransaction = mSipHelper.handleChallenge(
                            (ResponseEvent) evt, getAccountManager());
                    mDialog = mClientTransaction.getDialog();
                    if (handleAuthentication(event)) {
                        addSipSession(this);
                    return true;
                case Response.BUSY_HERE:
                    reset();
                    mProxy.onCallBusy(this);
                    } else {
                        endCallOnError(SipErrorCode.INVALID_CREDENTIALS,
                                "incorrect username or password");
                    }
                    return true;
                case Response.REQUEST_PENDING:
                    // TODO:
@@ -849,7 +865,7 @@ class SipSessionGroup implements SipListener {
                default:
                    if (statusCode >= 400) {
                        // error: an ack is sent automatically by the stack
                        onError(createCallbackException(response));
                        onError(response);
                        return true;
                    } else if (statusCode >= 300) {
                        // TODO: handle 3xx (redirect)
@@ -933,9 +949,13 @@ class SipSessionGroup implements SipListener {
            return false;
        }

        private String createErrorMessage(Response response) {
            return String.format(SERVER_ERROR_PREFIX + "%s (%d)",
                    response.getReasonPhrase(), response.getStatusCode());
        }

        private Exception createCallbackException(Response response) {
            return new SipException(String.format("Response: %s (%d)",
                    response.getReasonPhrase(), response.getStatusCode()));
            return new SipException(createErrorMessage(response));
        }

        private void establishCall() {
@@ -946,8 +966,9 @@ class SipSessionGroup implements SipListener {

        private void fallbackToPreviousInCall(Throwable exception) {
            mState = SipSessionState.IN_CALL;
            mProxy.onCallChangeFailed(this, exception.getClass().getName(),
                    exception.getMessage());
            exception = getRootCause(exception);
            mProxy.onCallChangeFailed(this, getErrorCode(exception).toString(),
                    exception.toString());
        }

        private void endCallNormally() {
@@ -956,9 +977,18 @@ class SipSessionGroup implements SipListener {
        }

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

        private void endCallOnBusy() {
            reset();
            mProxy.onError(this, exception.getClass().getName(),
                    exception.getMessage());
            mProxy.onCallBusy(this);
        }

        private void onError(Throwable exception) {
@@ -969,13 +999,72 @@ class SipSessionGroup implements SipListener {
            }
        }

        private void onError(Response response) {
            if (mInCall) {
                fallbackToPreviousInCall(createCallbackException(response));
            } else {
                int statusCode = response.getStatusCode();
                if ((statusCode == Response.TEMPORARILY_UNAVAILABLE)
                        || (statusCode == Response.BUSY_HERE)) {
                    endCallOnBusy();
                } else {
                    endCallOnError(getErrorCode(statusCode),
                            createErrorMessage(response));
                }
            }
        }

        private SipErrorCode getErrorCode(int responseStatusCode) {
            switch (responseStatusCode) {
                case Response.NOT_FOUND:
                case Response.ADDRESS_INCOMPLETE:
                    return SipErrorCode.INVALID_REMOTE_URI;
                case Response.REQUEST_TIMEOUT:
                    return SipErrorCode.TIME_OUT;
                default:
                    if (responseStatusCode < 500) {
                        return SipErrorCode.CLIENT_ERROR;
                    } else {
                        return SipErrorCode.SERVER_ERROR;
                    }
            }
        }

        private Throwable getRootCause(Throwable exception) {
            Throwable cause = exception.getCause();
            while (cause != null) {
                exception = cause;
                cause = exception.getCause();
            }
            return exception;
        }

        private SipErrorCode getErrorCode(Throwable exception) {
            String message = exception.getMessage();
            if (exception instanceof UnknownHostException) {
                return SipErrorCode.INVALID_REMOTE_URI;
            } else if (exception instanceof IOException) {
                return SipErrorCode.SOCKET_ERROR;
            } else if (message.startsWith(SERVER_ERROR_PREFIX)) {
                return SipErrorCode.SERVER_ERROR;
            } else {
                return SipErrorCode.CLIENT_ERROR;
            }
        }

        private void onRegistrationDone(int duration) {
            mProxy.onRegistrationDone(this, duration);
        }

        private void onRegistrationFailed(SipErrorCode errorCode,
                String message) {
            mProxy.onRegistrationFailed(this, errorCode.toString(), message);
        }

        private void onRegistrationFailed(Throwable exception) {
            mProxy.onRegistrationFailed(this, exception.getClass().getName(),
                    exception.getMessage());
            exception = getRootCause(exception);
            onRegistrationFailed(getErrorCode(exception),
                    exception.toString());
        }
    }

+6 −6
Original line number Diff line number Diff line
@@ -124,12 +124,12 @@ class SipSessionListenerProxy extends ISipSessionListener.Stub {
    }

    public void onCallChangeFailed(final ISipSession session,
            final String className, final String message) {
            final String errorCode, final String message) {
        if (mListener == null) return;
        proxy(new Runnable() {
            public void run() {
                try {
                    mListener.onCallChangeFailed(session, className, message);
                    mListener.onCallChangeFailed(session, errorCode, message);
                } catch (Throwable t) {
                    handle(t, "onCallChangeFailed()");
                }
@@ -137,13 +137,13 @@ class SipSessionListenerProxy extends ISipSessionListener.Stub {
        });
    }

    public void onError(final ISipSession session, final String className,
    public void onError(final ISipSession session, final String errorCode,
            final String message) {
        if (mListener == null) return;
        proxy(new Runnable() {
            public void run() {
                try {
                    mListener.onError(session, className, message);
                    mListener.onError(session, errorCode, message);
                } catch (Throwable t) {
                    handle(t, "onError()");
                }
@@ -179,12 +179,12 @@ class SipSessionListenerProxy extends ISipSessionListener.Stub {
    }

    public void onRegistrationFailed(final ISipSession session,
            final String className, final String message) {
            final String errorCode, final String message) {
        if (mListener == null) return;
        proxy(new Runnable() {
            public void run() {
                try {
                    mListener.onRegistrationFailed(session, className, message);
                    mListener.onRegistrationFailed(session, errorCode, message);
                } catch (Throwable t) {
                    handle(t, "onRegistrationFailed()");
                }
+1 −0
Original line number Diff line number Diff line
@@ -39,6 +39,7 @@ public abstract class Connection {
        CONGESTION,                     /* outgoing call to congested network */
        MMI,                            /* not presently used; dial() returns null */
        INVALID_NUMBER,                 /* invalid dial string */
        INVALID_CREDENTIALS,            /* invalid credentials */
        LOST_SIGNAL,
        LIMIT_EXCEEDED,                 /* eg GSM ACM limit exceeded */
        INCOMING_REJECTED,              /* an incoming call that was rejected */
+23 −7
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@ import android.net.Uri;
import android.net.rtp.AudioGroup;
import android.net.rtp.AudioStream;
import android.net.sip.SipAudioCall;
import android.net.sip.SipErrorCode;
import android.net.sip.SipManager;
import android.net.sip.SipProfile;
import android.net.sip.SipSessionState;
@@ -633,16 +634,15 @@ public class SipPhone extends SipPhoneBase {
            }

            @Override
            protected void onError(String errorMessage) {
                Log.w(LOG_TAG, "SIP error: " + errorMessage);
            protected void onError(DisconnectCause cause) {
                Log.w(LOG_TAG, "SIP error: " + cause);
                if (mSipAudioCall.isInCall()) {
                    // Don't end the call when in call.
                    // TODO: how to deliver the error to PhoneApp
                    return;
                }

                // FIXME: specify error
                onCallEnded(DisconnectCause.ERROR_UNSPECIFIED);
                onCallEnded(cause);
            }
        };

@@ -807,7 +807,7 @@ public class SipPhone extends SipPhoneBase {

    private abstract class SipAudioCallAdapter extends SipAudioCall.Adapter {
        protected abstract void onCallEnded(Connection.DisconnectCause cause);
        protected abstract void onError(String errorMessage);
        protected abstract void onError(Connection.DisconnectCause cause);

        @Override
        public void onCallEnded(SipAudioCall call) {
@@ -820,8 +820,24 @@ public class SipPhone extends SipPhoneBase {
        }

        @Override
        public void onError(SipAudioCall call, String errorMessage) {
            onError(errorMessage);
        public void onError(SipAudioCall call, String errorCode,
                String errorMessage) {
            switch (Enum.valueOf(SipErrorCode.class, errorCode)) {
                case INVALID_REMOTE_URI:
                    onError(Connection.DisconnectCause.INVALID_NUMBER);
                    break;
                case TIME_OUT:
                    onError(Connection.DisconnectCause.CONGESTION);
                    break;
                case INVALID_CREDENTIALS:
                    onError(Connection.DisconnectCause.INVALID_CREDENTIALS);
                    break;
                case SOCKET_ERROR:
                case SERVER_ERROR:
                case CLIENT_ERROR:
                default:
                    onError(Connection.DisconnectCause.ERROR_UNSPECIFIED);
            }
        }
    }
}
+6 −6
Original line number Diff line number Diff line
@@ -76,20 +76,20 @@ interface ISipSessionListener {
     * termination.
     *
     * @param session the session object that carries out the transaction
     * @param errorClass name of the exception class
     * @param errorCode error code defined in {@link SipErrorCode}
     * @param errorMessage error message
     */
    void onError(in ISipSession session, String errorClass,
    void onError(in ISipSession session, String errorCode,
            String errorMessage);

    /**
     * Called when an error occurs during session modification negotiation.
     *
     * @param session the session object that carries out the transaction
     * @param errorClass name of the exception class
     * @param errorCode error code defined in {@link SipErrorCode}
     * @param errorMessage error message
     */
    void onCallChangeFailed(in ISipSession session, String errorClass,
    void onCallChangeFailed(in ISipSession session, String errorCode,
            String errorMessage);

    /**
@@ -111,10 +111,10 @@ interface ISipSessionListener {
     * Called when the registration fails.
     *
     * @param session the session object that carries out the transaction
     * @param errorClass name of the exception class
     * @param errorCode error code defined in {@link SipErrorCode}
     * @param errorMessage error message
     */
    void onRegistrationFailed(in ISipSession session, String errorClass,
    void onRegistrationFailed(in ISipSession session, String errorCode,
            String errorMessage);

    /**
Loading