summaryrefslogtreecommitdiffstats
path: root/services
diff options
context:
space:
mode:
authorHung-ying Tyan <tyanh@google.com>2010-09-27 16:25:49 -0700
committerAndroid (Google) Code Review <android-gerrit@google.com>2010-09-27 16:25:49 -0700
commit68ef7f3c3a8deb0e14b0b6325876b23cecc191b3 (patch)
tree994adc214fa6eb5e54909e3de5d242494334b8d5 /services
parent8d7057df401af668335c38273bc62872e4dbf538 (diff)
parent7e54ef71db3320a751571bba5259fba816399421 (diff)
downloadframeworks_base-68ef7f3c3a8deb0e14b0b6325876b23cecc191b3.zip
frameworks_base-68ef7f3c3a8deb0e14b0b6325876b23cecc191b3.tar.gz
frameworks_base-68ef7f3c3a8deb0e14b0b6325876b23cecc191b3.tar.bz2
Merge "Move SipService out of SystemServer to phone process." into gingerbread
Diffstat (limited to 'services')
-rw-r--r--services/java/com/android/server/SystemServer.java11
-rw-r--r--services/java/com/android/server/sip/SipHelper.java464
-rw-r--r--services/java/com/android/server/sip/SipService.java1231
-rw-r--r--services/java/com/android/server/sip/SipSessionGroup.java1393
-rw-r--r--services/java/com/android/server/sip/SipSessionListenerProxy.java217
5 files changed, 0 insertions, 3316 deletions
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 9475005..a80ab1d 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -17,7 +17,6 @@
package com.android.server;
import com.android.server.am.ActivityManagerService;
-import com.android.server.sip.SipService;
import com.android.internal.os.BinderInternal;
import com.android.internal.os.SamplingProfilerIntegration;
@@ -417,16 +416,6 @@ class ServerThread extends Thread {
} catch (Throwable e) {
Slog.e(TAG, "Failure starting DiskStats Service", e);
}
-
- try {
- SipService sipService = SipService.create(context);
- if (sipService != null) {
- Slog.i(TAG, "Sip Service");
- ServiceManager.addService("sip", sipService);
- }
- } catch (Throwable e) {
- Slog.e(TAG, "Failure starting SIP Service", e);
- }
}
// make sure the ADB_ENABLED setting value matches the secure property value
diff --git a/services/java/com/android/server/sip/SipHelper.java b/services/java/com/android/server/sip/SipHelper.java
deleted file mode 100644
index 050eddc..0000000
--- a/services/java/com/android/server/sip/SipHelper.java
+++ /dev/null
@@ -1,464 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.sip;
-
-import gov.nist.javax.sip.SipStackExt;
-import gov.nist.javax.sip.clientauthutils.AccountManager;
-import gov.nist.javax.sip.clientauthutils.AuthenticationHelper;
-
-import android.net.sip.SipProfile;
-import android.util.Log;
-
-import java.text.ParseException;
-import java.util.ArrayList;
-import java.util.EventObject;
-import java.util.List;
-import javax.sip.ClientTransaction;
-import javax.sip.Dialog;
-import javax.sip.DialogTerminatedEvent;
-import javax.sip.InvalidArgumentException;
-import javax.sip.ListeningPoint;
-import javax.sip.PeerUnavailableException;
-import javax.sip.RequestEvent;
-import javax.sip.ResponseEvent;
-import javax.sip.ServerTransaction;
-import javax.sip.SipException;
-import javax.sip.SipFactory;
-import javax.sip.SipProvider;
-import javax.sip.SipStack;
-import javax.sip.Transaction;
-import javax.sip.TransactionAlreadyExistsException;
-import javax.sip.TransactionTerminatedEvent;
-import javax.sip.TransactionUnavailableException;
-import javax.sip.TransactionState;
-import javax.sip.address.Address;
-import javax.sip.address.AddressFactory;
-import javax.sip.address.SipURI;
-import javax.sip.header.CSeqHeader;
-import javax.sip.header.CallIdHeader;
-import javax.sip.header.ContactHeader;
-import javax.sip.header.FromHeader;
-import javax.sip.header.Header;
-import javax.sip.header.HeaderFactory;
-import javax.sip.header.MaxForwardsHeader;
-import javax.sip.header.ToHeader;
-import javax.sip.header.ViaHeader;
-import javax.sip.message.Message;
-import javax.sip.message.MessageFactory;
-import javax.sip.message.Request;
-import javax.sip.message.Response;
-
-/**
- * Helper class for holding SIP stack related classes and for various low-level
- * SIP tasks like sending messages.
- */
-class SipHelper {
- private static final String TAG = SipHelper.class.getSimpleName();
- private static final boolean DEBUG = true;
-
- private SipStack mSipStack;
- private SipProvider mSipProvider;
- private AddressFactory mAddressFactory;
- private HeaderFactory mHeaderFactory;
- private MessageFactory mMessageFactory;
-
- public SipHelper(SipStack sipStack, SipProvider sipProvider)
- throws PeerUnavailableException {
- mSipStack = sipStack;
- mSipProvider = sipProvider;
-
- SipFactory sipFactory = SipFactory.getInstance();
- mAddressFactory = sipFactory.createAddressFactory();
- mHeaderFactory = sipFactory.createHeaderFactory();
- mMessageFactory = sipFactory.createMessageFactory();
- }
-
- private FromHeader createFromHeader(SipProfile profile, String tag)
- throws ParseException {
- return mHeaderFactory.createFromHeader(profile.getSipAddress(), tag);
- }
-
- private ToHeader createToHeader(SipProfile profile) throws ParseException {
- return createToHeader(profile, null);
- }
-
- private ToHeader createToHeader(SipProfile profile, String tag)
- throws ParseException {
- return mHeaderFactory.createToHeader(profile.getSipAddress(), tag);
- }
-
- private CallIdHeader createCallIdHeader() {
- return mSipProvider.getNewCallId();
- }
-
- private CSeqHeader createCSeqHeader(String method)
- throws ParseException, InvalidArgumentException {
- long sequence = (long) (Math.random() * 10000);
- return mHeaderFactory.createCSeqHeader(sequence, method);
- }
-
- private MaxForwardsHeader createMaxForwardsHeader()
- throws InvalidArgumentException {
- return mHeaderFactory.createMaxForwardsHeader(70);
- }
-
- private MaxForwardsHeader createMaxForwardsHeader(int max)
- throws InvalidArgumentException {
- return mHeaderFactory.createMaxForwardsHeader(max);
- }
-
- private ListeningPoint getListeningPoint() throws SipException {
- ListeningPoint lp = mSipProvider.getListeningPoint(ListeningPoint.UDP);
- if (lp == null) lp = mSipProvider.getListeningPoint(ListeningPoint.TCP);
- if (lp == null) {
- ListeningPoint[] lps = mSipProvider.getListeningPoints();
- if ((lps != null) && (lps.length > 0)) lp = lps[0];
- }
- if (lp == null) {
- throw new SipException("no listening point is available");
- }
- return lp;
- }
-
- private List<ViaHeader> createViaHeaders()
- throws ParseException, SipException {
- List<ViaHeader> viaHeaders = new ArrayList<ViaHeader>(1);
- ListeningPoint lp = getListeningPoint();
- ViaHeader viaHeader = mHeaderFactory.createViaHeader(lp.getIPAddress(),
- lp.getPort(), lp.getTransport(), null);
- viaHeader.setRPort();
- viaHeaders.add(viaHeader);
- return viaHeaders;
- }
-
- private ContactHeader createContactHeader(SipProfile profile)
- throws ParseException, SipException {
- ListeningPoint lp = getListeningPoint();
- SipURI contactURI =
- createSipUri(profile.getUserName(), profile.getProtocol(), lp);
-
- Address contactAddress = mAddressFactory.createAddress(contactURI);
- contactAddress.setDisplayName(profile.getDisplayName());
-
- return mHeaderFactory.createContactHeader(contactAddress);
- }
-
- private ContactHeader createWildcardContactHeader() {
- ContactHeader contactHeader = mHeaderFactory.createContactHeader();
- contactHeader.setWildCard();
- return contactHeader;
- }
-
- private SipURI createSipUri(String username, String transport,
- ListeningPoint lp) throws ParseException {
- SipURI uri = mAddressFactory.createSipURI(username, lp.getIPAddress());
- try {
- uri.setPort(lp.getPort());
- uri.setTransportParam(transport);
- } catch (InvalidArgumentException e) {
- throw new RuntimeException(e);
- }
- return uri;
- }
-
- public ClientTransaction sendKeepAlive(SipProfile userProfile, String tag)
- throws SipException {
- try {
- Request request = createRequest(Request.OPTIONS, userProfile, tag);
-
- ClientTransaction clientTransaction =
- mSipProvider.getNewClientTransaction(request);
- clientTransaction.sendRequest();
- return clientTransaction;
- } catch (Exception e) {
- throw new SipException("sendKeepAlive()", e);
- }
- }
-
- public ClientTransaction sendRegister(SipProfile userProfile, String tag,
- int expiry) throws SipException {
- try {
- Request request = createRequest(Request.REGISTER, userProfile, tag);
- if (expiry == 0) {
- // remove all previous registrations by wildcard
- // rfc3261#section-10.2.2
- request.addHeader(createWildcardContactHeader());
- } else {
- request.addHeader(createContactHeader(userProfile));
- }
- request.addHeader(mHeaderFactory.createExpiresHeader(expiry));
-
- ClientTransaction clientTransaction =
- mSipProvider.getNewClientTransaction(request);
- clientTransaction.sendRequest();
- return clientTransaction;
- } catch (ParseException e) {
- throw new SipException("sendRegister()", e);
- }
- }
-
- private Request createRequest(String requestType, SipProfile userProfile,
- String tag) throws ParseException, SipException {
- FromHeader fromHeader = createFromHeader(userProfile, tag);
- ToHeader toHeader = createToHeader(userProfile);
- SipURI requestURI = mAddressFactory.createSipURI("sip:"
- + userProfile.getSipDomain());
- List<ViaHeader> viaHeaders = createViaHeaders();
- CallIdHeader callIdHeader = createCallIdHeader();
- CSeqHeader cSeqHeader = createCSeqHeader(requestType);
- MaxForwardsHeader maxForwards = createMaxForwardsHeader();
- Request request = mMessageFactory.createRequest(requestURI,
- requestType, callIdHeader, cSeqHeader, fromHeader,
- toHeader, viaHeaders, maxForwards);
- Header userAgentHeader = mHeaderFactory.createHeader("User-Agent",
- "SIPAUA/0.1.001");
- request.addHeader(userAgentHeader);
- return request;
- }
-
- public ClientTransaction handleChallenge(ResponseEvent responseEvent,
- AccountManager accountManager) throws SipException {
- AuthenticationHelper authenticationHelper =
- ((SipStackExt) mSipStack).getAuthenticationHelper(
- accountManager, mHeaderFactory);
- ClientTransaction tid = responseEvent.getClientTransaction();
- ClientTransaction ct = authenticationHelper.handleChallenge(
- responseEvent.getResponse(), tid, mSipProvider, 5);
- ct.sendRequest();
- return ct;
- }
-
- public ClientTransaction sendInvite(SipProfile caller, SipProfile callee,
- String sessionDescription, String tag)
- throws SipException {
- try {
- FromHeader fromHeader = createFromHeader(caller, tag);
- ToHeader toHeader = createToHeader(callee);
- SipURI requestURI = callee.getUri();
- List<ViaHeader> viaHeaders = createViaHeaders();
- CallIdHeader callIdHeader = createCallIdHeader();
- CSeqHeader cSeqHeader = createCSeqHeader(Request.INVITE);
- MaxForwardsHeader maxForwards = createMaxForwardsHeader();
-
- Request request = mMessageFactory.createRequest(requestURI,
- Request.INVITE, callIdHeader, cSeqHeader, fromHeader,
- toHeader, viaHeaders, maxForwards);
-
- request.addHeader(createContactHeader(caller));
- request.setContent(sessionDescription,
- mHeaderFactory.createContentTypeHeader(
- "application", "sdp"));
-
- ClientTransaction clientTransaction =
- mSipProvider.getNewClientTransaction(request);
- if (DEBUG) Log.d(TAG, "send INVITE: " + request);
- clientTransaction.sendRequest();
- return clientTransaction;
- } catch (ParseException e) {
- throw new SipException("sendInvite()", e);
- }
- }
-
- public ClientTransaction sendReinvite(Dialog dialog,
- String sessionDescription) throws SipException {
- try {
- Request request = dialog.createRequest(Request.INVITE);
- request.setContent(sessionDescription,
- mHeaderFactory.createContentTypeHeader(
- "application", "sdp"));
-
- ClientTransaction clientTransaction =
- mSipProvider.getNewClientTransaction(request);
- if (DEBUG) Log.d(TAG, "send RE-INVITE: " + request);
- dialog.sendRequest(clientTransaction);
- return clientTransaction;
- } catch (ParseException e) {
- throw new SipException("sendReinvite()", e);
- }
- }
-
- private ServerTransaction getServerTransaction(RequestEvent event)
- throws SipException {
- ServerTransaction transaction = event.getServerTransaction();
- if (transaction == null) {
- Request request = event.getRequest();
- return mSipProvider.getNewServerTransaction(request);
- } else {
- return transaction;
- }
- }
-
- /**
- * @param event the INVITE request event
- */
- public ServerTransaction sendRinging(RequestEvent event, String tag)
- throws SipException {
- try {
- Request request = event.getRequest();
- ServerTransaction transaction = getServerTransaction(event);
-
- Response response = mMessageFactory.createResponse(Response.RINGING,
- request);
-
- ToHeader toHeader = (ToHeader) response.getHeader(ToHeader.NAME);
- toHeader.setTag(tag);
- response.addHeader(toHeader);
- if (DEBUG) Log.d(TAG, "send RINGING: " + response);
- transaction.sendResponse(response);
- return transaction;
- } catch (ParseException e) {
- throw new SipException("sendRinging()", e);
- }
- }
-
- /**
- * @param event the INVITE request event
- */
- public ServerTransaction sendInviteOk(RequestEvent event,
- SipProfile localProfile, String sessionDescription,
- ServerTransaction inviteTransaction)
- throws SipException {
- try {
- Request request = event.getRequest();
- Response response = mMessageFactory.createResponse(Response.OK,
- request);
- response.addHeader(createContactHeader(localProfile));
- response.setContent(sessionDescription,
- mHeaderFactory.createContentTypeHeader(
- "application", "sdp"));
-
- if (inviteTransaction == null) {
- inviteTransaction = getServerTransaction(event);
- }
-
- if (inviteTransaction.getState() != TransactionState.COMPLETED) {
- if (DEBUG) Log.d(TAG, "send OK: " + response);
- inviteTransaction.sendResponse(response);
- }
-
- return inviteTransaction;
- } catch (ParseException e) {
- throw new SipException("sendInviteOk()", e);
- }
- }
-
- public void sendInviteBusyHere(RequestEvent event,
- ServerTransaction inviteTransaction) throws SipException {
- try {
- Request request = event.getRequest();
- Response response = mMessageFactory.createResponse(
- Response.BUSY_HERE, request);
-
- if (inviteTransaction.getState() != TransactionState.COMPLETED) {
- if (DEBUG) Log.d(TAG, "send BUSY HERE: " + response);
- inviteTransaction.sendResponse(response);
- }
- } catch (ParseException e) {
- throw new SipException("sendInviteBusyHere()", e);
- }
- }
-
- /**
- * @param event the INVITE ACK request event
- */
- public void sendInviteAck(ResponseEvent event, Dialog dialog)
- throws SipException {
- Response response = event.getResponse();
- long cseq = ((CSeqHeader) response.getHeader(CSeqHeader.NAME))
- .getSeqNumber();
- Request ack = dialog.createAck(cseq);
- if (DEBUG) Log.d(TAG, "send ACK: " + ack);
- dialog.sendAck(ack);
- }
-
- public void sendBye(Dialog dialog) throws SipException {
- Request byeRequest = dialog.createRequest(Request.BYE);
- if (DEBUG) Log.d(TAG, "send BYE: " + byeRequest);
- dialog.sendRequest(mSipProvider.getNewClientTransaction(byeRequest));
- }
-
- public void sendCancel(ClientTransaction inviteTransaction)
- throws SipException {
- Request cancelRequest = inviteTransaction.createCancel();
- if (DEBUG) Log.d(TAG, "send CANCEL: " + cancelRequest);
- mSipProvider.getNewClientTransaction(cancelRequest).sendRequest();
- }
-
- public void sendResponse(RequestEvent event, int responseCode)
- throws SipException {
- try {
- Response response = mMessageFactory.createResponse(
- responseCode, event.getRequest());
- if (DEBUG) Log.d(TAG, "send response: " + response);
- getServerTransaction(event).sendResponse(response);
- } catch (ParseException e) {
- throw new SipException("sendResponse()", e);
- }
- }
-
- public void sendInviteRequestTerminated(Request inviteRequest,
- ServerTransaction inviteTransaction) throws SipException {
- try {
- Response response = mMessageFactory.createResponse(
- Response.REQUEST_TERMINATED, inviteRequest);
- if (DEBUG) Log.d(TAG, "send response: " + response);
- inviteTransaction.sendResponse(response);
- } catch (ParseException e) {
- throw new SipException("sendInviteRequestTerminated()", e);
- }
- }
-
- public static String getCallId(EventObject event) {
- if (event == null) return null;
- if (event instanceof RequestEvent) {
- return getCallId(((RequestEvent) event).getRequest());
- } else if (event instanceof ResponseEvent) {
- return getCallId(((ResponseEvent) event).getResponse());
- } else if (event instanceof DialogTerminatedEvent) {
- Dialog dialog = ((DialogTerminatedEvent) event).getDialog();
- return getCallId(((DialogTerminatedEvent) event).getDialog());
- } else if (event instanceof TransactionTerminatedEvent) {
- TransactionTerminatedEvent e = (TransactionTerminatedEvent) event;
- return getCallId(e.isServerTransaction()
- ? e.getServerTransaction()
- : e.getClientTransaction());
- } else {
- Object source = event.getSource();
- if (source instanceof Transaction) {
- return getCallId(((Transaction) source));
- } else if (source instanceof Dialog) {
- return getCallId((Dialog) source);
- }
- }
- return "";
- }
-
- public static String getCallId(Transaction transaction) {
- return ((transaction != null) ? getCallId(transaction.getRequest())
- : "");
- }
-
- private static String getCallId(Message message) {
- CallIdHeader callIdHeader =
- (CallIdHeader) message.getHeader(CallIdHeader.NAME);
- return callIdHeader.getCallId();
- }
-
- private static String getCallId(Dialog dialog) {
- return dialog.getCallId().getCallId();
- }
-}
diff --git a/services/java/com/android/server/sip/SipService.java b/services/java/com/android/server/sip/SipService.java
deleted file mode 100644
index 3f43e1c..0000000
--- a/services/java/com/android/server/sip/SipService.java
+++ /dev/null
@@ -1,1231 +0,0 @@
-/*
- * Copyright (C) 2010, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.sip;
-
-import android.app.AlarmManager;
-import android.app.PendingIntent;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.net.ConnectivityManager;
-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.SipSession;
-import android.net.sip.SipSessionAdapter;
-import android.net.wifi.WifiManager;
-import android.os.Binder;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.HandlerThread;
-import android.os.Looper;
-import android.os.Message;
-import android.os.RemoteException;
-import android.os.SystemClock;
-import android.text.TextUtils;
-import android.util.Log;
-
-import java.io.IOException;
-import java.net.DatagramSocket;
-import java.net.InetAddress;
-import java.net.UnknownHostException;
-import java.util.Collection;
-import java.util.Comparator;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.Timer;
-import java.util.TimerTask;
-import java.util.TreeSet;
-import javax.sip.SipException;
-
-/**
- * @hide
- */
-public final class SipService extends ISipService.Stub {
- private static final String TAG = "SipService";
- private static final boolean DEBUG = true;
- private static final boolean DEBUG_TIMER = DEBUG && false;
- private static final int EXPIRY_TIME = 3600;
- private static final int SHORT_EXPIRY_TIME = 10;
- private static final int MIN_EXPIRY_TIME = 60;
-
- private Context mContext;
- private String mLocalIp;
- private String mNetworkType;
- private boolean mConnected;
- private WakeupTimer mTimer;
- private WifiManager.WifiLock mWifiLock;
- private boolean mWifiOnly;
-
- private MyExecutor mExecutor;
-
- // SipProfile URI --> group
- private Map<String, SipSessionGroupExt> mSipGroups =
- new HashMap<String, SipSessionGroupExt>();
-
- // session ID --> session
- private Map<String, ISipSession> mPendingSessions =
- new HashMap<String, ISipSession>();
-
- private ConnectivityReceiver mConnectivityReceiver;
-
- /**
- * Creates a {@code SipService} instance. Returns null if SIP API is not
- * supported.
- */
- public static SipService create(Context context) {
- return (SipManager.isApiSupported(context) ? new SipService(context)
- : null);
- }
-
- private SipService(Context context) {
- if (DEBUG) Log.d(TAG, " service started!");
- mContext = context;
- mConnectivityReceiver = new ConnectivityReceiver();
- context.registerReceiver(mConnectivityReceiver,
- new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));
-
- mTimer = new WakeupTimer(context);
- mWifiOnly = SipManager.isSipWifiOnly(context);
- }
-
- private MyExecutor getExecutor() {
- // create mExecutor lazily
- if (mExecutor == null) mExecutor = new MyExecutor();
- return mExecutor;
- }
-
- public synchronized SipProfile[] getListOfProfiles() {
- SipProfile[] profiles = new SipProfile[mSipGroups.size()];
- int i = 0;
- for (SipSessionGroupExt group : mSipGroups.values()) {
- profiles[i++] = group.getLocalProfile();
- }
- return profiles;
- }
-
- public void open(SipProfile localProfile) {
- localProfile.setCallingUid(Binder.getCallingUid());
- if (localProfile.getAutoRegistration()) {
- openToReceiveCalls(localProfile);
- } else {
- openToMakeCalls(localProfile);
- }
- }
-
- private void openToMakeCalls(SipProfile localProfile) {
- try {
- createGroup(localProfile);
- } catch (SipException e) {
- Log.e(TAG, "openToMakeCalls()", e);
- // TODO: how to send the exception back
- }
- }
-
- private void openToReceiveCalls(SipProfile localProfile) {
- open3(localProfile, SipManager.ACTION_SIP_INCOMING_CALL, null);
- }
-
- public synchronized void open3(SipProfile localProfile,
- String incomingCallBroadcastAction, ISipSessionListener listener) {
- localProfile.setCallingUid(Binder.getCallingUid());
- if (TextUtils.isEmpty(incomingCallBroadcastAction)) {
- throw new RuntimeException(
- "empty broadcast action for incoming call");
- }
- if (DEBUG) Log.d(TAG, "open3: " + localProfile.getUriString() + ": "
- + incomingCallBroadcastAction + ": " + listener);
- try {
- SipSessionGroupExt group = createGroup(localProfile,
- incomingCallBroadcastAction, listener);
- if (localProfile.getAutoRegistration()) {
- group.openToReceiveCalls();
- if (isWifiOn()) grabWifiLock();
- }
- } catch (SipException e) {
- Log.e(TAG, "openToReceiveCalls()", e);
- // TODO: how to send the exception back
- }
- }
-
- public synchronized void close(String localProfileUri) {
- SipSessionGroupExt group = mSipGroups.remove(localProfileUri);
- if (group != null) {
- notifyProfileRemoved(group.getLocalProfile());
- group.close();
- if (isWifiOn() && !anyOpened()) releaseWifiLock();
- }
- }
-
- public synchronized boolean isOpened(String localProfileUri) {
- SipSessionGroupExt group = mSipGroups.get(localProfileUri);
- return ((group != null) ? group.isOpened() : false);
- }
-
- public synchronized boolean isRegistered(String localProfileUri) {
- SipSessionGroupExt group = mSipGroups.get(localProfileUri);
- return ((group != null) ? group.isRegistered() : false);
- }
-
- public synchronized void setRegistrationListener(String localProfileUri,
- ISipSessionListener listener) {
- SipSessionGroupExt group = mSipGroups.get(localProfileUri);
- if (group != null) group.setListener(listener);
- }
-
- public synchronized ISipSession createSession(SipProfile localProfile,
- ISipSessionListener listener) {
- localProfile.setCallingUid(Binder.getCallingUid());
- if (!mConnected) return null;
- try {
- SipSessionGroupExt group = createGroup(localProfile);
- return group.createSession(listener);
- } catch (SipException e) {
- Log.w(TAG, "createSession()", e);
- return null;
- }
- }
-
- public synchronized ISipSession getPendingSession(String callId) {
- if (callId == null) return null;
- return mPendingSessions.get(callId);
- }
-
- private String determineLocalIp() {
- try {
- DatagramSocket s = new DatagramSocket();
- s.connect(InetAddress.getByName("192.168.1.1"), 80);
- return s.getLocalAddress().getHostAddress();
- } catch (IOException e) {
- Log.w(TAG, "determineLocalIp()", e);
- // dont do anything; there should be a connectivity change going
- return null;
- }
- }
-
- private SipSessionGroupExt createGroup(SipProfile localProfile)
- throws SipException {
- String key = localProfile.getUriString();
- SipSessionGroupExt group = mSipGroups.get(key);
- if (group == null) {
- group = new SipSessionGroupExt(localProfile, null, null);
- mSipGroups.put(key, group);
- notifyProfileAdded(localProfile);
- }
- return group;
- }
-
- private SipSessionGroupExt createGroup(SipProfile localProfile,
- String incomingCallBroadcastAction, ISipSessionListener listener)
- throws SipException {
- String key = localProfile.getUriString();
- SipSessionGroupExt group = mSipGroups.get(key);
- if (group != null) {
- group.setIncomingCallBroadcastAction(
- incomingCallBroadcastAction);
- group.setListener(listener);
- } else {
- group = new SipSessionGroupExt(localProfile,
- incomingCallBroadcastAction, listener);
- mSipGroups.put(key, group);
- notifyProfileAdded(localProfile);
- }
- return group;
- }
-
- private void notifyProfileAdded(SipProfile localProfile) {
- if (DEBUG) Log.d(TAG, "notify: profile added: " + localProfile);
- Intent intent = new Intent(SipManager.ACTION_SIP_ADD_PHONE);
- intent.putExtra(SipManager.EXTRA_LOCAL_URI, localProfile.getUriString());
- mContext.sendBroadcast(intent);
- }
-
- private void notifyProfileRemoved(SipProfile localProfile) {
- if (DEBUG) Log.d(TAG, "notify: profile removed: " + localProfile);
- Intent intent = new Intent(SipManager.ACTION_SIP_REMOVE_PHONE);
- intent.putExtra(SipManager.EXTRA_LOCAL_URI, localProfile.getUriString());
- mContext.sendBroadcast(intent);
- }
-
- private boolean anyOpened() {
- for (SipSessionGroupExt group : mSipGroups.values()) {
- if (group.isOpened()) return true;
- }
- return false;
- }
-
- private void grabWifiLock() {
- if (mWifiLock == null) {
- if (DEBUG) Log.d(TAG, "acquire wifi lock");
- mWifiLock = ((WifiManager)
- mContext.getSystemService(Context.WIFI_SERVICE))
- .createWifiLock(WifiManager.WIFI_MODE_FULL, TAG);
- mWifiLock.acquire();
- }
- }
-
- private void releaseWifiLock() {
- if (mWifiLock != null) {
- if (DEBUG) Log.d(TAG, "release wifi lock");
- mWifiLock.release();
- mWifiLock = null;
- }
- }
-
- private boolean isWifiOn() {
- return "WIFI".equalsIgnoreCase(mNetworkType);
- //return (mConnected && "WIFI".equalsIgnoreCase(mNetworkType));
- }
-
- private synchronized void onConnectivityChanged(
- String type, boolean connected) {
- if (DEBUG) Log.d(TAG, "onConnectivityChanged(): "
- + mNetworkType + (mConnected? " CONNECTED" : " DISCONNECTED")
- + " --> " + type + (connected? " CONNECTED" : " DISCONNECTED"));
-
- boolean sameType = type.equals(mNetworkType);
- if (!sameType && !connected) return;
-
- boolean wasWifi = "WIFI".equalsIgnoreCase(mNetworkType);
- boolean isWifi = "WIFI".equalsIgnoreCase(type);
- boolean wifiOff = (isWifi && !connected) || (wasWifi && !sameType);
- boolean wifiOn = isWifi && connected;
- if (wifiOff) {
- releaseWifiLock();
- } else if (wifiOn) {
- if (anyOpened()) grabWifiLock();
- }
-
- try {
- boolean wasConnected = mConnected;
- mNetworkType = type;
- mConnected = connected;
-
- if (wasConnected) {
- mLocalIp = null;
- for (SipSessionGroupExt group : mSipGroups.values()) {
- group.onConnectivityChanged(false);
- }
- }
-
- if (connected) {
- mLocalIp = determineLocalIp();
- for (SipSessionGroupExt group : mSipGroups.values()) {
- group.onConnectivityChanged(true);
- }
- }
-
- } catch (SipException e) {
- Log.e(TAG, "onConnectivityChanged()", e);
- }
- }
-
- private synchronized void addPendingSession(ISipSession session) {
- try {
- mPendingSessions.put(session.getCallId(), session);
- } catch (RemoteException e) {
- // should not happen with a local call
- Log.e(TAG, "addPendingSession()", e);
- }
- }
-
- private class SipSessionGroupExt extends SipSessionAdapter {
- private SipSessionGroup mSipGroup;
- private String mIncomingCallBroadcastAction;
- private boolean mOpened;
-
- private AutoRegistrationProcess mAutoRegistration =
- new AutoRegistrationProcess();
-
- public SipSessionGroupExt(SipProfile localProfile,
- String incomingCallBroadcastAction,
- ISipSessionListener listener) throws SipException {
- String password = localProfile.getPassword();
- SipProfile p = duplicate(localProfile);
- mSipGroup = createSipSessionGroup(mLocalIp, p, password);
- mIncomingCallBroadcastAction = incomingCallBroadcastAction;
- mAutoRegistration.setListener(listener);
- }
-
- public SipProfile getLocalProfile() {
- return mSipGroup.getLocalProfile();
- }
-
- // network connectivity is tricky because network can be disconnected
- // at any instant so need to deal with exceptions carefully even when
- // you think you are connected
- private SipSessionGroup createSipSessionGroup(String localIp,
- SipProfile localProfile, String password) throws SipException {
- try {
- return new SipSessionGroup(localIp, localProfile, password);
- } catch (IOException e) {
- // network disconnected
- Log.w(TAG, "createSipSessionGroup(): network disconnected?");
- if (localIp != null) {
- return createSipSessionGroup(null, localProfile, password);
- } else {
- // recursive
- Log.wtf(TAG, "impossible!");
- throw new RuntimeException("createSipSessionGroup");
- }
- }
- }
-
- private SipProfile duplicate(SipProfile p) {
- try {
- return new SipProfile.Builder(p).setPassword("*").build();
- } catch (Exception e) {
- Log.wtf(TAG, "duplicate()", e);
- throw new RuntimeException("duplicate profile", e);
- }
- }
-
- public void setListener(ISipSessionListener listener) {
- mAutoRegistration.setListener(listener);
- }
-
- public void setIncomingCallBroadcastAction(String action) {
- mIncomingCallBroadcastAction = action;
- }
-
- public void openToReceiveCalls() throws SipException {
- mOpened = true;
- if (mConnected) {
- mSipGroup.openToReceiveCalls(this);
- mAutoRegistration.start(mSipGroup);
- }
- if (DEBUG) Log.d(TAG, " openToReceiveCalls: " + getUri() + ": "
- + mIncomingCallBroadcastAction);
- }
-
- public void onConnectivityChanged(boolean connected)
- throws SipException {
- mSipGroup.onConnectivityChanged();
- if (connected) {
- resetGroup(mLocalIp);
- if (mOpened) openToReceiveCalls();
- } else {
- // close mSipGroup but remember mOpened
- if (DEBUG) Log.d(TAG, " close auto reg temporarily: "
- + getUri() + ": " + mIncomingCallBroadcastAction);
- mSipGroup.close();
- mAutoRegistration.stop();
- }
- }
-
- private void resetGroup(String localIp) throws SipException {
- try {
- mSipGroup.reset(localIp);
- } catch (IOException e) {
- // network disconnected
- Log.w(TAG, "resetGroup(): network disconnected?");
- if (localIp != null) {
- resetGroup(null); // reset w/o local IP
- } else {
- // recursive
- Log.wtf(TAG, "impossible!");
- throw new RuntimeException("resetGroup");
- }
- }
- }
-
- public void close() {
- mOpened = false;
- mSipGroup.close();
- mAutoRegistration.stop();
- if (DEBUG) Log.d(TAG, " close: " + getUri() + ": "
- + mIncomingCallBroadcastAction);
- }
-
- public ISipSession createSession(ISipSessionListener listener) {
- return mSipGroup.createSession(listener);
- }
-
- @Override
- public void onRinging(ISipSession session, SipProfile caller,
- String sessionDescription) {
- synchronized (SipService.this) {
- try {
- if (!isRegistered()) {
- session.endCall();
- return;
- }
-
- // send out incoming call broadcast
- addPendingSession(session);
- Intent intent = SipManager.createIncomingCallBroadcast(
- session.getCallId(), sessionDescription)
- .setAction(mIncomingCallBroadcastAction);
- if (DEBUG) Log.d(TAG, " ringing~~ " + getUri() + ": "
- + caller.getUri() + ": " + session.getCallId()
- + " " + mIncomingCallBroadcastAction);
- mContext.sendBroadcast(intent);
- } catch (RemoteException e) {
- // should never happen with a local call
- Log.e(TAG, "processCall()", e);
- }
- }
- }
-
- @Override
- public void onError(ISipSession session, int errorCode,
- String message) {
- if (DEBUG) Log.d(TAG, "sip session error: "
- + SipErrorCode.toString(errorCode) + ": " + message);
- }
-
- public boolean isOpened() {
- return mOpened;
- }
-
- public boolean isRegistered() {
- return mAutoRegistration.isRegistered();
- }
-
- private String getUri() {
- return mSipGroup.getLocalProfileUri();
- }
- }
-
- private class KeepAliveProcess implements Runnable {
- private static final String TAG = "\\KEEPALIVE/";
- private static final int INTERVAL = 10;
- private SipSessionGroup.SipSessionImpl mSession;
-
- public KeepAliveProcess(SipSessionGroup.SipSessionImpl session) {
- mSession = session;
- }
-
- public void start() {
- mTimer.set(INTERVAL * 1000, this);
- }
-
- public void run() {
- // delegate to mExecutor
- getExecutor().addTask(new Runnable() {
- public void run() {
- realRun();
- }
- });
- }
-
- private void realRun() {
- synchronized (SipService.this) {
- SipSessionGroup.SipSessionImpl session = mSession.duplicate();
- if (DEBUG) Log.d(TAG, "~~~ keepalive");
- mTimer.cancel(this);
- session.sendKeepAlive();
- if (session.isReRegisterRequired()) {
- mSession.register(EXPIRY_TIME);
- } else {
- mTimer.set(INTERVAL * 1000, this);
- }
- }
- }
-
- public void stop() {
- mTimer.cancel(this);
- }
- }
-
- private class AutoRegistrationProcess extends SipSessionAdapter
- implements Runnable {
- private SipSessionGroup.SipSessionImpl mSession;
- private SipSessionListenerProxy mProxy = new SipSessionListenerProxy();
- private KeepAliveProcess mKeepAliveProcess;
- private int mBackoff = 1;
- private boolean mRegistered;
- private long mExpiryTime;
- private int mErrorCode;
- private String mErrorMessage;
-
- private String getAction() {
- return toString();
- }
-
- public void start(SipSessionGroup group) {
- if (mSession == null) {
- mBackoff = 1;
- mSession = (SipSessionGroup.SipSessionImpl)
- group.createSession(this);
- // return right away if no active network connection.
- if (mSession == null) return;
-
- // start unregistration to clear up old registration at server
- // TODO: when rfc5626 is deployed, use reg-id and sip.instance
- // in registration to avoid adding duplicate entries to server
- mSession.unregister();
- if (DEBUG) Log.d(TAG, "start AutoRegistrationProcess for "
- + mSession.getLocalProfile().getUriString());
- }
- }
-
- public void stop() {
- stop(false);
- }
-
- private void stopButKeepStates() {
- stop(true);
- }
-
- private void stop(boolean keepStates) {
- if (mSession == null) return;
- 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);
- }
-
- public void setListener(ISipSessionListener listener) {
- synchronized (SipService.this) {
- mProxy.setListener(listener);
- if (mSession == null) return;
-
- try {
- int state = (mSession == null)
- ? SipSession.State.READY_TO_CALL
- : mSession.getState();
- if ((state == SipSession.State.REGISTERING)
- || (state == SipSession.State.DEREGISTERING)) {
- mProxy.onRegistering(mSession);
- } else if (mRegistered) {
- int duration = (int)
- (mExpiryTime - SystemClock.elapsedRealtime());
- mProxy.onRegistrationDone(mSession, duration);
- } else if (mErrorCode != SipErrorCode.NO_ERROR) {
- if (mErrorCode == SipErrorCode.TIME_OUT) {
- mProxy.onRegistrationTimeout(mSession);
- } else {
- mProxy.onRegistrationFailed(mSession, mErrorCode,
- mErrorMessage);
- }
- }
- } catch (Throwable t) {
- Log.w(TAG, "setListener(): " + t);
- }
- }
- }
-
- public boolean isRegistered() {
- return mRegistered;
- }
-
- public void run() {
- // delegate to mExecutor
- getExecutor().addTask(new Runnable() {
- public void run() {
- realRun();
- }
- });
- }
-
- private void realRun() {
- mErrorCode = SipErrorCode.NO_ERROR;
- mErrorMessage = null;
- if (DEBUG) Log.d(TAG, "~~~ registering");
- synchronized (SipService.this) {
- if (mConnected && !isStopped()) mSession.register(EXPIRY_TIME);
- }
- }
-
- private boolean isBehindNAT(String address) {
- try {
- byte[] d = InetAddress.getByName(address).getAddress();
- if ((d[0] == 10) ||
- (((0x000000FF & ((int)d[0])) == 172) &&
- ((0x000000F0 & ((int)d[1])) == 16)) ||
- (((0x000000FF & ((int)d[0])) == 192) &&
- ((0x000000FF & ((int)d[1])) == 168))) {
- return true;
- }
- } catch (UnknownHostException e) {
- Log.e(TAG, "isBehindAT()" + address, e);
- }
- return false;
- }
-
- private void restart(int duration) {
- if (DEBUG) Log.d(TAG, "Refresh registration " + duration + "s later.");
- mTimer.cancel(this);
- mTimer.set(duration * 1000, this);
- }
-
- private int backoffDuration() {
- int duration = SHORT_EXPIRY_TIME * mBackoff;
- if (duration > 3600) {
- duration = 3600;
- } else {
- mBackoff *= 2;
- }
- return duration;
- }
-
- @Override
- public void onRegistering(ISipSession session) {
- if (DEBUG) Log.d(TAG, "onRegistering(): " + session);
- synchronized (SipService.this) {
- if (!isStopped() && (session != mSession)) return;
- mRegistered = false;
- mProxy.onRegistering(session);
- }
- }
-
- @Override
- public void onRegistrationDone(ISipSession session, int duration) {
- if (DEBUG) Log.d(TAG, "onRegistrationDone(): " + session);
- synchronized (SipService.this) {
- if (!isStopped() && (session != mSession)) return;
-
- mProxy.onRegistrationDone(session, duration);
-
- if (isStopped()) return;
-
- if (duration > 0) {
- mSession.clearReRegisterRequired();
- mExpiryTime = SystemClock.elapsedRealtime()
- + (duration * 1000);
-
- if (!mRegistered) {
- mRegistered = true;
- // allow some overlap to avoid call drop during renew
- duration -= MIN_EXPIRY_TIME;
- if (duration < MIN_EXPIRY_TIME) {
- duration = MIN_EXPIRY_TIME;
- }
- restart(duration);
-
- if (isBehindNAT(mLocalIp) ||
- mSession.getLocalProfile().getSendKeepAlive()) {
- if (mKeepAliveProcess == null) {
- mKeepAliveProcess =
- new KeepAliveProcess(mSession);
- }
- mKeepAliveProcess.start();
- }
- }
- } else {
- mRegistered = false;
- mExpiryTime = -1L;
- if (DEBUG) Log.d(TAG, "Refresh registration immediately");
- run();
- }
- }
- }
-
- @Override
- public void onRegistrationFailed(ISipSession session, int errorCode,
- String message) {
- if (DEBUG) Log.d(TAG, "onRegistrationFailed(): " + session + ": "
- + SipErrorCode.toString(errorCode) + ": " + message);
- synchronized (SipService.this) {
- if (!isStopped() && (session != mSession)) return;
- mErrorCode = errorCode;
- mErrorMessage = message;
- mProxy.onRegistrationFailed(session, errorCode, message);
-
- if (errorCode == SipErrorCode.INVALID_CREDENTIALS) {
- if (DEBUG) Log.d(TAG, " pause auto-registration");
- stopButKeepStates();
- } else if (!isStopped()) {
- onError();
- }
- }
- }
-
- @Override
- public void onRegistrationTimeout(ISipSession session) {
- if (DEBUG) Log.d(TAG, "onRegistrationTimeout(): " + session);
- synchronized (SipService.this) {
- if (!isStopped() && (session != mSession)) return;
- mErrorCode = SipErrorCode.TIME_OUT;
- mProxy.onRegistrationTimeout(session);
-
- if (!isStopped()) {
- mRegistered = false;
- onError();
- }
- }
- }
-
- private void onError() {
- mRegistered = false;
- restart(backoffDuration());
- if (mKeepAliveProcess != null) {
- mKeepAliveProcess.stop();
- mKeepAliveProcess = null;
- }
- }
- }
-
- private class ConnectivityReceiver extends BroadcastReceiver {
- private Timer mTimer = new Timer();
- private MyTimerTask mTask;
-
- @Override
- public void onReceive(Context context, Intent intent) {
- String action = intent.getAction();
- if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
- Bundle b = intent.getExtras();
- if (b != null) {
- NetworkInfo netInfo = (NetworkInfo)
- b.get(ConnectivityManager.EXTRA_NETWORK_INFO);
- String type = netInfo.getTypeName();
- NetworkInfo.State state = netInfo.getState();
-
- if (mWifiOnly && (netInfo.getType() !=
- ConnectivityManager.TYPE_WIFI)) {
- if (DEBUG) {
- Log.d(TAG, "Wifi only, other connectivity ignored: "
- + type);
- }
- return;
- }
-
- NetworkInfo activeNetInfo = getActiveNetworkInfo();
- if (DEBUG) {
- if (activeNetInfo != null) {
- Log.d(TAG, "active network: "
- + activeNetInfo.getTypeName()
- + ((activeNetInfo.getState() == NetworkInfo.State.CONNECTED)
- ? " CONNECTED" : " DISCONNECTED"));
- } else {
- Log.d(TAG, "active network: null");
- }
- }
- if ((state == NetworkInfo.State.CONNECTED)
- && (activeNetInfo != null)
- && (activeNetInfo.getType() != netInfo.getType())) {
- if (DEBUG) Log.d(TAG, "ignore connect event: " + type
- + ", active: " + activeNetInfo.getTypeName());
- return;
- }
-
- if (state == NetworkInfo.State.CONNECTED) {
- if (DEBUG) Log.d(TAG, "Connectivity alert: CONNECTED " + type);
- onChanged(type, true);
- } else if (state == NetworkInfo.State.DISCONNECTED) {
- if (DEBUG) Log.d(TAG, "Connectivity alert: DISCONNECTED " + type);
- onChanged(type, false);
- } else {
- if (DEBUG) Log.d(TAG, "Connectivity alert not processed: "
- + state + " " + type);
- }
- }
- }
- }
-
- private NetworkInfo getActiveNetworkInfo() {
- ConnectivityManager cm = (ConnectivityManager)
- mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
- return cm.getActiveNetworkInfo();
- }
-
- private void onChanged(String type, boolean connected) {
- synchronized (SipService.this) {
- // When turning on WIFI, it needs some time for network
- // connectivity to get stabile so we defer good news (because
- // we want to skip the interim ones) but deliver bad news
- // immediately
- if (connected) {
- if (mTask != null) mTask.cancel();
- mTask = new MyTimerTask(type, connected);
- mTimer.schedule(mTask, 2 * 1000L);
- // TODO: hold wakup lock so that we can finish change before
- // the device goes to sleep
- } else {
- if ((mTask != null) && mTask.mNetworkType.equals(type)) {
- mTask.cancel();
- }
- onConnectivityChanged(type, false);
- }
- }
- }
-
- private class MyTimerTask extends TimerTask {
- private boolean mConnected;
- private String mNetworkType;
-
- public MyTimerTask(String type, boolean connected) {
- mNetworkType = type;
- mConnected = connected;
- }
-
- @Override
- public void run() {
- // delegate to mExecutor
- getExecutor().addTask(new Runnable() {
- public void run() {
- realRun();
- }
- });
- }
-
- private void realRun() {
- synchronized (SipService.this) {
- if (mTask != this) {
- Log.w(TAG, " unexpected task: " + mNetworkType
- + (mConnected ? " CONNECTED" : "DISCONNECTED"));
- return;
- }
- mTask = null;
- if (DEBUG) Log.d(TAG, " deliver change for " + mNetworkType
- + (mConnected ? " CONNECTED" : "DISCONNECTED"));
- onConnectivityChanged(mNetworkType, mConnected);
- }
- }
- }
- }
-
- // TODO: clean up pending SipSession(s) periodically
-
-
- /**
- * Timer that can schedule events to occur even when the device is in sleep.
- * Only used internally in this package.
- */
- class WakeupTimer extends BroadcastReceiver {
- private static final String TAG = "_SIP.WkTimer_";
- private static final String TRIGGER_TIME = "TriggerTime";
-
- private Context mContext;
- private AlarmManager mAlarmManager;
-
- // runnable --> time to execute in SystemClock
- private TreeSet<MyEvent> mEventQueue =
- new TreeSet<MyEvent>(new MyEventComparator());
-
- private PendingIntent mPendingIntent;
-
- public WakeupTimer(Context context) {
- mContext = context;
- mAlarmManager = (AlarmManager)
- context.getSystemService(Context.ALARM_SERVICE);
-
- IntentFilter filter = new IntentFilter(getAction());
- context.registerReceiver(this, filter);
- }
-
- /**
- * Stops the timer. No event can be scheduled after this method is called.
- */
- public synchronized void stop() {
- mContext.unregisterReceiver(this);
- if (mPendingIntent != null) {
- mAlarmManager.cancel(mPendingIntent);
- mPendingIntent = null;
- }
- mEventQueue.clear();
- mEventQueue = null;
- }
-
- private synchronized boolean stopped() {
- if (mEventQueue == null) {
- Log.w(TAG, "Timer stopped");
- return true;
- } else {
- return false;
- }
- }
-
- private void cancelAlarm() {
- mAlarmManager.cancel(mPendingIntent);
- mPendingIntent = null;
- }
-
- private void recalculatePeriods() {
- if (mEventQueue.isEmpty()) return;
-
- MyEvent firstEvent = mEventQueue.first();
- int minPeriod = firstEvent.mMaxPeriod;
- long minTriggerTime = firstEvent.mTriggerTime;
- for (MyEvent e : mEventQueue) {
- e.mPeriod = e.mMaxPeriod / minPeriod * minPeriod;
- int interval = (int) (e.mLastTriggerTime + e.mMaxPeriod
- - minTriggerTime);
- interval = interval / minPeriod * minPeriod;
- e.mTriggerTime = minTriggerTime + interval;
- }
- TreeSet<MyEvent> newQueue = new TreeSet<MyEvent>(
- mEventQueue.comparator());
- newQueue.addAll((Collection<MyEvent>) mEventQueue);
- mEventQueue.clear();
- mEventQueue = newQueue;
- if (DEBUG_TIMER) {
- Log.d(TAG, "queue re-calculated");
- printQueue();
- }
- }
-
- // Determines the period and the trigger time of the new event and insert it
- // to the queue.
- private void insertEvent(MyEvent event) {
- long now = SystemClock.elapsedRealtime();
- if (mEventQueue.isEmpty()) {
- event.mTriggerTime = now + event.mPeriod;
- mEventQueue.add(event);
- return;
- }
- MyEvent firstEvent = mEventQueue.first();
- int minPeriod = firstEvent.mPeriod;
- if (minPeriod <= event.mMaxPeriod) {
- event.mPeriod = event.mMaxPeriod / minPeriod * minPeriod;
- int interval = event.mMaxPeriod;
- interval -= (int) (firstEvent.mTriggerTime - now);
- interval = interval / minPeriod * minPeriod;
- event.mTriggerTime = firstEvent.mTriggerTime + interval;
- mEventQueue.add(event);
- } else {
- long triggerTime = now + event.mPeriod;
- if (firstEvent.mTriggerTime < triggerTime) {
- event.mTriggerTime = firstEvent.mTriggerTime;
- event.mLastTriggerTime -= event.mPeriod;
- } else {
- event.mTriggerTime = triggerTime;
- }
- mEventQueue.add(event);
- recalculatePeriods();
- }
- }
-
- /**
- * Sets a periodic timer.
- *
- * @param period the timer period; in milli-second
- * @param callback is called back when the timer goes off; the same callback
- * can be specified in multiple timer events
- */
- public synchronized void set(int period, Runnable callback) {
- if (stopped()) return;
-
- long now = SystemClock.elapsedRealtime();
- MyEvent event = new MyEvent(period, callback, now);
- insertEvent(event);
-
- if (mEventQueue.first() == event) {
- if (mEventQueue.size() > 1) cancelAlarm();
- scheduleNext();
- }
-
- long triggerTime = event.mTriggerTime;
- if (DEBUG_TIMER) {
- Log.d(TAG, " add event " + event + " scheduled at "
- + showTime(triggerTime) + " at " + showTime(now)
- + ", #events=" + mEventQueue.size());
- printQueue();
- }
- }
-
- /**
- * Cancels all the timer events with the specified callback.
- *
- * @param callback the callback
- */
- public synchronized void cancel(Runnable callback) {
- if (stopped() || mEventQueue.isEmpty()) return;
- if (DEBUG_TIMER) Log.d(TAG, "cancel:" + callback);
-
- MyEvent firstEvent = mEventQueue.first();
- for (Iterator<MyEvent> iter = mEventQueue.iterator();
- iter.hasNext();) {
- MyEvent event = iter.next();
- if (event.mCallback == callback) {
- iter.remove();
- if (DEBUG_TIMER) Log.d(TAG, " cancel found:" + event);
- }
- }
- if (mEventQueue.isEmpty()) {
- cancelAlarm();
- } else if (mEventQueue.first() != firstEvent) {
- cancelAlarm();
- firstEvent = mEventQueue.first();
- firstEvent.mPeriod = firstEvent.mMaxPeriod;
- firstEvent.mTriggerTime = firstEvent.mLastTriggerTime
- + firstEvent.mPeriod;
- recalculatePeriods();
- scheduleNext();
- }
- if (DEBUG_TIMER) {
- Log.d(TAG, "after cancel:");
- printQueue();
- }
- }
-
- private void scheduleNext() {
- if (stopped() || mEventQueue.isEmpty()) return;
-
- if (mPendingIntent != null) {
- throw new RuntimeException("pendingIntent is not null!");
- }
-
- MyEvent event = mEventQueue.first();
- Intent intent = new Intent(getAction());
- intent.putExtra(TRIGGER_TIME, event.mTriggerTime);
- PendingIntent pendingIntent = mPendingIntent =
- PendingIntent.getBroadcast(mContext, 0, intent,
- PendingIntent.FLAG_UPDATE_CURRENT);
- mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
- event.mTriggerTime, pendingIntent);
- }
-
- @Override
- public synchronized void onReceive(Context context, Intent intent) {
- String action = intent.getAction();
- if (getAction().equals(action)
- && intent.getExtras().containsKey(TRIGGER_TIME)) {
- mPendingIntent = null;
- long triggerTime = intent.getLongExtra(TRIGGER_TIME, -1L);
- execute(triggerTime);
- } else {
- Log.d(TAG, "unrecognized intent: " + intent);
- }
- }
-
- private void printQueue() {
- int count = 0;
- for (MyEvent event : mEventQueue) {
- Log.d(TAG, " " + event + ": scheduled at "
- + showTime(event.mTriggerTime) + ": last at "
- + showTime(event.mLastTriggerTime));
- if (++count >= 5) break;
- }
- if (mEventQueue.size() > count) {
- Log.d(TAG, " .....");
- } else if (count == 0) {
- Log.d(TAG, " <empty>");
- }
- }
-
- private void execute(long triggerTime) {
- if (DEBUG_TIMER) Log.d(TAG, "time's up, triggerTime = "
- + showTime(triggerTime) + ": " + mEventQueue.size());
- if (stopped() || mEventQueue.isEmpty()) return;
-
- for (MyEvent event : mEventQueue) {
- if (event.mTriggerTime != triggerTime) break;
- if (DEBUG_TIMER) Log.d(TAG, "execute " + event);
-
- event.mLastTriggerTime = event.mTriggerTime;
- event.mTriggerTime += event.mPeriod;
-
- // run the callback in a new thread to prevent deadlock
- new Thread(event.mCallback, "SipServiceTimerCallbackThread")
- .start();
- }
- if (DEBUG_TIMER) {
- Log.d(TAG, "after timeout execution");
- printQueue();
- }
- scheduleNext();
- }
-
- private String getAction() {
- return toString();
- }
-
- private String showTime(long time) {
- int ms = (int) (time % 1000);
- int s = (int) (time / 1000);
- int m = s / 60;
- s %= 60;
- return String.format("%d.%d.%d", m, s, ms);
- }
- }
-
- private static class MyEvent {
- int mPeriod;
- int mMaxPeriod;
- long mTriggerTime;
- long mLastTriggerTime;
- Runnable mCallback;
-
- MyEvent(int period, Runnable callback, long now) {
- mPeriod = mMaxPeriod = period;
- mCallback = callback;
- mLastTriggerTime = now;
- }
-
- @Override
- public String toString() {
- String s = super.toString();
- s = s.substring(s.indexOf("@"));
- return s + ":" + (mPeriod / 1000) + ":" + (mMaxPeriod / 1000) + ":"
- + toString(mCallback);
- }
-
- private String toString(Object o) {
- String s = o.toString();
- int index = s.indexOf("$");
- if (index > 0) s = s.substring(index + 1);
- return s;
- }
- }
-
- private static class MyEventComparator implements Comparator<MyEvent> {
- public int compare(MyEvent e1, MyEvent e2) {
- if (e1 == e2) return 0;
- int diff = e1.mMaxPeriod - e2.mMaxPeriod;
- if (diff == 0) diff = -1;
- return diff;
- }
-
- public boolean equals(Object that) {
- return (this == that);
- }
- }
-
- // Single-threaded executor
- private static class MyExecutor extends Handler {
- MyExecutor() {
- super(createLooper());
- }
-
- private static Looper createLooper() {
- HandlerThread thread = new HandlerThread("SipService");
- thread.start();
- return thread.getLooper();
- }
-
- void addTask(Runnable task) {
- Message.obtain(this, 0/* don't care */, task).sendToTarget();
- }
-
- @Override
- public void handleMessage(Message msg) {
- if (msg.obj instanceof Runnable) {
- ((Runnable) msg.obj).run();
- } else {
- Log.w(TAG, "can't handle msg: " + msg);
- }
- }
- }
-}
diff --git a/services/java/com/android/server/sip/SipSessionGroup.java b/services/java/com/android/server/sip/SipSessionGroup.java
deleted file mode 100644
index 91677a2..0000000
--- a/services/java/com/android/server/sip/SipSessionGroup.java
+++ /dev/null
@@ -1,1393 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.sip;
-
-import gov.nist.javax.sip.clientauthutils.AccountManager;
-import gov.nist.javax.sip.clientauthutils.UserCredentials;
-import gov.nist.javax.sip.header.SIPHeaderNames;
-import gov.nist.javax.sip.header.ProxyAuthenticate;
-import gov.nist.javax.sip.header.WWWAuthenticate;
-import gov.nist.javax.sip.message.SIPMessage;
-
-import android.net.sip.ISipSession;
-import android.net.sip.ISipSessionListener;
-import android.net.sip.SipErrorCode;
-import android.net.sip.SipProfile;
-import android.net.sip.SipSession;
-import android.net.sip.SipSessionAdapter;
-import android.text.TextUtils;
-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;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Properties;
-import java.util.TooManyListenersException;
-
-import javax.sip.ClientTransaction;
-import javax.sip.Dialog;
-import javax.sip.DialogTerminatedEvent;
-import javax.sip.IOExceptionEvent;
-import javax.sip.InvalidArgumentException;
-import javax.sip.ListeningPoint;
-import javax.sip.RequestEvent;
-import javax.sip.ResponseEvent;
-import javax.sip.ServerTransaction;
-import javax.sip.SipException;
-import javax.sip.SipFactory;
-import javax.sip.SipListener;
-import javax.sip.SipProvider;
-import javax.sip.SipStack;
-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;
-import javax.sip.header.ExpiresHeader;
-import javax.sip.header.FromHeader;
-import javax.sip.header.MinExpiresHeader;
-import javax.sip.header.ViaHeader;
-import javax.sip.message.Message;
-import javax.sip.message.Request;
-import javax.sip.message.Response;
-
-/**
- * Manages {@link ISipSession}'s for a SIP account.
- */
-class SipSessionGroup implements SipListener {
- private static final String TAG = "SipSession";
- private static final boolean DEBUG = true;
- private static final boolean DEBUG_PING = DEBUG && false;
- private static final String ANONYMOUS = "anonymous";
- private static final String SERVER_ERROR_PREFIX = "Response: ";
- private static final int EXPIRY_TIME = 3600; // in seconds
- private static final int CANCEL_CALL_TIMER = 3; // in seconds
-
- private static final EventObject DEREGISTER = new EventObject("Deregister");
- private static final EventObject END_CALL = new EventObject("End call");
- private static final EventObject HOLD_CALL = new EventObject("Hold call");
- private static final EventObject CONTINUE_CALL
- = new EventObject("Continue call");
-
- private final SipProfile mLocalProfile;
- private final String mPassword;
-
- private SipStack mSipStack;
- private SipHelper mSipHelper;
- private String mLastNonce;
- private int mRPort;
-
- // session that processes INVITE requests
- private SipSessionImpl mCallReceiverSession;
- private String mLocalIp;
-
- // call-id-to-SipSession map
- private Map<String, SipSessionImpl> mSessionMap =
- new HashMap<String, SipSessionImpl>();
-
- /**
- * @param myself the local profile with password crossed out
- * @param password the password of the profile
- * @throws IOException if cannot assign requested address
- */
- public SipSessionGroup(String localIp, SipProfile myself, String password)
- throws SipException, IOException {
- mLocalProfile = myself;
- mPassword = password;
- reset(localIp);
- }
-
- synchronized void reset(String localIp) throws SipException, IOException {
- mLocalIp = localIp;
- if (localIp == null) return;
-
- SipProfile myself = mLocalProfile;
- SipFactory sipFactory = SipFactory.getInstance();
- Properties properties = new Properties();
- properties.setProperty("javax.sip.STACK_NAME", getStackName());
- String outboundProxy = myself.getProxyAddress();
- if (!TextUtils.isEmpty(outboundProxy)) {
- Log.v(TAG, "outboundProxy is " + outboundProxy);
- properties.setProperty("javax.sip.OUTBOUND_PROXY", outboundProxy
- + ":" + myself.getPort() + "/" + myself.getProtocol());
- }
- SipStack stack = mSipStack = sipFactory.createSipStack(properties);
-
- try {
- SipProvider provider = stack.createSipProvider(
- stack.createListeningPoint(localIp, allocateLocalPort(),
- myself.getProtocol()));
- provider.addSipListener(this);
- mSipHelper = new SipHelper(stack, provider);
- } catch (InvalidArgumentException e) {
- throw new IOException(e.getMessage());
- } catch (TooManyListenersException e) {
- // must never happen
- throw new SipException("SipSessionGroup constructor", e);
- }
- Log.d(TAG, " start stack for " + myself.getUriString());
- stack.start();
-
- mLastNonce = null;
- mCallReceiverSession = null;
- mSessionMap.clear();
- }
-
- synchronized void onConnectivityChanged() {
- for (SipSessionImpl s : mSessionMap.values()) {
- s.onError(SipErrorCode.DATA_CONNECTION_LOST,
- "data connection lost");
- }
- }
-
- public SipProfile getLocalProfile() {
- return mLocalProfile;
- }
-
- public String getLocalProfileUri() {
- return mLocalProfile.getUriString();
- }
-
- private String getStackName() {
- return "stack" + System.currentTimeMillis();
- }
-
- public synchronized void close() {
- Log.d(TAG, " close stack for " + mLocalProfile.getUriString());
- mSessionMap.clear();
- closeToNotReceiveCalls();
- if (mSipStack != null) {
- mSipStack.stop();
- mSipStack = null;
- mSipHelper = null;
- }
- }
-
- public synchronized boolean isClosed() {
- return (mSipStack == null);
- }
-
- // For internal use, require listener not to block in callbacks.
- public synchronized void openToReceiveCalls(ISipSessionListener listener) {
- if (mCallReceiverSession == null) {
- mCallReceiverSession = new SipSessionCallReceiverImpl(listener);
- } else {
- mCallReceiverSession.setListener(listener);
- }
- }
-
- public synchronized void closeToNotReceiveCalls() {
- mCallReceiverSession = null;
- }
-
- public ISipSession createSession(ISipSessionListener listener) {
- return (isClosed() ? null : new SipSessionImpl(listener));
- }
-
- private static int allocateLocalPort() throws SipException {
- try {
- DatagramSocket s = new DatagramSocket();
- int localPort = s.getLocalPort();
- s.close();
- return localPort;
- } catch (IOException e) {
- throw new SipException("allocateLocalPort()", e);
- }
- }
-
- private synchronized SipSessionImpl getSipSession(EventObject event) {
- String key = SipHelper.getCallId(event);
- SipSessionImpl session = mSessionMap.get(key);
- if ((session != null) && isLoggable(session)) {
- Log.d(TAG, "session key from event: " + key);
- Log.d(TAG, "active sessions:");
- for (String k : mSessionMap.keySet()) {
- Log.d(TAG, " ..." + k + ": " + mSessionMap.get(k));
- }
- }
- return ((session != null) ? session : mCallReceiverSession);
- }
-
- private synchronized void addSipSession(SipSessionImpl newSession) {
- removeSipSession(newSession);
- String key = newSession.getCallId();
- mSessionMap.put(key, newSession);
- if (isLoggable(newSession)) {
- Log.d(TAG, "+++ add a session with key: '" + key + "'");
- for (String k : mSessionMap.keySet()) {
- Log.d(TAG, " " + k + ": " + mSessionMap.get(k));
- }
- }
- }
-
- private synchronized void removeSipSession(SipSessionImpl session) {
- if (session == mCallReceiverSession) return;
- String key = session.getCallId();
- SipSessionImpl s = mSessionMap.remove(key);
- // sanity check
- if ((s != null) && (s != session)) {
- Log.w(TAG, "session " + session + " is not associated with key '"
- + key + "'");
- mSessionMap.put(key, s);
- for (Map.Entry<String, SipSessionImpl> entry
- : mSessionMap.entrySet()) {
- if (entry.getValue() == s) {
- key = entry.getKey();
- mSessionMap.remove(key);
- }
- }
- }
-
- if ((s != null) && isLoggable(s)) {
- Log.d(TAG, "remove session " + session + " @key '" + key + "'");
- for (String k : mSessionMap.keySet()) {
- Log.d(TAG, " " + k + ": " + mSessionMap.get(k));
- }
- }
- }
-
- public void processRequest(RequestEvent event) {
- process(event);
- }
-
- public void processResponse(ResponseEvent event) {
- process(event);
- }
-
- public void processIOException(IOExceptionEvent event) {
- process(event);
- }
-
- public void processTimeout(TimeoutEvent event) {
- process(event);
- }
-
- public void processTransactionTerminated(TransactionTerminatedEvent event) {
- process(event);
- }
-
- public void processDialogTerminated(DialogTerminatedEvent event) {
- process(event);
- }
-
- private synchronized void process(EventObject event) {
- SipSessionImpl session = getSipSession(event);
- try {
- boolean isLoggable = isLoggable(session, event);
- boolean processed = (session != null) && session.process(event);
- if (isLoggable && processed) {
- Log.d(TAG, "new state after: "
- + SipSession.State.toString(session.mState));
- }
- } catch (Throwable e) {
- Log.w(TAG, "event process error: " + event, e);
- session.onError(e);
- }
- }
-
- private String extractContent(Message message) {
- // Currently we do not support secure MIME bodies.
- byte[] bytes = message.getRawContent();
- if (bytes != null) {
- try {
- if (message instanceof SIPMessage) {
- return ((SIPMessage) message).getMessageContent();
- } else {
- return new String(bytes, "UTF-8");
- }
- } catch (UnsupportedEncodingException e) {
- }
- }
- return null;
- }
-
- private class SipSessionCallReceiverImpl extends SipSessionImpl {
- public SipSessionCallReceiverImpl(ISipSessionListener listener) {
- super(listener);
- }
-
- public boolean process(EventObject evt) throws SipException {
- if (isLoggable(this, evt)) Log.d(TAG, " ~~~~~ " + this + ": "
- + SipSession.State.toString(mState) + ": processing "
- + log(evt));
- if (isRequestEvent(Request.INVITE, evt)) {
- RequestEvent event = (RequestEvent) evt;
- SipSessionImpl newSession = new SipSessionImpl(mProxy);
- newSession.mServerTransaction = mSipHelper.sendRinging(event,
- generateTag());
- newSession.mDialog = newSession.mServerTransaction.getDialog();
- newSession.mInviteReceived = event;
- newSession.mPeerProfile = createPeerProfile(event.getRequest());
- newSession.mState = SipSession.State.INCOMING_CALL;
- newSession.mPeerSessionDescription =
- extractContent(event.getRequest());
- addSipSession(newSession);
- mProxy.onRinging(newSession, newSession.mPeerProfile,
- newSession.mPeerSessionDescription);
- return true;
- } else if (isRequestEvent(Request.OPTIONS, evt)) {
- mSipHelper.sendResponse((RequestEvent) evt, Response.OK);
- return true;
- } else {
- return false;
- }
- }
- }
-
- class SipSessionImpl extends ISipSession.Stub {
- SipProfile mPeerProfile;
- SipSessionListenerProxy mProxy = new SipSessionListenerProxy();
- int mState = SipSession.State.READY_TO_CALL;
- RequestEvent mInviteReceived;
- Dialog mDialog;
- ServerTransaction mServerTransaction;
- ClientTransaction mClientTransaction;
- String mPeerSessionDescription;
- boolean mInCall;
- boolean mReRegisterFlag = false;
- SessionTimer mTimer;
-
- // lightweight timer
- class SessionTimer {
- private boolean mRunning = true;
-
- void start(final int timeout) {
- new Thread(new Runnable() {
- public void run() {
- sleep(timeout);
- if (mRunning) timeout();
- }
- }, "SipSessionTimerThread").start();
- }
-
- synchronized void cancel() {
- mRunning = false;
- this.notify();
- }
-
- private void timeout() {
- synchronized (SipSessionGroup.this) {
- onError(SipErrorCode.TIME_OUT, "Session timed out!");
- }
- }
-
- private synchronized void sleep(int timeout) {
- try {
- this.wait(timeout * 1000);
- } catch (InterruptedException e) {
- Log.e(TAG, "session timer interrupted!");
- }
- }
- }
-
- public SipSessionImpl(ISipSessionListener listener) {
- setListener(listener);
- }
-
- SipSessionImpl duplicate() {
- return new SipSessionImpl(mProxy.getListener());
- }
-
- private void reset() {
- mInCall = false;
- removeSipSession(this);
- mPeerProfile = null;
- mState = SipSession.State.READY_TO_CALL;
- mInviteReceived = null;
- mDialog = null;
- mServerTransaction = null;
- mClientTransaction = null;
- mPeerSessionDescription = null;
-
- cancelSessionTimer();
- }
-
- public boolean isInCall() {
- return mInCall;
- }
-
- public String getLocalIp() {
- return mLocalIp;
- }
-
- public SipProfile getLocalProfile() {
- return mLocalProfile;
- }
-
- public SipProfile getPeerProfile() {
- return mPeerProfile;
- }
-
- public String getCallId() {
- return SipHelper.getCallId(getTransaction());
- }
-
- private Transaction getTransaction() {
- if (mClientTransaction != null) return mClientTransaction;
- if (mServerTransaction != null) return mServerTransaction;
- return null;
- }
-
- public int getState() {
- return mState;
- }
-
- public void setListener(ISipSessionListener listener) {
- mProxy.setListener((listener instanceof SipSessionListenerProxy)
- ? ((SipSessionListenerProxy) listener).getListener()
- : listener);
- }
-
- // process the command in a new thread
- private void doCommandAsync(final EventObject command) {
- new Thread(new Runnable() {
- public void run() {
- try {
- processCommand(command);
- } catch (SipException e) {
- Log.w(TAG, "command error: " + command, e);
- onError(e);
- }
- }
- }, "SipSessionAsyncCmdThread").start();
- }
-
- public void makeCall(SipProfile peerProfile, String sessionDescription,
- int timeout) {
- doCommandAsync(new MakeCallCommand(peerProfile, sessionDescription,
- timeout));
- }
-
- public void answerCall(String sessionDescription, int timeout) {
- try {
- processCommand(new MakeCallCommand(mPeerProfile,
- sessionDescription, timeout));
- } catch (SipException e) {
- onError(e);
- }
- }
-
- public void endCall() {
- doCommandAsync(END_CALL);
- }
-
- public void changeCall(String sessionDescription, int timeout) {
- doCommandAsync(new MakeCallCommand(mPeerProfile, sessionDescription,
- timeout));
- }
-
- public void changeCallWithTimeout(
- String sessionDescription, int timeout) {
- doCommandAsync(new MakeCallCommand(mPeerProfile, sessionDescription,
- timeout));
- }
-
- public void register(int duration) {
- doCommandAsync(new RegisterCommand(duration));
- }
-
- public void unregister() {
- doCommandAsync(DEREGISTER);
- }
-
- public boolean isReRegisterRequired() {
- return mReRegisterFlag;
- }
-
- public void clearReRegisterRequired() {
- mReRegisterFlag = false;
- }
-
- public void sendKeepAlive() {
- mState = SipSession.State.PINGING;
- try {
- processCommand(new OptionsCommand());
- while (SipSession.State.PINGING == mState) {
- Thread.sleep(1000);
- }
- } catch (SipException e) {
- Log.e(TAG, "sendKeepAlive failed", e);
- } catch (InterruptedException e) {
- Log.e(TAG, "sendKeepAlive interrupted", e);
- }
- }
-
- private void processCommand(EventObject command) throws SipException {
- if (!process(command)) {
- onError(SipErrorCode.IN_PROGRESS,
- "cannot initiate a new transaction to execute: "
- + command);
- }
- }
-
- protected String generateTag() {
- // 32-bit randomness
- return String.valueOf((long) (Math.random() * 0x100000000L));
- }
-
- public String toString() {
- try {
- String s = super.toString();
- return s.substring(s.indexOf("@")) + ":"
- + SipSession.State.toString(mState);
- } catch (Throwable e) {
- return super.toString();
- }
- }
-
- public boolean process(EventObject evt) throws SipException {
- if (isLoggable(this, evt)) Log.d(TAG, " ~~~~~ " + this + ": "
- + SipSession.State.toString(mState) + ": processing "
- + log(evt));
- synchronized (SipSessionGroup.this) {
- if (isClosed()) return false;
-
- Dialog dialog = null;
- if (evt instanceof RequestEvent) {
- dialog = ((RequestEvent) evt).getDialog();
- } else if (evt instanceof ResponseEvent) {
- dialog = ((ResponseEvent) evt).getDialog();
- }
- if (dialog != null) mDialog = dialog;
-
- boolean processed;
-
- switch (mState) {
- case SipSession.State.REGISTERING:
- case SipSession.State.DEREGISTERING:
- processed = registeringToReady(evt);
- break;
- case SipSession.State.PINGING:
- processed = keepAliveProcess(evt);
- break;
- case SipSession.State.READY_TO_CALL:
- processed = readyForCall(evt);
- break;
- case SipSession.State.INCOMING_CALL:
- processed = incomingCall(evt);
- break;
- case SipSession.State.INCOMING_CALL_ANSWERING:
- processed = incomingCallToInCall(evt);
- break;
- case SipSession.State.OUTGOING_CALL:
- case SipSession.State.OUTGOING_CALL_RING_BACK:
- processed = outgoingCall(evt);
- break;
- case SipSession.State.OUTGOING_CALL_CANCELING:
- processed = outgoingCallToReady(evt);
- break;
- case SipSession.State.IN_CALL:
- processed = inCall(evt);
- break;
- default:
- processed = false;
- }
- return (processed || processExceptions(evt));
- }
- }
-
- private boolean processExceptions(EventObject evt) throws SipException {
- if (isRequestEvent(Request.BYE, evt)) {
- // terminate the call whenever a BYE is received
- mSipHelper.sendResponse((RequestEvent) evt, Response.OK);
- endCallNormally();
- return true;
- } else if (isRequestEvent(Request.CANCEL, evt)) {
- mSipHelper.sendResponse((RequestEvent) evt,
- Response.CALL_OR_TRANSACTION_DOES_NOT_EXIST);
- return true;
- } else if (evt instanceof TransactionTerminatedEvent) {
- if (isCurrentTransaction((TransactionTerminatedEvent) evt)) {
- if (evt instanceof TimeoutEvent) {
- processTimeout((TimeoutEvent) evt);
- } else {
- processTransactionTerminated(
- (TransactionTerminatedEvent) evt);
- }
- return true;
- }
- } else if (isRequestEvent(Request.OPTIONS, evt)) {
- mSipHelper.sendResponse((RequestEvent) evt, Response.OK);
- return true;
- } else if (evt instanceof DialogTerminatedEvent) {
- processDialogTerminated((DialogTerminatedEvent) evt);
- return true;
- }
- return false;
- }
-
- private void processDialogTerminated(DialogTerminatedEvent event) {
- if (mDialog == event.getDialog()) {
- onError(new SipException("dialog terminated"));
- } else {
- Log.d(TAG, "not the current dialog; current=" + mDialog
- + ", terminated=" + event.getDialog());
- }
- }
-
- private boolean isCurrentTransaction(TransactionTerminatedEvent event) {
- Transaction current = event.isServerTransaction()
- ? mServerTransaction
- : mClientTransaction;
- Transaction target = event.isServerTransaction()
- ? event.getServerTransaction()
- : event.getClientTransaction();
-
- if ((current != target) && (mState != SipSession.State.PINGING)) {
- Log.d(TAG, "not the current transaction; current="
- + toString(current) + ", target=" + toString(target));
- return false;
- } else if (current != null) {
- Log.d(TAG, "transaction terminated: " + toString(current));
- return true;
- } else {
- // no transaction; shouldn't be here; ignored
- return true;
- }
- }
-
- private String toString(Transaction transaction) {
- if (transaction == null) return "null";
- Request request = transaction.getRequest();
- Dialog dialog = transaction.getDialog();
- CSeqHeader cseq = (CSeqHeader) request.getHeader(CSeqHeader.NAME);
- return String.format("req=%s,%s,s=%s,ds=%s,", request.getMethod(),
- cseq.getSeqNumber(), transaction.getState(),
- ((dialog == null) ? "-" : dialog.getState()));
- }
-
- private void processTransactionTerminated(
- TransactionTerminatedEvent event) {
- switch (mState) {
- case SipSession.State.IN_CALL:
- case SipSession.State.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...");
- switch (mState) {
- case SipSession.State.REGISTERING:
- case SipSession.State.DEREGISTERING:
- reset();
- mProxy.onRegistrationTimeout(this);
- break;
- case SipSession.State.INCOMING_CALL:
- case SipSession.State.INCOMING_CALL_ANSWERING:
- case SipSession.State.OUTGOING_CALL:
- case SipSession.State.OUTGOING_CALL_CANCELING:
- onError(SipErrorCode.TIME_OUT, event.toString());
- break;
- case SipSession.State.PINGING:
- reset();
- mReRegisterFlag = true;
- mState = SipSession.State.READY_TO_CALL;
- break;
-
- default:
- Log.d(TAG, " do nothing");
- break;
- }
- }
-
- private int getExpiryTime(Response response) {
- int expires = EXPIRY_TIME;
- ExpiresHeader expiresHeader = (ExpiresHeader)
- response.getHeader(ExpiresHeader.NAME);
- if (expiresHeader != null) expires = expiresHeader.getExpires();
- expiresHeader = (ExpiresHeader)
- response.getHeader(MinExpiresHeader.NAME);
- if (expiresHeader != null) {
- expires = Math.max(expires, expiresHeader.getExpires());
- }
- return expires;
- }
-
- private boolean keepAliveProcess(EventObject evt) throws SipException {
- if (evt instanceof OptionsCommand) {
- mClientTransaction = mSipHelper.sendKeepAlive(mLocalProfile,
- generateTag());
- mDialog = mClientTransaction.getDialog();
- addSipSession(this);
- return true;
- } else if (evt instanceof ResponseEvent) {
- return parseOptionsResult(evt);
- }
- return false;
- }
-
- private boolean parseOptionsResult(EventObject evt) {
- if (expectResponse(Request.OPTIONS, evt)) {
- ResponseEvent event = (ResponseEvent) evt;
- int rPort = getRPortFromResponse(event.getResponse());
- if (rPort != -1) {
- if (mRPort == 0) mRPort = rPort;
- if (mRPort != rPort) {
- mReRegisterFlag = true;
- if (DEBUG) Log.w(TAG, String.format(
- "rport is changed: %d <> %d", mRPort, rPort));
- mRPort = rPort;
- } else {
- if (DEBUG_PING) Log.w(TAG, "rport is the same: " + rPort);
- }
- } else {
- if (DEBUG) Log.w(TAG, "peer did not respond rport");
- }
- reset();
- return true;
- }
- return false;
- }
-
- private int getRPortFromResponse(Response response) {
- ViaHeader viaHeader = (ViaHeader)(response.getHeader(
- SIPHeaderNames.VIA));
- return (viaHeader == null) ? -1 : viaHeader.getRPort();
- }
-
- private boolean registeringToReady(EventObject evt)
- throws SipException {
- if (expectResponse(Request.REGISTER, evt)) {
- ResponseEvent event = (ResponseEvent) evt;
- Response response = event.getResponse();
-
- int statusCode = response.getStatusCode();
- switch (statusCode) {
- case Response.OK:
- int state = mState;
- onRegistrationDone((state == SipSession.State.REGISTERING)
- ? getExpiryTime(((ResponseEvent) evt).getResponse())
- : -1);
- mLastNonce = null;
- mRPort = 0;
- return true;
- case Response.UNAUTHORIZED:
- case Response.PROXY_AUTHENTICATION_REQUIRED:
- if (!handleAuthentication(event)) {
- if (mLastNonce == null) {
- onRegistrationFailed(SipErrorCode.SERVER_ERROR,
- "server does not provide challenge");
- } else {
- Log.v(TAG, "Incorrect username/password");
- onRegistrationFailed(
- SipErrorCode.INVALID_CREDENTIALS,
- "incorrect username or password");
- }
- }
- return true;
- default:
- if (statusCode >= 500) {
- onRegistrationFailed(response);
- return true;
- }
- }
- }
- return false;
- }
-
- private boolean handleAuthentication(ResponseEvent event)
- throws SipException {
- Response response = event.getResponse();
- String nonce = getNonceFromResponse(response);
- if (((nonce != null) && nonce.equals(mLastNonce)) ||
- (nonce == null)) {
- mLastNonce = nonce;
- return false;
- } else {
- mClientTransaction = mSipHelper.handleChallenge(
- event, getAccountManager());
- mDialog = mClientTransaction.getDialog();
- mLastNonce = nonce;
- return true;
- }
- }
-
- private boolean crossDomainAuthenticationRequired(Response response) {
- String realm = getRealmFromResponse(response);
- if (realm == null) realm = "";
- return !mLocalProfile.getSipDomain().trim().equals(realm.trim());
- }
-
- private AccountManager getAccountManager() {
- return new AccountManager() {
- public UserCredentials getCredentials(ClientTransaction
- challengedTransaction, String realm) {
- return new UserCredentials() {
- public String getUserName() {
- return mLocalProfile.getUserName();
- }
-
- public String getPassword() {
- return mPassword;
- }
-
- public String getSipDomain() {
- return mLocalProfile.getSipDomain();
- }
- };
- }
- };
- }
-
- private String getRealmFromResponse(Response response) {
- WWWAuthenticate wwwAuth = (WWWAuthenticate)response.getHeader(
- SIPHeaderNames.WWW_AUTHENTICATE);
- if (wwwAuth != null) return wwwAuth.getRealm();
- ProxyAuthenticate proxyAuth = (ProxyAuthenticate)response.getHeader(
- SIPHeaderNames.PROXY_AUTHENTICATE);
- return (proxyAuth == null) ? null : proxyAuth.getRealm();
- }
-
- private String getNonceFromResponse(Response response) {
- WWWAuthenticate wwwAuth = (WWWAuthenticate)response.getHeader(
- SIPHeaderNames.WWW_AUTHENTICATE);
- if (wwwAuth != null) return wwwAuth.getNonce();
- ProxyAuthenticate proxyAuth = (ProxyAuthenticate)response.getHeader(
- SIPHeaderNames.PROXY_AUTHENTICATE);
- return (proxyAuth == null) ? null : proxyAuth.getNonce();
- }
-
- private boolean readyForCall(EventObject evt) throws SipException {
- // expect MakeCallCommand, RegisterCommand, DEREGISTER
- if (evt instanceof MakeCallCommand) {
- MakeCallCommand cmd = (MakeCallCommand) evt;
- mPeerProfile = cmd.getPeerProfile();
- mClientTransaction = mSipHelper.sendInvite(mLocalProfile,
- mPeerProfile, cmd.getSessionDescription(),
- generateTag());
- mDialog = mClientTransaction.getDialog();
- addSipSession(this);
- mState = SipSession.State.OUTGOING_CALL;
- mProxy.onCalling(this);
- startSessionTimer(cmd.getTimeout());
- return true;
- } else if (evt instanceof RegisterCommand) {
- int duration = ((RegisterCommand) evt).getDuration();
- mClientTransaction = mSipHelper.sendRegister(mLocalProfile,
- generateTag(), duration);
- mDialog = mClientTransaction.getDialog();
- addSipSession(this);
- mState = SipSession.State.REGISTERING;
- mProxy.onRegistering(this);
- return true;
- } else if (DEREGISTER == evt) {
- mClientTransaction = mSipHelper.sendRegister(mLocalProfile,
- generateTag(), 0);
- mDialog = mClientTransaction.getDialog();
- addSipSession(this);
- mState = SipSession.State.DEREGISTERING;
- mProxy.onRegistering(this);
- return true;
- }
- return false;
- }
-
- private boolean incomingCall(EventObject evt) throws SipException {
- // expect MakeCallCommand(answering) , END_CALL cmd , Cancel
- if (evt instanceof MakeCallCommand) {
- // answer call
- mServerTransaction = mSipHelper.sendInviteOk(mInviteReceived,
- mLocalProfile,
- ((MakeCallCommand) evt).getSessionDescription(),
- mServerTransaction);
- mState = SipSession.State.INCOMING_CALL_ANSWERING;
- startSessionTimer(((MakeCallCommand) evt).getTimeout());
- return true;
- } else if (END_CALL == evt) {
- mSipHelper.sendInviteBusyHere(mInviteReceived,
- mServerTransaction);
- endCallNormally();
- return true;
- } else if (isRequestEvent(Request.CANCEL, evt)) {
- RequestEvent event = (RequestEvent) evt;
- mSipHelper.sendResponse(event, Response.OK);
- mSipHelper.sendInviteRequestTerminated(
- mInviteReceived.getRequest(), mServerTransaction);
- endCallNormally();
- return true;
- }
- return false;
- }
-
- private boolean incomingCallToInCall(EventObject evt)
- throws SipException {
- // expect ACK, CANCEL request
- if (isRequestEvent(Request.ACK, evt)) {
- establishCall();
- return true;
- } else if (isRequestEvent(Request.CANCEL, evt)) {
- // http://tools.ietf.org/html/rfc3261#section-9.2
- // Final response has been sent; do nothing here.
- return true;
- }
- return false;
- }
-
- private boolean outgoingCall(EventObject evt) throws SipException {
- if (expectResponse(Request.INVITE, evt)) {
- ResponseEvent event = (ResponseEvent) evt;
- Response response = event.getResponse();
-
- int statusCode = response.getStatusCode();
- switch (statusCode) {
- case Response.RINGING:
- if (mState == SipSession.State.OUTGOING_CALL) {
- mState = SipSession.State.OUTGOING_CALL_RING_BACK;
- mProxy.onRingingBack(this);
- cancelSessionTimer();
- }
- return true;
- case Response.OK:
- mSipHelper.sendInviteAck(event, mDialog);
- mPeerSessionDescription = extractContent(response);
- establishCall();
- return true;
- case Response.UNAUTHORIZED:
- case Response.PROXY_AUTHENTICATION_REQUIRED:
- if (crossDomainAuthenticationRequired(response)) {
- onError(SipErrorCode.CROSS_DOMAIN_AUTHENTICATION,
- getRealmFromResponse(response));
- } else if (handleAuthentication(event)) {
- addSipSession(this);
- } else if (mLastNonce == null) {
- onError(SipErrorCode.SERVER_ERROR,
- "server does not provide challenge");
- } else {
- onError(SipErrorCode.INVALID_CREDENTIALS,
- "incorrect username or password");
- }
- return true;
- case Response.REQUEST_PENDING:
- // TODO:
- // rfc3261#section-14.1; re-schedule invite
- return true;
- default:
- if (statusCode >= 400) {
- // error: an ack is sent automatically by the stack
- onError(response);
- return true;
- } else if (statusCode >= 300) {
- // TODO: handle 3xx (redirect)
- } else {
- return true;
- }
- }
- return false;
- } else if (END_CALL == evt) {
- // RFC says that UA should not send out cancel when no
- // response comes back yet. We are cheating for not checking
- // response.
- mSipHelper.sendCancel(mClientTransaction);
- mState = SipSession.State.OUTGOING_CALL_CANCELING;
- startSessionTimer(CANCEL_CALL_TIMER);
- return true;
- }
- return false;
- }
-
- private boolean outgoingCallToReady(EventObject evt)
- throws SipException {
- if (evt instanceof ResponseEvent) {
- ResponseEvent event = (ResponseEvent) evt;
- Response response = event.getResponse();
- int statusCode = response.getStatusCode();
- if (expectResponse(Request.CANCEL, evt)) {
- if (statusCode == Response.OK) {
- // do nothing; wait for REQUEST_TERMINATED
- return true;
- }
- } else if (expectResponse(Request.INVITE, evt)) {
- switch (statusCode) {
- case Response.OK:
- outgoingCall(evt); // abort Cancel
- return true;
- case Response.REQUEST_TERMINATED:
- endCallNormally();
- return true;
- }
- } else {
- return false;
- }
-
- if (statusCode >= 400) {
- onError(response);
- return true;
- }
- } else if (evt instanceof TransactionTerminatedEvent) {
- // rfc3261#section-14.1:
- // if re-invite gets timed out, terminate the dialog; but
- // re-invite is not reliable, just let it go and pretend
- // nothing happened.
- onError(new SipException("timed out"));
- }
- return false;
- }
-
- private boolean inCall(EventObject evt) throws SipException {
- // expect END_CALL cmd, BYE request, hold call (MakeCallCommand)
- // OK retransmission is handled in SipStack
- if (END_CALL == evt) {
- // rfc3261#section-15.1.1
- mSipHelper.sendBye(mDialog);
- endCallNormally();
- return true;
- } else if (isRequestEvent(Request.INVITE, evt)) {
- // got Re-INVITE
- RequestEvent event = mInviteReceived = (RequestEvent) evt;
- mState = SipSession.State.INCOMING_CALL;
- mPeerSessionDescription = extractContent(event.getRequest());
- mServerTransaction = null;
- mProxy.onRinging(this, mPeerProfile, mPeerSessionDescription);
- return true;
- } else if (isRequestEvent(Request.BYE, evt)) {
- mSipHelper.sendResponse((RequestEvent) evt, Response.OK);
- endCallNormally();
- return true;
- } else if (evt instanceof MakeCallCommand) {
- // to change call
- mClientTransaction = mSipHelper.sendReinvite(mDialog,
- ((MakeCallCommand) evt).getSessionDescription());
- mState = SipSession.State.OUTGOING_CALL;
- startSessionTimer(((MakeCallCommand) evt).getTimeout());
- return true;
- }
- return false;
- }
-
- // timeout in seconds
- private void startSessionTimer(int timeout) {
- if (timeout > 0) {
- mTimer = new SessionTimer();
- mTimer.start(timeout);
- }
- }
-
- private void cancelSessionTimer() {
- if (mTimer != null) {
- mTimer.cancel();
- mTimer = null;
- }
- }
-
- private String createErrorMessage(Response response) {
- return String.format(SERVER_ERROR_PREFIX + "%s (%d)",
- response.getReasonPhrase(), response.getStatusCode());
- }
-
- private void establishCall() {
- mState = SipSession.State.IN_CALL;
- mInCall = true;
- cancelSessionTimer();
- mProxy.onCallEstablished(this, mPeerSessionDescription);
- }
-
- private void fallbackToPreviousInCall(int errorCode, String message) {
- mState = SipSession.State.IN_CALL;
- mProxy.onCallChangeFailed(this, errorCode, message);
- }
-
- private void endCallNormally() {
- reset();
- mProxy.onCallEnded(this);
- }
-
- private void endCallOnError(int errorCode, String message) {
- reset();
- mProxy.onError(this, errorCode, message);
- }
-
- private void endCallOnBusy() {
- reset();
- mProxy.onCallBusy(this);
- }
-
- private void onError(int errorCode, String message) {
- cancelSessionTimer();
- switch (mState) {
- case SipSession.State.REGISTERING:
- case SipSession.State.DEREGISTERING:
- onRegistrationFailed(errorCode, message);
- break;
- default:
- if ((errorCode != SipErrorCode.DATA_CONNECTION_LOST)
- && 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) {
- int statusCode = response.getStatusCode();
- if (!mInCall && (statusCode == Response.BUSY_HERE)) {
- endCallOnBusy();
- } else {
- onError(getErrorCode(statusCode), createErrorMessage(response));
- }
- }
-
- private int getErrorCode(int responseStatusCode) {
- switch (responseStatusCode) {
- case Response.TEMPORARILY_UNAVAILABLE:
- case Response.FORBIDDEN:
- case Response.GONE:
- case Response.NOT_FOUND:
- case Response.NOT_ACCEPTABLE:
- case Response.NOT_ACCEPTABLE_HERE:
- return SipErrorCode.PEER_NOT_REACHABLE;
-
- case Response.REQUEST_URI_TOO_LONG:
- case Response.ADDRESS_INCOMPLETE:
- case Response.AMBIGUOUS:
- 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 int 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) {
- reset();
- mProxy.onRegistrationDone(this, duration);
- }
-
- private void onRegistrationFailed(int errorCode, String message) {
- reset();
- mProxy.onRegistrationFailed(this, errorCode, 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));
- }
- }
-
- /**
- * @return true if the event is a request event matching the specified
- * method; false otherwise
- */
- private static boolean isRequestEvent(String method, EventObject event) {
- try {
- if (event instanceof RequestEvent) {
- RequestEvent requestEvent = (RequestEvent) event;
- return method.equals(requestEvent.getRequest().getMethod());
- }
- } catch (Throwable e) {
- }
- return false;
- }
-
- private static String getCseqMethod(Message message) {
- return ((CSeqHeader) message.getHeader(CSeqHeader.NAME)).getMethod();
- }
-
- /**
- * @return true if the event is a response event and the CSeqHeader method
- * match the given arguments; false otherwise
- */
- private static boolean expectResponse(
- String expectedMethod, EventObject evt) {
- if (evt instanceof ResponseEvent) {
- ResponseEvent event = (ResponseEvent) evt;
- Response response = event.getResponse();
- return expectedMethod.equalsIgnoreCase(getCseqMethod(response));
- }
- return false;
- }
-
- /**
- * @return true if the event is a response event and the response code and
- * CSeqHeader method match the given arguments; false otherwise
- */
- private static boolean expectResponse(
- int responseCode, String expectedMethod, EventObject evt) {
- if (evt instanceof ResponseEvent) {
- ResponseEvent event = (ResponseEvent) evt;
- Response response = event.getResponse();
- if (response.getStatusCode() == responseCode) {
- return expectedMethod.equalsIgnoreCase(getCseqMethod(response));
- }
- }
- return false;
- }
-
- private static SipProfile createPeerProfile(Request request)
- throws SipException {
- try {
- FromHeader fromHeader =
- (FromHeader) request.getHeader(FromHeader.NAME);
- Address address = fromHeader.getAddress();
- SipURI uri = (SipURI) address.getURI();
- String username = uri.getUser();
- if (username == null) username = ANONYMOUS;
- return new SipProfile.Builder(username, uri.getHost())
- .setPort(uri.getPort())
- .setDisplayName(address.getDisplayName())
- .build();
- } catch (IllegalArgumentException e) {
- throw new SipException("createPeerProfile()", e);
- } catch (ParseException e) {
- throw new SipException("createPeerProfile()", e);
- }
- }
-
- private static boolean isLoggable(SipSessionImpl s) {
- if (s != null) {
- switch (s.mState) {
- case SipSession.State.PINGING:
- return DEBUG_PING;
- }
- }
- return DEBUG;
- }
-
- private static boolean isLoggable(SipSessionImpl s, EventObject evt) {
- if (!isLoggable(s)) return false;
- if (evt == null) return false;
-
- if (evt instanceof OptionsCommand) {
- return DEBUG_PING;
- } else if (evt instanceof ResponseEvent) {
- Response response = ((ResponseEvent) evt).getResponse();
- if (Request.OPTIONS.equals(response.getHeader(CSeqHeader.NAME))) {
- return DEBUG_PING;
- }
- return DEBUG;
- } else if (evt instanceof RequestEvent) {
- return DEBUG;
- }
- return false;
- }
-
- private static String log(EventObject evt) {
- if (evt instanceof RequestEvent) {
- return ((RequestEvent) evt).getRequest().toString();
- } else if (evt instanceof ResponseEvent) {
- return ((ResponseEvent) evt).getResponse().toString();
- } else {
- return evt.toString();
- }
- }
-
- private class OptionsCommand extends EventObject {
- public OptionsCommand() {
- super(SipSessionGroup.this);
- }
- }
-
- private class RegisterCommand extends EventObject {
- private int mDuration;
-
- public RegisterCommand(int duration) {
- super(SipSessionGroup.this);
- mDuration = duration;
- }
-
- public int getDuration() {
- return mDuration;
- }
- }
-
- private class MakeCallCommand extends EventObject {
- private String mSessionDescription;
- private int mTimeout; // in seconds
-
- public MakeCallCommand(SipProfile peerProfile,
- String sessionDescription) {
- this(peerProfile, sessionDescription, -1);
- }
-
- public MakeCallCommand(SipProfile peerProfile,
- String sessionDescription, int timeout) {
- super(peerProfile);
- mSessionDescription = sessionDescription;
- mTimeout = timeout;
- }
-
- public SipProfile getPeerProfile() {
- return (SipProfile) getSource();
- }
-
- public String getSessionDescription() {
- return mSessionDescription;
- }
-
- public int getTimeout() {
- return mTimeout;
- }
- }
-}
diff --git a/services/java/com/android/server/sip/SipSessionListenerProxy.java b/services/java/com/android/server/sip/SipSessionListenerProxy.java
deleted file mode 100644
index f8be0a8..0000000
--- a/services/java/com/android/server/sip/SipSessionListenerProxy.java
+++ /dev/null
@@ -1,217 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.sip;
-
-import android.net.sip.ISipSession;
-import android.net.sip.ISipSessionListener;
-import android.net.sip.SipProfile;
-import android.os.DeadObjectException;
-import android.util.Log;
-
-/** Class to help safely run a callback in a different thread. */
-class SipSessionListenerProxy extends ISipSessionListener.Stub {
- private static final String TAG = "SipSession";
-
- private ISipSessionListener mListener;
-
- public void setListener(ISipSessionListener listener) {
- mListener = listener;
- }
-
- public ISipSessionListener getListener() {
- return mListener;
- }
-
- private void proxy(Runnable runnable) {
- // One thread for each calling back.
- // Note: Guarantee ordering if the issue becomes important. Currently,
- // the chance of handling two callback events at a time is none.
- new Thread(runnable, "SipSessionCallbackThread").start();
- }
-
- public void onCalling(final ISipSession session) {
- if (mListener == null) return;
- proxy(new Runnable() {
- public void run() {
- try {
- mListener.onCalling(session);
- } catch (Throwable t) {
- handle(t, "onCalling()");
- }
- }
- });
- }
-
- public void onRinging(final ISipSession session, final SipProfile caller,
- final String sessionDescription) {
- if (mListener == null) return;
- proxy(new Runnable() {
- public void run() {
- try {
- mListener.onRinging(session, caller, sessionDescription);
- } catch (Throwable t) {
- handle(t, "onRinging()");
- }
- }
- });
- }
-
- public void onRingingBack(final ISipSession session) {
- if (mListener == null) return;
- proxy(new Runnable() {
- public void run() {
- try {
- mListener.onRingingBack(session);
- } catch (Throwable t) {
- handle(t, "onRingingBack()");
- }
- }
- });
- }
-
- public void onCallEstablished(final ISipSession session,
- final String sessionDescription) {
- if (mListener == null) return;
- proxy(new Runnable() {
- public void run() {
- try {
- mListener.onCallEstablished(session, sessionDescription);
- } catch (Throwable t) {
- handle(t, "onCallEstablished()");
- }
- }
- });
- }
-
- public void onCallEnded(final ISipSession session) {
- if (mListener == null) return;
- proxy(new Runnable() {
- public void run() {
- try {
- mListener.onCallEnded(session);
- } catch (Throwable t) {
- handle(t, "onCallEnded()");
- }
- }
- });
- }
-
- public void onCallBusy(final ISipSession session) {
- if (mListener == null) return;
- proxy(new Runnable() {
- public void run() {
- try {
- mListener.onCallBusy(session);
- } catch (Throwable t) {
- handle(t, "onCallBusy()");
- }
- }
- });
- }
-
- public void onCallChangeFailed(final ISipSession session,
- final int errorCode, final String message) {
- if (mListener == null) return;
- proxy(new Runnable() {
- public void run() {
- try {
- mListener.onCallChangeFailed(session, errorCode, message);
- } catch (Throwable t) {
- handle(t, "onCallChangeFailed()");
- }
- }
- });
- }
-
- public void onError(final ISipSession session, final int errorCode,
- final String message) {
- if (mListener == null) return;
- proxy(new Runnable() {
- public void run() {
- try {
- mListener.onError(session, errorCode, message);
- } catch (Throwable t) {
- handle(t, "onError()");
- }
- }
- });
- }
-
- public void onRegistering(final ISipSession session) {
- if (mListener == null) return;
- proxy(new Runnable() {
- public void run() {
- try {
- mListener.onRegistering(session);
- } catch (Throwable t) {
- handle(t, "onRegistering()");
- }
- }
- });
- }
-
- public void onRegistrationDone(final ISipSession session,
- final int duration) {
- if (mListener == null) return;
- proxy(new Runnable() {
- public void run() {
- try {
- mListener.onRegistrationDone(session, duration);
- } catch (Throwable t) {
- handle(t, "onRegistrationDone()");
- }
- }
- });
- }
-
- public void onRegistrationFailed(final ISipSession session,
- final int errorCode, final String message) {
- if (mListener == null) return;
- proxy(new Runnable() {
- public void run() {
- try {
- mListener.onRegistrationFailed(session, errorCode, message);
- } catch (Throwable t) {
- handle(t, "onRegistrationFailed()");
- }
- }
- });
- }
-
- public void onRegistrationTimeout(final ISipSession session) {
- if (mListener == null) return;
- proxy(new Runnable() {
- public void run() {
- try {
- mListener.onRegistrationTimeout(session);
- } catch (Throwable t) {
- handle(t, "onRegistrationTimeout()");
- }
- }
- });
- }
-
- private void handle(Throwable t, String message) {
- if (t instanceof DeadObjectException) {
- mListener = null;
- // This creates race but it's harmless. Just don't log the error
- // when it happens.
- } else if (mListener != null) {
- Log.w(TAG, message, t);
- }
- }
-}