12d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang/* 22d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang * Copyright (C) 2010, The Android Open Source Project 32d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang * 42d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang * Licensed under the Apache License, Version 2.0 (the "License"); 52d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang * you may not use this file except in compliance with the License. 62d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang * You may obtain a copy of the License at 72d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang * 82d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang * http://www.apache.org/licenses/LICENSE-2.0 92d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang * 102d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang * Unless required by applicable law or agreed to in writing, software 112d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang * distributed under the License is distributed on an "AS IS" BASIS, 122d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 132d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang * See the License for the specific language governing permissions and 142d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang * limitations under the License. 152d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang */ 162d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 172d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangpackage com.android.server.sip; 182d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 192d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport android.app.AlarmManager; 202d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport android.app.PendingIntent; 212d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport android.content.BroadcastReceiver; 222d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport android.content.Context; 232d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport android.content.Intent; 242d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport android.content.IntentFilter; 252d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport android.net.ConnectivityManager; 262d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport android.net.NetworkInfo; 272d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport android.net.sip.ISipService; 282d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport android.net.sip.ISipSession; 292d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport android.net.sip.ISipSessionListener; 303d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyanimport android.net.sip.SipErrorCode; 312d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport android.net.sip.SipManager; 322d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport android.net.sip.SipProfile; 3384a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyanimport android.net.sip.SipSession; 342d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport android.net.sip.SipSessionAdapter; 352d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport android.net.wifi.WifiManager; 365424c8dcacf1c227fe7deb0185510614122ab447Chung-yih Wangimport android.os.Binder; 372d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport android.os.Bundle; 38b17eae9e227475a323f61519abc8a7d35ddf8828Hung-ying Tyanimport android.os.Handler; 39b17eae9e227475a323f61519abc8a7d35ddf8828Hung-ying Tyanimport android.os.HandlerThread; 40b17eae9e227475a323f61519abc8a7d35ddf8828Hung-ying Tyanimport android.os.Looper; 41b17eae9e227475a323f61519abc8a7d35ddf8828Hung-ying Tyanimport android.os.Message; 42bd57eeafe034cf850225db403700b5dc5db5ebccHung-ying Tyanimport android.os.PowerManager; 436a53489ae594d7cc373a00687d6ea2f23d0634dfHung-ying Tyanimport android.os.Process; 442d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport android.os.RemoteException; 457e54ef71db3320a751571bba5259fba816399421Hung-ying Tyanimport android.os.ServiceManager; 462d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport android.os.SystemClock; 472d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport android.text.TextUtils; 482d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport android.util.Log; 492d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 502d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport java.io.IOException; 512d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport java.net.DatagramSocket; 522d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport java.net.InetAddress; 532d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport java.net.UnknownHostException; 546a53489ae594d7cc373a00687d6ea2f23d0634dfHung-ying Tyanimport java.util.ArrayList; 552d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport java.util.Collection; 562d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport java.util.Comparator; 572d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport java.util.HashMap; 582d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport java.util.Iterator; 592d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport java.util.Map; 602d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport java.util.Timer; 612d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport java.util.TimerTask; 622d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport java.util.TreeSet; 635621554033089d1c07d53f56e8cd9787125d6e28Hung-ying Tyanimport java.util.concurrent.Executor; 642d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport javax.sip.SipException; 652d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 6695b15c35608fe3ea679c8a478c6cbd841623371eChia-chi Yeh/** 6795b15c35608fe3ea679c8a478c6cbd841623371eChia-chi Yeh * @hide 6895b15c35608fe3ea679c8a478c6cbd841623371eChia-chi Yeh */ 692d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangpublic final class SipService extends ISipService.Stub { 7028f63c06894b9ca9252f43bc54a098c0a785d4b4Hung-ying Tyan static final String TAG = "SipService"; 71cb6ee06f62c20ae036a206667097f20b837b11abChia-chi Yeh static final boolean DEBUG = false; 722d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private static final int EXPIRY_TIME = 3600; 732d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private static final int SHORT_EXPIRY_TIME = 10; 742d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private static final int MIN_EXPIRY_TIME = 60; 754a267a9158a62010cd76ab93681586ea8e3d6015Hung-ying Tyan private static final int DEFAULT_KEEPALIVE_INTERVAL = 10; // in seconds 769edfa107575b5905c9ae0a2fa0d6f0cc19595300Hung-ying Tyan private static final int DEFAULT_MAX_KEEPALIVE_INTERVAL = 120; // in seconds 772d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 782d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private Context mContext; 792d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private String mLocalIp; 80c2bd6162eddad0cdfdafc037142e043680ffa705Chia-chi Yeh private int mNetworkType = -1; 815621554033089d1c07d53f56e8cd9787125d6e28Hung-ying Tyan private SipWakeupTimer mTimer; 822d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private WifiManager.WifiLock mWifiLock; 83ee59e6a9fc69241b286acb7b55a22b8393c81222Chia-chi Yeh private boolean mSipOnWifiOnly; 84f89654dd2847cc574dfa6a44806289f7e69e17b7Hung-ying Tyan 85bb0a989c17cd6135c8d9c8566507521d4d927fe0Chung-yih Wang private IntervalMeasurementProcess mIntervalMeasurementProcess; 862d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 875621554033089d1c07d53f56e8cd9787125d6e28Hung-ying Tyan private MyExecutor mExecutor = new MyExecutor(); 88b17eae9e227475a323f61519abc8a7d35ddf8828Hung-ying Tyan 892d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang // SipProfile URI --> group 902d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private Map<String, SipSessionGroupExt> mSipGroups = 912d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang new HashMap<String, SipSessionGroupExt>(); 922d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 932d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang // session ID --> session 942d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private Map<String, ISipSession> mPendingSessions = 952d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang new HashMap<String, ISipSession>(); 962d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 972d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private ConnectivityReceiver mConnectivityReceiver; 9828f63c06894b9ca9252f43bc54a098c0a785d4b4Hung-ying Tyan private SipWakeLock mMyWakeLock; 99bb0a989c17cd6135c8d9c8566507521d4d927fe0Chung-yih Wang private int mKeepAliveInterval; 1009edfa107575b5905c9ae0a2fa0d6f0cc19595300Hung-ying Tyan private int mLastGoodKeepAliveInterval = DEFAULT_KEEPALIVE_INTERVAL; 1012d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 1023424c02e6b931a8bbd651ae75217bebd008b2605Hung-ying Tyan /** 1037e54ef71db3320a751571bba5259fba816399421Hung-ying Tyan * Starts the SIP service. Do nothing if the SIP API is not supported on the 1047e54ef71db3320a751571bba5259fba816399421Hung-ying Tyan * device. 1053424c02e6b931a8bbd651ae75217bebd008b2605Hung-ying Tyan */ 1067e54ef71db3320a751571bba5259fba816399421Hung-ying Tyan public static void start(Context context) { 1077e54ef71db3320a751571bba5259fba816399421Hung-ying Tyan if (SipManager.isApiSupported(context)) { 1087e54ef71db3320a751571bba5259fba816399421Hung-ying Tyan ServiceManager.addService("sip", new SipService(context)); 1099db99a4dc10ac0d5d3751f03ea51c0fed217d2f8Hung-ying Tyan context.sendBroadcast(new Intent(SipManager.ACTION_SIP_SERVICE_UP)); 110e9b54077274d0c4066093cd90dabca59b3d9a157Hung-ying Tyan if (DEBUG) Log.d(TAG, "SIP service started"); 1117e54ef71db3320a751571bba5259fba816399421Hung-ying Tyan } 1123424c02e6b931a8bbd651ae75217bebd008b2605Hung-ying Tyan } 1133424c02e6b931a8bbd651ae75217bebd008b2605Hung-ying Tyan 1143424c02e6b931a8bbd651ae75217bebd008b2605Hung-ying Tyan private SipService(Context context) { 115c7510581b81d63536db7d46ca8533106c8cf57c6Hung-ying Tyan if (DEBUG) Log.d(TAG, " service started!"); 1162d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mContext = context; 1172d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mConnectivityReceiver = new ConnectivityReceiver(); 118ee59e6a9fc69241b286acb7b55a22b8393c81222Chia-chi Yeh 119ee59e6a9fc69241b286acb7b55a22b8393c81222Chia-chi Yeh mWifiLock = ((WifiManager) 120ee59e6a9fc69241b286acb7b55a22b8393c81222Chia-chi Yeh context.getSystemService(Context.WIFI_SERVICE)) 121ee59e6a9fc69241b286acb7b55a22b8393c81222Chia-chi Yeh .createWifiLock(WifiManager.WIFI_MODE_FULL, TAG); 122ee59e6a9fc69241b286acb7b55a22b8393c81222Chia-chi Yeh mWifiLock.setReferenceCounted(false); 123ee59e6a9fc69241b286acb7b55a22b8393c81222Chia-chi Yeh mSipOnWifiOnly = SipManager.isSipWifiOnly(context); 124ee59e6a9fc69241b286acb7b55a22b8393c81222Chia-chi Yeh 12528f63c06894b9ca9252f43bc54a098c0a785d4b4Hung-ying Tyan mMyWakeLock = new SipWakeLock((PowerManager) 126bd57eeafe034cf850225db403700b5dc5db5ebccHung-ying Tyan context.getSystemService(Context.POWER_SERVICE)); 1272d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 1285621554033089d1c07d53f56e8cd9787125d6e28Hung-ying Tyan mTimer = new SipWakeupTimer(context, mExecutor); 129e9b54077274d0c4066093cd90dabca59b3d9a157Hung-ying Tyan } 130e9b54077274d0c4066093cd90dabca59b3d9a157Hung-ying Tyan 1312d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public synchronized SipProfile[] getListOfProfiles() { 132aa562ffdb8f728569e6957b742f271eb7303f878Hung-ying Tyan mContext.enforceCallingOrSelfPermission( 133aa562ffdb8f728569e6957b742f271eb7303f878Hung-ying Tyan android.Manifest.permission.USE_SIP, null); 1346a53489ae594d7cc373a00687d6ea2f23d0634dfHung-ying Tyan boolean isCallerRadio = isCallerRadio(); 1356a53489ae594d7cc373a00687d6ea2f23d0634dfHung-ying Tyan ArrayList<SipProfile> profiles = new ArrayList<SipProfile>(); 1362d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang for (SipSessionGroupExt group : mSipGroups.values()) { 1376a53489ae594d7cc373a00687d6ea2f23d0634dfHung-ying Tyan if (isCallerRadio || isCallerCreator(group)) { 1386a53489ae594d7cc373a00687d6ea2f23d0634dfHung-ying Tyan profiles.add(group.getLocalProfile()); 1396a53489ae594d7cc373a00687d6ea2f23d0634dfHung-ying Tyan } 1402d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 1416a53489ae594d7cc373a00687d6ea2f23d0634dfHung-ying Tyan return profiles.toArray(new SipProfile[profiles.size()]); 1422d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 1432d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 144e9b54077274d0c4066093cd90dabca59b3d9a157Hung-ying Tyan public synchronized void open(SipProfile localProfile) { 145aa562ffdb8f728569e6957b742f271eb7303f878Hung-ying Tyan mContext.enforceCallingOrSelfPermission( 146aa562ffdb8f728569e6957b742f271eb7303f878Hung-ying Tyan android.Manifest.permission.USE_SIP, null); 1475424c8dcacf1c227fe7deb0185510614122ab447Chung-yih Wang localProfile.setCallingUid(Binder.getCallingUid()); 1482d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang try { 1492d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang createGroup(localProfile); 1502d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } catch (SipException e) { 1512d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang Log.e(TAG, "openToMakeCalls()", e); 1522d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang // TODO: how to send the exception back 1532d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 1542d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 1552d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 1562d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public synchronized void open3(SipProfile localProfile, 157323d3671ac813df8dd173f3f4d6cb681ee29f740Hung-ying Tyan PendingIntent incomingCallPendingIntent, 158323d3671ac813df8dd173f3f4d6cb681ee29f740Hung-ying Tyan ISipSessionListener listener) { 159aa562ffdb8f728569e6957b742f271eb7303f878Hung-ying Tyan mContext.enforceCallingOrSelfPermission( 160aa562ffdb8f728569e6957b742f271eb7303f878Hung-ying Tyan android.Manifest.permission.USE_SIP, null); 1615424c8dcacf1c227fe7deb0185510614122ab447Chung-yih Wang localProfile.setCallingUid(Binder.getCallingUid()); 162323d3671ac813df8dd173f3f4d6cb681ee29f740Hung-ying Tyan if (incomingCallPendingIntent == null) { 163323d3671ac813df8dd173f3f4d6cb681ee29f740Hung-ying Tyan Log.w(TAG, "incomingCallPendingIntent cannot be null; " 164323d3671ac813df8dd173f3f4d6cb681ee29f740Hung-ying Tyan + "the profile is not opened"); 1656a53489ae594d7cc373a00687d6ea2f23d0634dfHung-ying Tyan return; 1662d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 167c7510581b81d63536db7d46ca8533106c8cf57c6Hung-ying Tyan if (DEBUG) Log.d(TAG, "open3: " + localProfile.getUriString() + ": " 168323d3671ac813df8dd173f3f4d6cb681ee29f740Hung-ying Tyan + incomingCallPendingIntent + ": " + listener); 1692d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang try { 1702d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang SipSessionGroupExt group = createGroup(localProfile, 171323d3671ac813df8dd173f3f4d6cb681ee29f740Hung-ying Tyan incomingCallPendingIntent, listener); 1722d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if (localProfile.getAutoRegistration()) { 1732d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang group.openToReceiveCalls(); 174c2bd6162eddad0cdfdafc037142e043680ffa705Chia-chi Yeh updateWakeLocks(); 1752d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 1762d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } catch (SipException e) { 1772d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang Log.e(TAG, "openToReceiveCalls()", e); 1782d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang // TODO: how to send the exception back 1792d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 1802d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 1812d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 1826a53489ae594d7cc373a00687d6ea2f23d0634dfHung-ying Tyan private boolean isCallerCreator(SipSessionGroupExt group) { 1836a53489ae594d7cc373a00687d6ea2f23d0634dfHung-ying Tyan SipProfile profile = group.getLocalProfile(); 1846a53489ae594d7cc373a00687d6ea2f23d0634dfHung-ying Tyan return (profile.getCallingUid() == Binder.getCallingUid()); 1856a53489ae594d7cc373a00687d6ea2f23d0634dfHung-ying Tyan } 1866a53489ae594d7cc373a00687d6ea2f23d0634dfHung-ying Tyan 1876a53489ae594d7cc373a00687d6ea2f23d0634dfHung-ying Tyan private boolean isCallerCreatorOrRadio(SipSessionGroupExt group) { 1886a53489ae594d7cc373a00687d6ea2f23d0634dfHung-ying Tyan return (isCallerRadio() || isCallerCreator(group)); 1896a53489ae594d7cc373a00687d6ea2f23d0634dfHung-ying Tyan } 1906a53489ae594d7cc373a00687d6ea2f23d0634dfHung-ying Tyan 1916a53489ae594d7cc373a00687d6ea2f23d0634dfHung-ying Tyan private boolean isCallerRadio() { 1926a53489ae594d7cc373a00687d6ea2f23d0634dfHung-ying Tyan return (Binder.getCallingUid() == Process.PHONE_UID); 1936a53489ae594d7cc373a00687d6ea2f23d0634dfHung-ying Tyan } 1946a53489ae594d7cc373a00687d6ea2f23d0634dfHung-ying Tyan 1952d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public synchronized void close(String localProfileUri) { 196aa562ffdb8f728569e6957b742f271eb7303f878Hung-ying Tyan mContext.enforceCallingOrSelfPermission( 197aa562ffdb8f728569e6957b742f271eb7303f878Hung-ying Tyan android.Manifest.permission.USE_SIP, null); 1986a53489ae594d7cc373a00687d6ea2f23d0634dfHung-ying Tyan SipSessionGroupExt group = mSipGroups.get(localProfileUri); 1996a53489ae594d7cc373a00687d6ea2f23d0634dfHung-ying Tyan if (group == null) return; 2006a53489ae594d7cc373a00687d6ea2f23d0634dfHung-ying Tyan if (!isCallerCreatorOrRadio(group)) { 201431bb2269532f2514861b908d5fafda8fa64da79Joe Onorato Log.w(TAG, "only creator or radio can close this profile"); 2026a53489ae594d7cc373a00687d6ea2f23d0634dfHung-ying Tyan return; 2032d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 2046a53489ae594d7cc373a00687d6ea2f23d0634dfHung-ying Tyan 2056a53489ae594d7cc373a00687d6ea2f23d0634dfHung-ying Tyan group = mSipGroups.remove(localProfileUri); 2066a53489ae594d7cc373a00687d6ea2f23d0634dfHung-ying Tyan notifyProfileRemoved(group.getLocalProfile()); 2076a53489ae594d7cc373a00687d6ea2f23d0634dfHung-ying Tyan group.close(); 208bd57eeafe034cf850225db403700b5dc5db5ebccHung-ying Tyan 209c2bd6162eddad0cdfdafc037142e043680ffa705Chia-chi Yeh updateWakeLocks(); 2102d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 2112d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 2122d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public synchronized boolean isOpened(String localProfileUri) { 213aa562ffdb8f728569e6957b742f271eb7303f878Hung-ying Tyan mContext.enforceCallingOrSelfPermission( 214aa562ffdb8f728569e6957b742f271eb7303f878Hung-ying Tyan android.Manifest.permission.USE_SIP, null); 2152d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang SipSessionGroupExt group = mSipGroups.get(localProfileUri); 2166a53489ae594d7cc373a00687d6ea2f23d0634dfHung-ying Tyan if (group == null) return false; 2176a53489ae594d7cc373a00687d6ea2f23d0634dfHung-ying Tyan if (isCallerCreatorOrRadio(group)) { 218262cdfca7a0940735d3a08779e2d01bfdf639294Hung-ying Tyan return true; 2196a53489ae594d7cc373a00687d6ea2f23d0634dfHung-ying Tyan } else { 220431bb2269532f2514861b908d5fafda8fa64da79Joe Onorato Log.w(TAG, "only creator or radio can query on the profile"); 2216a53489ae594d7cc373a00687d6ea2f23d0634dfHung-ying Tyan return false; 2226a53489ae594d7cc373a00687d6ea2f23d0634dfHung-ying Tyan } 2232d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 2242d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 2252d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public synchronized boolean isRegistered(String localProfileUri) { 226aa562ffdb8f728569e6957b742f271eb7303f878Hung-ying Tyan mContext.enforceCallingOrSelfPermission( 227aa562ffdb8f728569e6957b742f271eb7303f878Hung-ying Tyan android.Manifest.permission.USE_SIP, null); 2282d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang SipSessionGroupExt group = mSipGroups.get(localProfileUri); 2296a53489ae594d7cc373a00687d6ea2f23d0634dfHung-ying Tyan if (group == null) return false; 2306a53489ae594d7cc373a00687d6ea2f23d0634dfHung-ying Tyan if (isCallerCreatorOrRadio(group)) { 2316a53489ae594d7cc373a00687d6ea2f23d0634dfHung-ying Tyan return group.isRegistered(); 2326a53489ae594d7cc373a00687d6ea2f23d0634dfHung-ying Tyan } else { 233431bb2269532f2514861b908d5fafda8fa64da79Joe Onorato Log.w(TAG, "only creator or radio can query on the profile"); 2346a53489ae594d7cc373a00687d6ea2f23d0634dfHung-ying Tyan return false; 2356a53489ae594d7cc373a00687d6ea2f23d0634dfHung-ying Tyan } 2362d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 2372d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 2382d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public synchronized void setRegistrationListener(String localProfileUri, 2392d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang ISipSessionListener listener) { 240aa562ffdb8f728569e6957b742f271eb7303f878Hung-ying Tyan mContext.enforceCallingOrSelfPermission( 241aa562ffdb8f728569e6957b742f271eb7303f878Hung-ying Tyan android.Manifest.permission.USE_SIP, null); 2422d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang SipSessionGroupExt group = mSipGroups.get(localProfileUri); 2436a53489ae594d7cc373a00687d6ea2f23d0634dfHung-ying Tyan if (group == null) return; 2446a53489ae594d7cc373a00687d6ea2f23d0634dfHung-ying Tyan if (isCallerCreator(group)) { 2456a53489ae594d7cc373a00687d6ea2f23d0634dfHung-ying Tyan group.setListener(listener); 2466a53489ae594d7cc373a00687d6ea2f23d0634dfHung-ying Tyan } else { 247431bb2269532f2514861b908d5fafda8fa64da79Joe Onorato Log.w(TAG, "only creator can set listener on the profile"); 2486a53489ae594d7cc373a00687d6ea2f23d0634dfHung-ying Tyan } 2492d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 2502d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 2512d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public synchronized ISipSession createSession(SipProfile localProfile, 2522d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang ISipSessionListener listener) { 253aa562ffdb8f728569e6957b742f271eb7303f878Hung-ying Tyan mContext.enforceCallingOrSelfPermission( 254aa562ffdb8f728569e6957b742f271eb7303f878Hung-ying Tyan android.Manifest.permission.USE_SIP, null); 2555424c8dcacf1c227fe7deb0185510614122ab447Chung-yih Wang localProfile.setCallingUid(Binder.getCallingUid()); 256c2bd6162eddad0cdfdafc037142e043680ffa705Chia-chi Yeh if (mNetworkType == -1) return null; 2572d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang try { 2582d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang SipSessionGroupExt group = createGroup(localProfile); 2592d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return group.createSession(listener); 2602d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } catch (SipException e) { 261431bb2269532f2514861b908d5fafda8fa64da79Joe Onorato if (DEBUG) Log.d(TAG, "createSession()", e); 2622d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return null; 2632d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 2642d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 2652d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 2662d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public synchronized ISipSession getPendingSession(String callId) { 267aa562ffdb8f728569e6957b742f271eb7303f878Hung-ying Tyan mContext.enforceCallingOrSelfPermission( 268aa562ffdb8f728569e6957b742f271eb7303f878Hung-ying Tyan android.Manifest.permission.USE_SIP, null); 2692d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if (callId == null) return null; 2702d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return mPendingSessions.get(callId); 2712d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 2722d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 2732d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private String determineLocalIp() { 2742d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang try { 2752d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang DatagramSocket s = new DatagramSocket(); 2762d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang s.connect(InetAddress.getByName("192.168.1.1"), 80); 2772d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return s.getLocalAddress().getHostAddress(); 2782d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } catch (IOException e) { 279431bb2269532f2514861b908d5fafda8fa64da79Joe Onorato if (DEBUG) Log.d(TAG, "determineLocalIp()", e); 2802d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang // dont do anything; there should be a connectivity change going 2812d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return null; 2822d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 2832d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 2842d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 2852d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private SipSessionGroupExt createGroup(SipProfile localProfile) 2862d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang throws SipException { 2872d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang String key = localProfile.getUriString(); 2882d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang SipSessionGroupExt group = mSipGroups.get(key); 2892d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if (group == null) { 2902d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang group = new SipSessionGroupExt(localProfile, null, null); 2912d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mSipGroups.put(key, group); 2922d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang notifyProfileAdded(localProfile); 2936a53489ae594d7cc373a00687d6ea2f23d0634dfHung-ying Tyan } else if (!isCallerCreator(group)) { 2946a53489ae594d7cc373a00687d6ea2f23d0634dfHung-ying Tyan throw new SipException("only creator can access the profile"); 2952d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 2962d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return group; 2972d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 2982d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 2992d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private SipSessionGroupExt createGroup(SipProfile localProfile, 300323d3671ac813df8dd173f3f4d6cb681ee29f740Hung-ying Tyan PendingIntent incomingCallPendingIntent, 301323d3671ac813df8dd173f3f4d6cb681ee29f740Hung-ying Tyan ISipSessionListener listener) throws SipException { 3022d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang String key = localProfile.getUriString(); 3032d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang SipSessionGroupExt group = mSipGroups.get(key); 3042d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if (group != null) { 3056a53489ae594d7cc373a00687d6ea2f23d0634dfHung-ying Tyan if (!isCallerCreator(group)) { 3066a53489ae594d7cc373a00687d6ea2f23d0634dfHung-ying Tyan throw new SipException("only creator can access the profile"); 3076a53489ae594d7cc373a00687d6ea2f23d0634dfHung-ying Tyan } 308323d3671ac813df8dd173f3f4d6cb681ee29f740Hung-ying Tyan group.setIncomingCallPendingIntent(incomingCallPendingIntent); 3092d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang group.setListener(listener); 3102d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } else { 3112d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang group = new SipSessionGroupExt(localProfile, 312323d3671ac813df8dd173f3f4d6cb681ee29f740Hung-ying Tyan incomingCallPendingIntent, listener); 3132d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mSipGroups.put(key, group); 3142d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang notifyProfileAdded(localProfile); 3152d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 3162d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return group; 3172d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 3182d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 3192d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private void notifyProfileAdded(SipProfile localProfile) { 320c7510581b81d63536db7d46ca8533106c8cf57c6Hung-ying Tyan if (DEBUG) Log.d(TAG, "notify: profile added: " + localProfile); 32184a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan Intent intent = new Intent(SipManager.ACTION_SIP_ADD_PHONE); 32284a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan intent.putExtra(SipManager.EXTRA_LOCAL_URI, localProfile.getUriString()); 3232d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mContext.sendBroadcast(intent); 324c2bd6162eddad0cdfdafc037142e043680ffa705Chia-chi Yeh if (mSipGroups.size() == 1) { 325c2bd6162eddad0cdfdafc037142e043680ffa705Chia-chi Yeh registerReceivers(); 326c2bd6162eddad0cdfdafc037142e043680ffa705Chia-chi Yeh } 3272d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 3282d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 3292d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private void notifyProfileRemoved(SipProfile localProfile) { 330c7510581b81d63536db7d46ca8533106c8cf57c6Hung-ying Tyan if (DEBUG) Log.d(TAG, "notify: profile removed: " + localProfile); 33184a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan Intent intent = new Intent(SipManager.ACTION_SIP_REMOVE_PHONE); 33284a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan intent.putExtra(SipManager.EXTRA_LOCAL_URI, localProfile.getUriString()); 3332d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mContext.sendBroadcast(intent); 334c2bd6162eddad0cdfdafc037142e043680ffa705Chia-chi Yeh if (mSipGroups.size() == 0) { 335c2bd6162eddad0cdfdafc037142e043680ffa705Chia-chi Yeh unregisterReceivers(); 3362d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 3372d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 3382d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 339bb0a989c17cd6135c8d9c8566507521d4d927fe0Chung-yih Wang private void stopPortMappingMeasurement() { 340bb0a989c17cd6135c8d9c8566507521d4d927fe0Chung-yih Wang if (mIntervalMeasurementProcess != null) { 341bb0a989c17cd6135c8d9c8566507521d4d927fe0Chung-yih Wang mIntervalMeasurementProcess.stop(); 342bb0a989c17cd6135c8d9c8566507521d4d927fe0Chung-yih Wang mIntervalMeasurementProcess = null; 343bb0a989c17cd6135c8d9c8566507521d4d927fe0Chung-yih Wang } 344bb0a989c17cd6135c8d9c8566507521d4d927fe0Chung-yih Wang } 345bb0a989c17cd6135c8d9c8566507521d4d927fe0Chung-yih Wang 3464a267a9158a62010cd76ab93681586ea8e3d6015Hung-ying Tyan private void startPortMappingLifetimeMeasurement( 3474a267a9158a62010cd76ab93681586ea8e3d6015Hung-ying Tyan SipProfile localProfile) { 3489edfa107575b5905c9ae0a2fa0d6f0cc19595300Hung-ying Tyan startPortMappingLifetimeMeasurement(localProfile, 3499edfa107575b5905c9ae0a2fa0d6f0cc19595300Hung-ying Tyan DEFAULT_MAX_KEEPALIVE_INTERVAL); 350e65f3a896f03bba5327ce4f3989c0422855450caHung-ying Tyan } 351e65f3a896f03bba5327ce4f3989c0422855450caHung-ying Tyan 352e65f3a896f03bba5327ce4f3989c0422855450caHung-ying Tyan private void startPortMappingLifetimeMeasurement( 353e65f3a896f03bba5327ce4f3989c0422855450caHung-ying Tyan SipProfile localProfile, int maxInterval) { 3544a267a9158a62010cd76ab93681586ea8e3d6015Hung-ying Tyan if ((mIntervalMeasurementProcess == null) 3554a267a9158a62010cd76ab93681586ea8e3d6015Hung-ying Tyan && (mKeepAliveInterval == -1) 3564a267a9158a62010cd76ab93681586ea8e3d6015Hung-ying Tyan && isBehindNAT(mLocalIp)) { 3574a267a9158a62010cd76ab93681586ea8e3d6015Hung-ying Tyan Log.d(TAG, "start NAT port mapping timeout measurement on " 3584a267a9158a62010cd76ab93681586ea8e3d6015Hung-ying Tyan + localProfile.getUriString()); 3594a267a9158a62010cd76ab93681586ea8e3d6015Hung-ying Tyan 3609edfa107575b5905c9ae0a2fa0d6f0cc19595300Hung-ying Tyan int minInterval = mLastGoodKeepAliveInterval; 3619edfa107575b5905c9ae0a2fa0d6f0cc19595300Hung-ying Tyan if (minInterval >= maxInterval) { 3629edfa107575b5905c9ae0a2fa0d6f0cc19595300Hung-ying Tyan // If mLastGoodKeepAliveInterval also does not work, reset it 3639edfa107575b5905c9ae0a2fa0d6f0cc19595300Hung-ying Tyan // to the default min 3649edfa107575b5905c9ae0a2fa0d6f0cc19595300Hung-ying Tyan minInterval = mLastGoodKeepAliveInterval 3659edfa107575b5905c9ae0a2fa0d6f0cc19595300Hung-ying Tyan = DEFAULT_KEEPALIVE_INTERVAL; 3669edfa107575b5905c9ae0a2fa0d6f0cc19595300Hung-ying Tyan Log.d(TAG, " reset min interval to " + minInterval); 3679edfa107575b5905c9ae0a2fa0d6f0cc19595300Hung-ying Tyan } 3689edfa107575b5905c9ae0a2fa0d6f0cc19595300Hung-ying Tyan mIntervalMeasurementProcess = new IntervalMeasurementProcess( 3699edfa107575b5905c9ae0a2fa0d6f0cc19595300Hung-ying Tyan localProfile, minInterval, maxInterval); 3704a267a9158a62010cd76ab93681586ea8e3d6015Hung-ying Tyan mIntervalMeasurementProcess.start(); 3714a267a9158a62010cd76ab93681586ea8e3d6015Hung-ying Tyan } 372bb0a989c17cd6135c8d9c8566507521d4d927fe0Chung-yih Wang } 373bb0a989c17cd6135c8d9c8566507521d4d927fe0Chung-yih Wang 374e65f3a896f03bba5327ce4f3989c0422855450caHung-ying Tyan private void restartPortMappingLifetimeMeasurement( 375e65f3a896f03bba5327ce4f3989c0422855450caHung-ying Tyan SipProfile localProfile, int maxInterval) { 376e65f3a896f03bba5327ce4f3989c0422855450caHung-ying Tyan stopPortMappingMeasurement(); 377e65f3a896f03bba5327ce4f3989c0422855450caHung-ying Tyan mKeepAliveInterval = -1; 378e65f3a896f03bba5327ce4f3989c0422855450caHung-ying Tyan startPortMappingLifetimeMeasurement(localProfile, maxInterval); 379e65f3a896f03bba5327ce4f3989c0422855450caHung-ying Tyan } 380e65f3a896f03bba5327ce4f3989c0422855450caHung-ying Tyan 3812d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private synchronized void addPendingSession(ISipSession session) { 3822d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang try { 38360c45d026907edbe340c8cf9e1723b3dd34f8b6aHung-ying Tyan cleanUpPendingSessions(); 3842d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mPendingSessions.put(session.getCallId(), session); 38560c45d026907edbe340c8cf9e1723b3dd34f8b6aHung-ying Tyan if (DEBUG) Log.d(TAG, "#pending sess=" + mPendingSessions.size()); 3862d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } catch (RemoteException e) { 3872d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang // should not happen with a local call 3882d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang Log.e(TAG, "addPendingSession()", e); 3892d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 3902d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 3912d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 39260c45d026907edbe340c8cf9e1723b3dd34f8b6aHung-ying Tyan private void cleanUpPendingSessions() throws RemoteException { 39360c45d026907edbe340c8cf9e1723b3dd34f8b6aHung-ying Tyan Map.Entry<String, ISipSession>[] entries = 39460c45d026907edbe340c8cf9e1723b3dd34f8b6aHung-ying Tyan mPendingSessions.entrySet().toArray( 39560c45d026907edbe340c8cf9e1723b3dd34f8b6aHung-ying Tyan new Map.Entry[mPendingSessions.size()]); 39660c45d026907edbe340c8cf9e1723b3dd34f8b6aHung-ying Tyan for (Map.Entry<String, ISipSession> entry : entries) { 39760c45d026907edbe340c8cf9e1723b3dd34f8b6aHung-ying Tyan if (entry.getValue().getState() != SipSession.State.INCOMING_CALL) { 39860c45d026907edbe340c8cf9e1723b3dd34f8b6aHung-ying Tyan mPendingSessions.remove(entry.getKey()); 39960c45d026907edbe340c8cf9e1723b3dd34f8b6aHung-ying Tyan } 40060c45d026907edbe340c8cf9e1723b3dd34f8b6aHung-ying Tyan } 40160c45d026907edbe340c8cf9e1723b3dd34f8b6aHung-ying Tyan } 40260c45d026907edbe340c8cf9e1723b3dd34f8b6aHung-ying Tyan 4030a6e717fb6846f66b8dc853e079f2166307bfc60Hung-ying Tyan private synchronized boolean callingSelf(SipSessionGroupExt ringingGroup, 4040a6e717fb6846f66b8dc853e079f2166307bfc60Hung-ying Tyan SipSessionGroup.SipSessionImpl ringingSession) { 4050a6e717fb6846f66b8dc853e079f2166307bfc60Hung-ying Tyan String callId = ringingSession.getCallId(); 4060a6e717fb6846f66b8dc853e079f2166307bfc60Hung-ying Tyan for (SipSessionGroupExt group : mSipGroups.values()) { 4070a6e717fb6846f66b8dc853e079f2166307bfc60Hung-ying Tyan if ((group != ringingGroup) && group.containsSession(callId)) { 4080a6e717fb6846f66b8dc853e079f2166307bfc60Hung-ying Tyan if (DEBUG) Log.d(TAG, "call self: " 4090a6e717fb6846f66b8dc853e079f2166307bfc60Hung-ying Tyan + ringingSession.getLocalProfile().getUriString() 4100a6e717fb6846f66b8dc853e079f2166307bfc60Hung-ying Tyan + " -> " + group.getLocalProfile().getUriString()); 4110a6e717fb6846f66b8dc853e079f2166307bfc60Hung-ying Tyan return true; 4120a6e717fb6846f66b8dc853e079f2166307bfc60Hung-ying Tyan } 4130a6e717fb6846f66b8dc853e079f2166307bfc60Hung-ying Tyan } 4140a6e717fb6846f66b8dc853e079f2166307bfc60Hung-ying Tyan return false; 4150a6e717fb6846f66b8dc853e079f2166307bfc60Hung-ying Tyan } 4160a6e717fb6846f66b8dc853e079f2166307bfc60Hung-ying Tyan 4174a267a9158a62010cd76ab93681586ea8e3d6015Hung-ying Tyan private synchronized void onKeepAliveIntervalChanged() { 4184a267a9158a62010cd76ab93681586ea8e3d6015Hung-ying Tyan for (SipSessionGroupExt group : mSipGroups.values()) { 4194a267a9158a62010cd76ab93681586ea8e3d6015Hung-ying Tyan group.onKeepAliveIntervalChanged(); 4204a267a9158a62010cd76ab93681586ea8e3d6015Hung-ying Tyan } 4214a267a9158a62010cd76ab93681586ea8e3d6015Hung-ying Tyan } 4224a267a9158a62010cd76ab93681586ea8e3d6015Hung-ying Tyan 4234a267a9158a62010cd76ab93681586ea8e3d6015Hung-ying Tyan private int getKeepAliveInterval() { 4244a267a9158a62010cd76ab93681586ea8e3d6015Hung-ying Tyan return (mKeepAliveInterval < 0) 4259edfa107575b5905c9ae0a2fa0d6f0cc19595300Hung-ying Tyan ? mLastGoodKeepAliveInterval 4264a267a9158a62010cd76ab93681586ea8e3d6015Hung-ying Tyan : mKeepAliveInterval; 4274a267a9158a62010cd76ab93681586ea8e3d6015Hung-ying Tyan } 4284a267a9158a62010cd76ab93681586ea8e3d6015Hung-ying Tyan 4294a267a9158a62010cd76ab93681586ea8e3d6015Hung-ying Tyan private boolean isBehindNAT(String address) { 4304a267a9158a62010cd76ab93681586ea8e3d6015Hung-ying Tyan try { 4314a267a9158a62010cd76ab93681586ea8e3d6015Hung-ying Tyan byte[] d = InetAddress.getByName(address).getAddress(); 4324a267a9158a62010cd76ab93681586ea8e3d6015Hung-ying Tyan if ((d[0] == 10) || 4334a267a9158a62010cd76ab93681586ea8e3d6015Hung-ying Tyan (((0x000000FF & ((int)d[0])) == 172) && 4344a267a9158a62010cd76ab93681586ea8e3d6015Hung-ying Tyan ((0x000000F0 & ((int)d[1])) == 16)) || 4354a267a9158a62010cd76ab93681586ea8e3d6015Hung-ying Tyan (((0x000000FF & ((int)d[0])) == 192) && 4364a267a9158a62010cd76ab93681586ea8e3d6015Hung-ying Tyan ((0x000000FF & ((int)d[1])) == 168))) { 4374a267a9158a62010cd76ab93681586ea8e3d6015Hung-ying Tyan return true; 4384a267a9158a62010cd76ab93681586ea8e3d6015Hung-ying Tyan } 4394a267a9158a62010cd76ab93681586ea8e3d6015Hung-ying Tyan } catch (UnknownHostException e) { 4404a267a9158a62010cd76ab93681586ea8e3d6015Hung-ying Tyan Log.e(TAG, "isBehindAT()" + address, e); 4414a267a9158a62010cd76ab93681586ea8e3d6015Hung-ying Tyan } 4424a267a9158a62010cd76ab93681586ea8e3d6015Hung-ying Tyan return false; 4434a267a9158a62010cd76ab93681586ea8e3d6015Hung-ying Tyan } 4440a6e717fb6846f66b8dc853e079f2166307bfc60Hung-ying Tyan 4452d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private class SipSessionGroupExt extends SipSessionAdapter { 4462d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private SipSessionGroup mSipGroup; 447323d3671ac813df8dd173f3f4d6cb681ee29f740Hung-ying Tyan private PendingIntent mIncomingCallPendingIntent; 448262cdfca7a0940735d3a08779e2d01bfdf639294Hung-ying Tyan private boolean mOpenedToReceiveCalls; 4492d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 4502d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private AutoRegistrationProcess mAutoRegistration = 4512d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang new AutoRegistrationProcess(); 4522d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 4532d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public SipSessionGroupExt(SipProfile localProfile, 454323d3671ac813df8dd173f3f4d6cb681ee29f740Hung-ying Tyan PendingIntent incomingCallPendingIntent, 4552d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang ISipSessionListener listener) throws SipException { 4562dd9134c6b2da47f4816bc0f72a0e4924aca4f84Chia-chi Yeh mSipGroup = new SipSessionGroup(duplicate(localProfile), 4572dd9134c6b2da47f4816bc0f72a0e4924aca4f84Chia-chi Yeh localProfile.getPassword(), mTimer, mMyWakeLock); 458323d3671ac813df8dd173f3f4d6cb681ee29f740Hung-ying Tyan mIncomingCallPendingIntent = incomingCallPendingIntent; 4592d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mAutoRegistration.setListener(listener); 4602d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 4612d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 4622d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public SipProfile getLocalProfile() { 4632d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return mSipGroup.getLocalProfile(); 4642d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 4652d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 4660a6e717fb6846f66b8dc853e079f2166307bfc60Hung-ying Tyan public boolean containsSession(String callId) { 4670a6e717fb6846f66b8dc853e079f2166307bfc60Hung-ying Tyan return mSipGroup.containsSession(callId); 4680a6e717fb6846f66b8dc853e079f2166307bfc60Hung-ying Tyan } 4690a6e717fb6846f66b8dc853e079f2166307bfc60Hung-ying Tyan 4704a267a9158a62010cd76ab93681586ea8e3d6015Hung-ying Tyan public void onKeepAliveIntervalChanged() { 4714a267a9158a62010cd76ab93681586ea8e3d6015Hung-ying Tyan mAutoRegistration.onKeepAliveIntervalChanged(); 4724a267a9158a62010cd76ab93681586ea8e3d6015Hung-ying Tyan } 4734a267a9158a62010cd76ab93681586ea8e3d6015Hung-ying Tyan 4744a267a9158a62010cd76ab93681586ea8e3d6015Hung-ying Tyan // TODO: remove this method once SipWakeupTimer can better handle variety 4754a267a9158a62010cd76ab93681586ea8e3d6015Hung-ying Tyan // of timeout values 4764a267a9158a62010cd76ab93681586ea8e3d6015Hung-ying Tyan void setWakeupTimer(SipWakeupTimer timer) { 4774a267a9158a62010cd76ab93681586ea8e3d6015Hung-ying Tyan mSipGroup.setWakeupTimer(timer); 4784a267a9158a62010cd76ab93681586ea8e3d6015Hung-ying Tyan } 4794a267a9158a62010cd76ab93681586ea8e3d6015Hung-ying Tyan 4802d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private SipProfile duplicate(SipProfile p) { 4812d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang try { 4825424c8dcacf1c227fe7deb0185510614122ab447Chung-yih Wang return new SipProfile.Builder(p).setPassword("*").build(); 4832d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } catch (Exception e) { 4842d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang Log.wtf(TAG, "duplicate()", e); 4852d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang throw new RuntimeException("duplicate profile", e); 4862d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 4872d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 4882d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 4892d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public void setListener(ISipSessionListener listener) { 4902d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mAutoRegistration.setListener(listener); 4912d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 4922d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 493323d3671ac813df8dd173f3f4d6cb681ee29f740Hung-ying Tyan public void setIncomingCallPendingIntent(PendingIntent pIntent) { 494323d3671ac813df8dd173f3f4d6cb681ee29f740Hung-ying Tyan mIncomingCallPendingIntent = pIntent; 4952d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 4962d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 4972d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public void openToReceiveCalls() throws SipException { 498262cdfca7a0940735d3a08779e2d01bfdf639294Hung-ying Tyan mOpenedToReceiveCalls = true; 499c2bd6162eddad0cdfdafc037142e043680ffa705Chia-chi Yeh if (mNetworkType != -1) { 5002d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mSipGroup.openToReceiveCalls(this); 5012d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mAutoRegistration.start(mSipGroup); 5022d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 503c7510581b81d63536db7d46ca8533106c8cf57c6Hung-ying Tyan if (DEBUG) Log.d(TAG, " openToReceiveCalls: " + getUri() + ": " 504323d3671ac813df8dd173f3f4d6cb681ee29f740Hung-ying Tyan + mIncomingCallPendingIntent); 5052d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 5062d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 5072d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public void onConnectivityChanged(boolean connected) 5082d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang throws SipException { 509d231aa880ab006d51ffe03454c1fc082f1c97bb8Hung-ying Tyan mSipGroup.onConnectivityChanged(); 5102d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if (connected) { 5112dd9134c6b2da47f4816bc0f72a0e4924aca4f84Chia-chi Yeh mSipGroup.reset(); 512262cdfca7a0940735d3a08779e2d01bfdf639294Hung-ying Tyan if (mOpenedToReceiveCalls) openToReceiveCalls(); 5132d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } else { 514262cdfca7a0940735d3a08779e2d01bfdf639294Hung-ying Tyan // close mSipGroup but remember mOpenedToReceiveCalls 515c7510581b81d63536db7d46ca8533106c8cf57c6Hung-ying Tyan if (DEBUG) Log.d(TAG, " close auto reg temporarily: " 516323d3671ac813df8dd173f3f4d6cb681ee29f740Hung-ying Tyan + getUri() + ": " + mIncomingCallPendingIntent); 5172d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mSipGroup.close(); 5182d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mAutoRegistration.stop(); 5192d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 5202d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 5212d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 522fc51f2c972c7a3a829f556c4c19f16c60c87d7e7Hung-ying Tyan public void close() { 523262cdfca7a0940735d3a08779e2d01bfdf639294Hung-ying Tyan mOpenedToReceiveCalls = false; 524fc51f2c972c7a3a829f556c4c19f16c60c87d7e7Hung-ying Tyan mSipGroup.close(); 5252d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mAutoRegistration.stop(); 526c7510581b81d63536db7d46ca8533106c8cf57c6Hung-ying Tyan if (DEBUG) Log.d(TAG, " close: " + getUri() + ": " 527323d3671ac813df8dd173f3f4d6cb681ee29f740Hung-ying Tyan + mIncomingCallPendingIntent); 5282d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 5292d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 5302d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public ISipSession createSession(ISipSessionListener listener) { 5312d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return mSipGroup.createSession(listener); 5322d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 5332d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 5342d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang @Override 535323d3671ac813df8dd173f3f4d6cb681ee29f740Hung-ying Tyan public void onRinging(ISipSession s, SipProfile caller, 53695b15c35608fe3ea679c8a478c6cbd841623371eChia-chi Yeh String sessionDescription) { 537cb6ee06f62c20ae036a206667097f20b837b11abChia-chi Yeh if (DEBUG) Log.d(TAG, "<<<<< onRinging()"); 538323d3671ac813df8dd173f3f4d6cb681ee29f740Hung-ying Tyan SipSessionGroup.SipSessionImpl session = 539323d3671ac813df8dd173f3f4d6cb681ee29f740Hung-ying Tyan (SipSessionGroup.SipSessionImpl) s; 5402d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang synchronized (SipService.this) { 5412d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang try { 5420a6e717fb6846f66b8dc853e079f2166307bfc60Hung-ying Tyan if (!isRegistered() || callingSelf(this, session)) { 5432d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang session.endCall(); 5442d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return; 5452d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 5462d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 5472d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang // send out incoming call broadcast 5482d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang addPendingSession(session); 5492d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang Intent intent = SipManager.createIncomingCallBroadcast( 550323d3671ac813df8dd173f3f4d6cb681ee29f740Hung-ying Tyan session.getCallId(), sessionDescription); 551c7510581b81d63536db7d46ca8533106c8cf57c6Hung-ying Tyan if (DEBUG) Log.d(TAG, " ringing~~ " + getUri() + ": " 552c7510581b81d63536db7d46ca8533106c8cf57c6Hung-ying Tyan + caller.getUri() + ": " + session.getCallId() 553323d3671ac813df8dd173f3f4d6cb681ee29f740Hung-ying Tyan + " " + mIncomingCallPendingIntent); 554323d3671ac813df8dd173f3f4d6cb681ee29f740Hung-ying Tyan mIncomingCallPendingIntent.send(mContext, 555323d3671ac813df8dd173f3f4d6cb681ee29f740Hung-ying Tyan SipManager.INCOMING_CALL_RESULT_CODE, intent); 556323d3671ac813df8dd173f3f4d6cb681ee29f740Hung-ying Tyan } catch (PendingIntent.CanceledException e) { 557323d3671ac813df8dd173f3f4d6cb681ee29f740Hung-ying Tyan Log.w(TAG, "pendingIntent is canceled, drop incoming call"); 558323d3671ac813df8dd173f3f4d6cb681ee29f740Hung-ying Tyan session.endCall(); 5592d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 5602d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 5612d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 5622d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 5632d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang @Override 56497963794af1e18674dd111e3ad344d90b16c922cHung-ying Tyan public void onError(ISipSession session, int errorCode, 5652d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang String message) { 56697963794af1e18674dd111e3ad344d90b16c922cHung-ying Tyan if (DEBUG) Log.d(TAG, "sip session error: " 56797963794af1e18674dd111e3ad344d90b16c922cHung-ying Tyan + SipErrorCode.toString(errorCode) + ": " + message); 5682d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 5692d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 570262cdfca7a0940735d3a08779e2d01bfdf639294Hung-ying Tyan public boolean isOpenedToReceiveCalls() { 571262cdfca7a0940735d3a08779e2d01bfdf639294Hung-ying Tyan return mOpenedToReceiveCalls; 5722d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 5732d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 5742d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public boolean isRegistered() { 5752d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return mAutoRegistration.isRegistered(); 5762d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 5772d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 5782d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private String getUri() { 5792d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return mSipGroup.getLocalProfileUri(); 5802d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 5812d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 5822d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 583129d0b08fdf9588f7c8feeb9db3def30973c092eHung-ying Tyan private class IntervalMeasurementProcess implements Runnable, 5844a267a9158a62010cd76ab93681586ea8e3d6015Hung-ying Tyan SipSessionGroup.KeepAliveProcessCallback { 5854a267a9158a62010cd76ab93681586ea8e3d6015Hung-ying Tyan private static final String TAG = "SipKeepAliveInterval"; 586129d0b08fdf9588f7c8feeb9db3def30973c092eHung-ying Tyan private static final int MIN_INTERVAL = 5; // in seconds 5874a267a9158a62010cd76ab93681586ea8e3d6015Hung-ying Tyan private static final int PASS_THRESHOLD = 10; 588e65f3a896f03bba5327ce4f3989c0422855450caHung-ying Tyan private static final int MAX_RETRY_COUNT = 5; 589129d0b08fdf9588f7c8feeb9db3def30973c092eHung-ying Tyan private static final int NAT_MEASUREMENT_RETRY_INTERVAL = 120; // in seconds 590d17b6d526648c372be761097e55c19767d5dba7dChia-chi Yeh private SipProfile mLocalProfile; 591bb0a989c17cd6135c8d9c8566507521d4d927fe0Chung-yih Wang private SipSessionGroupExt mGroup; 592bb0a989c17cd6135c8d9c8566507521d4d927fe0Chung-yih Wang private SipSessionGroup.SipSessionImpl mSession; 5939edfa107575b5905c9ae0a2fa0d6f0cc19595300Hung-ying Tyan private int mMinInterval; 594e65f3a896f03bba5327ce4f3989c0422855450caHung-ying Tyan private int mMaxInterval; 595e65f3a896f03bba5327ce4f3989c0422855450caHung-ying Tyan private int mInterval; 596d17b6d526648c372be761097e55c19767d5dba7dChia-chi Yeh private int mPassCount; 597e65f3a896f03bba5327ce4f3989c0422855450caHung-ying Tyan 5989edfa107575b5905c9ae0a2fa0d6f0cc19595300Hung-ying Tyan public IntervalMeasurementProcess(SipProfile localProfile, 5999edfa107575b5905c9ae0a2fa0d6f0cc19595300Hung-ying Tyan int minInterval, int maxInterval) { 6009edfa107575b5905c9ae0a2fa0d6f0cc19595300Hung-ying Tyan mMaxInterval = maxInterval; 6019edfa107575b5905c9ae0a2fa0d6f0cc19595300Hung-ying Tyan mMinInterval = minInterval; 602d17b6d526648c372be761097e55c19767d5dba7dChia-chi Yeh mLocalProfile = localProfile; 603bb0a989c17cd6135c8d9c8566507521d4d927fe0Chung-yih Wang } 604bb0a989c17cd6135c8d9c8566507521d4d927fe0Chung-yih Wang 605bb0a989c17cd6135c8d9c8566507521d4d927fe0Chung-yih Wang public void start() { 6064a267a9158a62010cd76ab93681586ea8e3d6015Hung-ying Tyan synchronized (SipService.this) { 607d17b6d526648c372be761097e55c19767d5dba7dChia-chi Yeh if (mSession != null) { 608d17b6d526648c372be761097e55c19767d5dba7dChia-chi Yeh return; 609129d0b08fdf9588f7c8feeb9db3def30973c092eHung-ying Tyan } 610d17b6d526648c372be761097e55c19767d5dba7dChia-chi Yeh 611d17b6d526648c372be761097e55c19767d5dba7dChia-chi Yeh mInterval = (mMaxInterval + mMinInterval) / 2; 612d17b6d526648c372be761097e55c19767d5dba7dChia-chi Yeh mPassCount = 0; 613d17b6d526648c372be761097e55c19767d5dba7dChia-chi Yeh 614d17b6d526648c372be761097e55c19767d5dba7dChia-chi Yeh // Don't start measurement if the interval is too small 615d17b6d526648c372be761097e55c19767d5dba7dChia-chi Yeh if (mInterval < DEFAULT_KEEPALIVE_INTERVAL || checkTermination()) { 616d17b6d526648c372be761097e55c19767d5dba7dChia-chi Yeh Log.w(TAG, "measurement aborted; interval=[" + 617d17b6d526648c372be761097e55c19767d5dba7dChia-chi Yeh mMinInterval + "," + mMaxInterval + "]"); 618d17b6d526648c372be761097e55c19767d5dba7dChia-chi Yeh return; 619d17b6d526648c372be761097e55c19767d5dba7dChia-chi Yeh } 620d17b6d526648c372be761097e55c19767d5dba7dChia-chi Yeh 6214a267a9158a62010cd76ab93681586ea8e3d6015Hung-ying Tyan try { 622d17b6d526648c372be761097e55c19767d5dba7dChia-chi Yeh Log.d(TAG, "start measurement w interval=" + mInterval); 623d17b6d526648c372be761097e55c19767d5dba7dChia-chi Yeh 624d17b6d526648c372be761097e55c19767d5dba7dChia-chi Yeh mGroup = new SipSessionGroupExt(mLocalProfile, null, null); 625d17b6d526648c372be761097e55c19767d5dba7dChia-chi Yeh // TODO: remove this line once SipWakeupTimer can better handle 626d17b6d526648c372be761097e55c19767d5dba7dChia-chi Yeh // variety of timeout values 627d17b6d526648c372be761097e55c19767d5dba7dChia-chi Yeh mGroup.setWakeupTimer(new SipWakeupTimer(mContext, mExecutor)); 628d17b6d526648c372be761097e55c19767d5dba7dChia-chi Yeh 629d17b6d526648c372be761097e55c19767d5dba7dChia-chi Yeh mSession = (SipSessionGroup.SipSessionImpl) 630d17b6d526648c372be761097e55c19767d5dba7dChia-chi Yeh mGroup.createSession(null); 6314a267a9158a62010cd76ab93681586ea8e3d6015Hung-ying Tyan mSession.startKeepAliveProcess(mInterval, this); 632d17b6d526648c372be761097e55c19767d5dba7dChia-chi Yeh } catch (Throwable t) { 633d17b6d526648c372be761097e55c19767d5dba7dChia-chi Yeh onError(SipErrorCode.CLIENT_ERROR, t.toString()); 6344a267a9158a62010cd76ab93681586ea8e3d6015Hung-ying Tyan } 6354a267a9158a62010cd76ab93681586ea8e3d6015Hung-ying Tyan } 636bb0a989c17cd6135c8d9c8566507521d4d927fe0Chung-yih Wang } 637bb0a989c17cd6135c8d9c8566507521d4d927fe0Chung-yih Wang 638bb0a989c17cd6135c8d9c8566507521d4d927fe0Chung-yih Wang public void stop() { 6394a267a9158a62010cd76ab93681586ea8e3d6015Hung-ying Tyan synchronized (SipService.this) { 640129d0b08fdf9588f7c8feeb9db3def30973c092eHung-ying Tyan if (mSession != null) { 641129d0b08fdf9588f7c8feeb9db3def30973c092eHung-ying Tyan mSession.stopKeepAliveProcess(); 642129d0b08fdf9588f7c8feeb9db3def30973c092eHung-ying Tyan mSession = null; 643129d0b08fdf9588f7c8feeb9db3def30973c092eHung-ying Tyan } 644d17b6d526648c372be761097e55c19767d5dba7dChia-chi Yeh if (mGroup != null) { 645d17b6d526648c372be761097e55c19767d5dba7dChia-chi Yeh mGroup.close(); 646d17b6d526648c372be761097e55c19767d5dba7dChia-chi Yeh mGroup = null; 647d17b6d526648c372be761097e55c19767d5dba7dChia-chi Yeh } 648129d0b08fdf9588f7c8feeb9db3def30973c092eHung-ying Tyan mTimer.cancel(this); 649bb0a989c17cd6135c8d9c8566507521d4d927fe0Chung-yih Wang } 650bb0a989c17cd6135c8d9c8566507521d4d927fe0Chung-yih Wang } 651bb0a989c17cd6135c8d9c8566507521d4d927fe0Chung-yih Wang 6524a267a9158a62010cd76ab93681586ea8e3d6015Hung-ying Tyan private void restart() { 653bb0a989c17cd6135c8d9c8566507521d4d927fe0Chung-yih Wang synchronized (SipService.this) { 654129d0b08fdf9588f7c8feeb9db3def30973c092eHung-ying Tyan // Return immediately if the measurement process is stopped 655129d0b08fdf9588f7c8feeb9db3def30973c092eHung-ying Tyan if (mSession == null) return; 656129d0b08fdf9588f7c8feeb9db3def30973c092eHung-ying Tyan 657129d0b08fdf9588f7c8feeb9db3def30973c092eHung-ying Tyan Log.d(TAG, "restart measurement w interval=" + mInterval); 658bb0a989c17cd6135c8d9c8566507521d4d927fe0Chung-yih Wang try { 6594a267a9158a62010cd76ab93681586ea8e3d6015Hung-ying Tyan mSession.stopKeepAliveProcess(); 660129d0b08fdf9588f7c8feeb9db3def30973c092eHung-ying Tyan mPassCount = 0; 6614a267a9158a62010cd76ab93681586ea8e3d6015Hung-ying Tyan mSession.startKeepAliveProcess(mInterval, this); 6624a267a9158a62010cd76ab93681586ea8e3d6015Hung-ying Tyan } catch (SipException e) { 6634a267a9158a62010cd76ab93681586ea8e3d6015Hung-ying Tyan Log.e(TAG, "restart()", e); 664bb0a989c17cd6135c8d9c8566507521d4d927fe0Chung-yih Wang } 665bb0a989c17cd6135c8d9c8566507521d4d927fe0Chung-yih Wang } 666bb0a989c17cd6135c8d9c8566507521d4d927fe0Chung-yih Wang } 667bb0a989c17cd6135c8d9c8566507521d4d927fe0Chung-yih Wang 6689edfa107575b5905c9ae0a2fa0d6f0cc19595300Hung-ying Tyan private boolean checkTermination() { 6699edfa107575b5905c9ae0a2fa0d6f0cc19595300Hung-ying Tyan return ((mMaxInterval - mMinInterval) < MIN_INTERVAL); 6709edfa107575b5905c9ae0a2fa0d6f0cc19595300Hung-ying Tyan } 6719edfa107575b5905c9ae0a2fa0d6f0cc19595300Hung-ying Tyan 6724a267a9158a62010cd76ab93681586ea8e3d6015Hung-ying Tyan // SipSessionGroup.KeepAliveProcessCallback 6734a267a9158a62010cd76ab93681586ea8e3d6015Hung-ying Tyan @Override 6744a267a9158a62010cd76ab93681586ea8e3d6015Hung-ying Tyan public void onResponse(boolean portChanged) { 6752d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang synchronized (SipService.this) { 6764a267a9158a62010cd76ab93681586ea8e3d6015Hung-ying Tyan if (!portChanged) { 677e65f3a896f03bba5327ce4f3989c0422855450caHung-ying Tyan if (++mPassCount != PASS_THRESHOLD) return; 6784a267a9158a62010cd76ab93681586ea8e3d6015Hung-ying Tyan // update the interval, since the current interval is good to 6794a267a9158a62010cd76ab93681586ea8e3d6015Hung-ying Tyan // keep the port mapping. 6809edfa107575b5905c9ae0a2fa0d6f0cc19595300Hung-ying Tyan if (mKeepAliveInterval > 0) { 6819edfa107575b5905c9ae0a2fa0d6f0cc19595300Hung-ying Tyan mLastGoodKeepAliveInterval = mKeepAliveInterval; 6829edfa107575b5905c9ae0a2fa0d6f0cc19595300Hung-ying Tyan } 6834a267a9158a62010cd76ab93681586ea8e3d6015Hung-ying Tyan mKeepAliveInterval = mMinInterval = mInterval; 6844a267a9158a62010cd76ab93681586ea8e3d6015Hung-ying Tyan if (DEBUG) { 6854a267a9158a62010cd76ab93681586ea8e3d6015Hung-ying Tyan Log.d(TAG, "measured good keepalive interval: " 6864a267a9158a62010cd76ab93681586ea8e3d6015Hung-ying Tyan + mKeepAliveInterval); 687bd57eeafe034cf850225db403700b5dc5db5ebccHung-ying Tyan } 6884a267a9158a62010cd76ab93681586ea8e3d6015Hung-ying Tyan onKeepAliveIntervalChanged(); 6894a267a9158a62010cd76ab93681586ea8e3d6015Hung-ying Tyan } else { 6904a267a9158a62010cd76ab93681586ea8e3d6015Hung-ying Tyan // Since the rport is changed, shorten the interval. 6914a267a9158a62010cd76ab93681586ea8e3d6015Hung-ying Tyan mMaxInterval = mInterval; 6924a267a9158a62010cd76ab93681586ea8e3d6015Hung-ying Tyan } 6939edfa107575b5905c9ae0a2fa0d6f0cc19595300Hung-ying Tyan if (checkTermination()) { 6944a267a9158a62010cd76ab93681586ea8e3d6015Hung-ying Tyan // update mKeepAliveInterval and stop measurement. 6954a267a9158a62010cd76ab93681586ea8e3d6015Hung-ying Tyan stop(); 6969edfa107575b5905c9ae0a2fa0d6f0cc19595300Hung-ying Tyan // If all the measurements failed, we still set it to 6979edfa107575b5905c9ae0a2fa0d6f0cc19595300Hung-ying Tyan // mMinInterval; If mMinInterval still doesn't work, a new 6989edfa107575b5905c9ae0a2fa0d6f0cc19595300Hung-ying Tyan // measurement with min interval=DEFAULT_KEEPALIVE_INTERVAL 6999edfa107575b5905c9ae0a2fa0d6f0cc19595300Hung-ying Tyan // will be conducted. 7004a267a9158a62010cd76ab93681586ea8e3d6015Hung-ying Tyan mKeepAliveInterval = mMinInterval; 7014a267a9158a62010cd76ab93681586ea8e3d6015Hung-ying Tyan if (DEBUG) { 7024a267a9158a62010cd76ab93681586ea8e3d6015Hung-ying Tyan Log.d(TAG, "measured keepalive interval: " 7034a267a9158a62010cd76ab93681586ea8e3d6015Hung-ying Tyan + mKeepAliveInterval); 704bb0a989c17cd6135c8d9c8566507521d4d927fe0Chung-yih Wang } 7054a267a9158a62010cd76ab93681586ea8e3d6015Hung-ying Tyan } else { 7064a267a9158a62010cd76ab93681586ea8e3d6015Hung-ying Tyan // calculate the new interval and continue. 7074a267a9158a62010cd76ab93681586ea8e3d6015Hung-ying Tyan mInterval = (mMaxInterval + mMinInterval) / 2; 7084a267a9158a62010cd76ab93681586ea8e3d6015Hung-ying Tyan if (DEBUG) { 7094a267a9158a62010cd76ab93681586ea8e3d6015Hung-ying Tyan Log.d(TAG, "current interval: " + mKeepAliveInterval 7104a267a9158a62010cd76ab93681586ea8e3d6015Hung-ying Tyan + ", test new interval: " + mInterval); 7114a267a9158a62010cd76ab93681586ea8e3d6015Hung-ying Tyan } 7124a267a9158a62010cd76ab93681586ea8e3d6015Hung-ying Tyan restart(); 7132d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 7142d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 7152d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 7162d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 7174a267a9158a62010cd76ab93681586ea8e3d6015Hung-ying Tyan // SipSessionGroup.KeepAliveProcessCallback 7184a267a9158a62010cd76ab93681586ea8e3d6015Hung-ying Tyan @Override 7194a267a9158a62010cd76ab93681586ea8e3d6015Hung-ying Tyan public void onError(int errorCode, String description) { 720129d0b08fdf9588f7c8feeb9db3def30973c092eHung-ying Tyan Log.w(TAG, "interval measurement error: " + description); 721129d0b08fdf9588f7c8feeb9db3def30973c092eHung-ying Tyan restartLater(); 722129d0b08fdf9588f7c8feeb9db3def30973c092eHung-ying Tyan } 723129d0b08fdf9588f7c8feeb9db3def30973c092eHung-ying Tyan 724129d0b08fdf9588f7c8feeb9db3def30973c092eHung-ying Tyan // timeout handler 725129d0b08fdf9588f7c8feeb9db3def30973c092eHung-ying Tyan @Override 726129d0b08fdf9588f7c8feeb9db3def30973c092eHung-ying Tyan public void run() { 727129d0b08fdf9588f7c8feeb9db3def30973c092eHung-ying Tyan mTimer.cancel(this); 728129d0b08fdf9588f7c8feeb9db3def30973c092eHung-ying Tyan restart(); 729129d0b08fdf9588f7c8feeb9db3def30973c092eHung-ying Tyan } 730129d0b08fdf9588f7c8feeb9db3def30973c092eHung-ying Tyan 731129d0b08fdf9588f7c8feeb9db3def30973c092eHung-ying Tyan private void restartLater() { 7324a267a9158a62010cd76ab93681586ea8e3d6015Hung-ying Tyan synchronized (SipService.this) { 733129d0b08fdf9588f7c8feeb9db3def30973c092eHung-ying Tyan int interval = NAT_MEASUREMENT_RETRY_INTERVAL; 734129d0b08fdf9588f7c8feeb9db3def30973c092eHung-ying Tyan mTimer.cancel(this); 735129d0b08fdf9588f7c8feeb9db3def30973c092eHung-ying Tyan mTimer.set(interval * 1000, this); 7364a267a9158a62010cd76ab93681586ea8e3d6015Hung-ying Tyan } 7372d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 7382d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 7392d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 7402d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private class AutoRegistrationProcess extends SipSessionAdapter 7414a267a9158a62010cd76ab93681586ea8e3d6015Hung-ying Tyan implements Runnable, SipSessionGroup.KeepAliveProcessCallback { 742129d0b08fdf9588f7c8feeb9db3def30973c092eHung-ying Tyan private static final int MIN_KEEPALIVE_SUCCESS_COUNT = 10; 743cb6ee06f62c20ae036a206667097f20b837b11abChia-chi Yeh private String TAG = "SipAutoReg"; 744129d0b08fdf9588f7c8feeb9db3def30973c092eHung-ying Tyan 7452d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private SipSessionGroup.SipSessionImpl mSession; 7464a267a9158a62010cd76ab93681586ea8e3d6015Hung-ying Tyan private SipSessionGroup.SipSessionImpl mKeepAliveSession; 7472d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private SipSessionListenerProxy mProxy = new SipSessionListenerProxy(); 7482d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private int mBackoff = 1; 7492d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private boolean mRegistered; 7502d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private long mExpiryTime; 75197963794af1e18674dd111e3ad344d90b16c922cHung-ying Tyan private int mErrorCode; 7523d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan private String mErrorMessage; 753fb3a98b1d8d0ad040980d509c4c5341928b9460bHung-ying Tyan private boolean mRunning = false; 7542d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 755129d0b08fdf9588f7c8feeb9db3def30973c092eHung-ying Tyan private int mKeepAliveSuccessCount = 0; 756129d0b08fdf9588f7c8feeb9db3def30973c092eHung-ying Tyan 7572d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private String getAction() { 7582d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return toString(); 7592d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 7602d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 7612d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public void start(SipSessionGroup group) { 762fb3a98b1d8d0ad040980d509c4c5341928b9460bHung-ying Tyan if (!mRunning) { 763fb3a98b1d8d0ad040980d509c4c5341928b9460bHung-ying Tyan mRunning = true; 7642d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mBackoff = 1; 7652d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mSession = (SipSessionGroup.SipSessionImpl) 7662d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang group.createSession(this); 7672d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang // return right away if no active network connection. 7682d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if (mSession == null) return; 7692d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 7702d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang // start unregistration to clear up old registration at server 7712d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang // TODO: when rfc5626 is deployed, use reg-id and sip.instance 7722d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang // in registration to avoid adding duplicate entries to server 773bd57eeafe034cf850225db403700b5dc5db5ebccHung-ying Tyan mMyWakeLock.acquire(mSession); 7742d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mSession.unregister(); 775cb6ee06f62c20ae036a206667097f20b837b11abChia-chi Yeh TAG = "SipAutoReg:" + mSession.getLocalProfile().getUriString(); 7762d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 7772d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 7782d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 779129d0b08fdf9588f7c8feeb9db3def30973c092eHung-ying Tyan private void startKeepAliveProcess(int interval) { 780cb6ee06f62c20ae036a206667097f20b837b11abChia-chi Yeh if (DEBUG) Log.d(TAG, "start keepalive w interval=" + interval); 781129d0b08fdf9588f7c8feeb9db3def30973c092eHung-ying Tyan if (mKeepAliveSession == null) { 782129d0b08fdf9588f7c8feeb9db3def30973c092eHung-ying Tyan mKeepAliveSession = mSession.duplicate(); 783129d0b08fdf9588f7c8feeb9db3def30973c092eHung-ying Tyan } else { 784129d0b08fdf9588f7c8feeb9db3def30973c092eHung-ying Tyan mKeepAliveSession.stopKeepAliveProcess(); 785129d0b08fdf9588f7c8feeb9db3def30973c092eHung-ying Tyan } 786129d0b08fdf9588f7c8feeb9db3def30973c092eHung-ying Tyan try { 787129d0b08fdf9588f7c8feeb9db3def30973c092eHung-ying Tyan mKeepAliveSession.startKeepAliveProcess(interval, this); 788129d0b08fdf9588f7c8feeb9db3def30973c092eHung-ying Tyan } catch (SipException e) { 789129d0b08fdf9588f7c8feeb9db3def30973c092eHung-ying Tyan Log.e(TAG, "failed to start keepalive w interval=" + interval, 790129d0b08fdf9588f7c8feeb9db3def30973c092eHung-ying Tyan e); 791129d0b08fdf9588f7c8feeb9db3def30973c092eHung-ying Tyan } 792129d0b08fdf9588f7c8feeb9db3def30973c092eHung-ying Tyan } 793129d0b08fdf9588f7c8feeb9db3def30973c092eHung-ying Tyan 794129d0b08fdf9588f7c8feeb9db3def30973c092eHung-ying Tyan private void stopKeepAliveProcess() { 795129d0b08fdf9588f7c8feeb9db3def30973c092eHung-ying Tyan if (mKeepAliveSession != null) { 796129d0b08fdf9588f7c8feeb9db3def30973c092eHung-ying Tyan mKeepAliveSession.stopKeepAliveProcess(); 797129d0b08fdf9588f7c8feeb9db3def30973c092eHung-ying Tyan mKeepAliveSession = null; 798129d0b08fdf9588f7c8feeb9db3def30973c092eHung-ying Tyan } 799129d0b08fdf9588f7c8feeb9db3def30973c092eHung-ying Tyan mKeepAliveSuccessCount = 0; 800129d0b08fdf9588f7c8feeb9db3def30973c092eHung-ying Tyan } 801129d0b08fdf9588f7c8feeb9db3def30973c092eHung-ying Tyan 8024a267a9158a62010cd76ab93681586ea8e3d6015Hung-ying Tyan // SipSessionGroup.KeepAliveProcessCallback 8034a267a9158a62010cd76ab93681586ea8e3d6015Hung-ying Tyan @Override 8044a267a9158a62010cd76ab93681586ea8e3d6015Hung-ying Tyan public void onResponse(boolean portChanged) { 8054a267a9158a62010cd76ab93681586ea8e3d6015Hung-ying Tyan synchronized (SipService.this) { 806e65f3a896f03bba5327ce4f3989c0422855450caHung-ying Tyan if (portChanged) { 807129d0b08fdf9588f7c8feeb9db3def30973c092eHung-ying Tyan int interval = getKeepAliveInterval(); 808129d0b08fdf9588f7c8feeb9db3def30973c092eHung-ying Tyan if (mKeepAliveSuccessCount < MIN_KEEPALIVE_SUCCESS_COUNT) { 809129d0b08fdf9588f7c8feeb9db3def30973c092eHung-ying Tyan Log.i(TAG, "keepalive doesn't work with interval " 810129d0b08fdf9588f7c8feeb9db3def30973c092eHung-ying Tyan + interval + ", past success count=" 811129d0b08fdf9588f7c8feeb9db3def30973c092eHung-ying Tyan + mKeepAliveSuccessCount); 812129d0b08fdf9588f7c8feeb9db3def30973c092eHung-ying Tyan if (interval > DEFAULT_KEEPALIVE_INTERVAL) { 813129d0b08fdf9588f7c8feeb9db3def30973c092eHung-ying Tyan restartPortMappingLifetimeMeasurement( 814129d0b08fdf9588f7c8feeb9db3def30973c092eHung-ying Tyan mSession.getLocalProfile(), interval); 815129d0b08fdf9588f7c8feeb9db3def30973c092eHung-ying Tyan mKeepAliveSuccessCount = 0; 816129d0b08fdf9588f7c8feeb9db3def30973c092eHung-ying Tyan } 817129d0b08fdf9588f7c8feeb9db3def30973c092eHung-ying Tyan } else { 818cb6ee06f62c20ae036a206667097f20b837b11abChia-chi Yeh if (DEBUG) { 819cb6ee06f62c20ae036a206667097f20b837b11abChia-chi Yeh Log.i(TAG, "keep keepalive going with interval " 820cb6ee06f62c20ae036a206667097f20b837b11abChia-chi Yeh + interval + ", past success count=" 821cb6ee06f62c20ae036a206667097f20b837b11abChia-chi Yeh + mKeepAliveSuccessCount); 822cb6ee06f62c20ae036a206667097f20b837b11abChia-chi Yeh } 823129d0b08fdf9588f7c8feeb9db3def30973c092eHung-ying Tyan mKeepAliveSuccessCount /= 2; 824129d0b08fdf9588f7c8feeb9db3def30973c092eHung-ying Tyan } 825e65f3a896f03bba5327ce4f3989c0422855450caHung-ying Tyan } else { 826e65f3a896f03bba5327ce4f3989c0422855450caHung-ying Tyan // Start keep-alive interval measurement on the first 827e65f3a896f03bba5327ce4f3989c0422855450caHung-ying Tyan // successfully kept-alive SipSessionGroup 828e65f3a896f03bba5327ce4f3989c0422855450caHung-ying Tyan startPortMappingLifetimeMeasurement( 829e65f3a896f03bba5327ce4f3989c0422855450caHung-ying Tyan mSession.getLocalProfile()); 830129d0b08fdf9588f7c8feeb9db3def30973c092eHung-ying Tyan mKeepAliveSuccessCount++; 831e65f3a896f03bba5327ce4f3989c0422855450caHung-ying Tyan } 8324a267a9158a62010cd76ab93681586ea8e3d6015Hung-ying Tyan 8334a267a9158a62010cd76ab93681586ea8e3d6015Hung-ying Tyan if (!mRunning || !portChanged) return; 83412750701d0f90ed0166f5ddcf588c1235efe830aHung-ying Tyan 83512750701d0f90ed0166f5ddcf588c1235efe830aHung-ying Tyan // The keep alive process is stopped when port is changed; 83612750701d0f90ed0166f5ddcf588c1235efe830aHung-ying Tyan // Nullify the session so that the process can be restarted 83712750701d0f90ed0166f5ddcf588c1235efe830aHung-ying Tyan // again when the re-registration is done 83812750701d0f90ed0166f5ddcf588c1235efe830aHung-ying Tyan mKeepAliveSession = null; 83912750701d0f90ed0166f5ddcf588c1235efe830aHung-ying Tyan 8404a267a9158a62010cd76ab93681586ea8e3d6015Hung-ying Tyan // Acquire wake lock for the registration process. The 8414a267a9158a62010cd76ab93681586ea8e3d6015Hung-ying Tyan // lock will be released when registration is complete. 8424a267a9158a62010cd76ab93681586ea8e3d6015Hung-ying Tyan mMyWakeLock.acquire(mSession); 8434a267a9158a62010cd76ab93681586ea8e3d6015Hung-ying Tyan mSession.register(EXPIRY_TIME); 8444a267a9158a62010cd76ab93681586ea8e3d6015Hung-ying Tyan } 8454a267a9158a62010cd76ab93681586ea8e3d6015Hung-ying Tyan } 8464a267a9158a62010cd76ab93681586ea8e3d6015Hung-ying Tyan 8474a267a9158a62010cd76ab93681586ea8e3d6015Hung-ying Tyan // SipSessionGroup.KeepAliveProcessCallback 8484a267a9158a62010cd76ab93681586ea8e3d6015Hung-ying Tyan @Override 8494a267a9158a62010cd76ab93681586ea8e3d6015Hung-ying Tyan public void onError(int errorCode, String description) { 850cb6ee06f62c20ae036a206667097f20b837b11abChia-chi Yeh if (DEBUG) { 851cb6ee06f62c20ae036a206667097f20b837b11abChia-chi Yeh Log.e(TAG, "keepalive error: " + description); 852cb6ee06f62c20ae036a206667097f20b837b11abChia-chi Yeh } 853e65f3a896f03bba5327ce4f3989c0422855450caHung-ying Tyan onResponse(true); // re-register immediately 8544a267a9158a62010cd76ab93681586ea8e3d6015Hung-ying Tyan } 8554a267a9158a62010cd76ab93681586ea8e3d6015Hung-ying Tyan 8562d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public void stop() { 857fb3a98b1d8d0ad040980d509c4c5341928b9460bHung-ying Tyan if (!mRunning) return; 858fb3a98b1d8d0ad040980d509c4c5341928b9460bHung-ying Tyan mRunning = false; 859bd57eeafe034cf850225db403700b5dc5db5ebccHung-ying Tyan mMyWakeLock.release(mSession); 860bd57eeafe034cf850225db403700b5dc5db5ebccHung-ying Tyan if (mSession != null) { 861bd57eeafe034cf850225db403700b5dc5db5ebccHung-ying Tyan mSession.setListener(null); 862c2bd6162eddad0cdfdafc037142e043680ffa705Chia-chi Yeh if (mNetworkType != -1 && mRegistered) mSession.unregister(); 863bd57eeafe034cf850225db403700b5dc5db5ebccHung-ying Tyan } 864fb3a98b1d8d0ad040980d509c4c5341928b9460bHung-ying Tyan 8652d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mTimer.cancel(this); 866129d0b08fdf9588f7c8feeb9db3def30973c092eHung-ying Tyan stopKeepAliveProcess(); 8672d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 868fb3a98b1d8d0ad040980d509c4c5341928b9460bHung-ying Tyan mRegistered = false; 869fb3a98b1d8d0ad040980d509c4c5341928b9460bHung-ying Tyan setListener(mProxy.getListener()); 8702d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 8712d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 8724a267a9158a62010cd76ab93681586ea8e3d6015Hung-ying Tyan public void onKeepAliveIntervalChanged() { 8734a267a9158a62010cd76ab93681586ea8e3d6015Hung-ying Tyan if (mKeepAliveSession != null) { 8744a267a9158a62010cd76ab93681586ea8e3d6015Hung-ying Tyan int newInterval = getKeepAliveInterval(); 875cb6ee06f62c20ae036a206667097f20b837b11abChia-chi Yeh if (DEBUG) { 8764a267a9158a62010cd76ab93681586ea8e3d6015Hung-ying Tyan Log.v(TAG, "restart keepalive w interval=" + newInterval); 8774a267a9158a62010cd76ab93681586ea8e3d6015Hung-ying Tyan } 878129d0b08fdf9588f7c8feeb9db3def30973c092eHung-ying Tyan mKeepAliveSuccessCount = 0; 879129d0b08fdf9588f7c8feeb9db3def30973c092eHung-ying Tyan startKeepAliveProcess(newInterval); 8804a267a9158a62010cd76ab93681586ea8e3d6015Hung-ying Tyan } 8814a267a9158a62010cd76ab93681586ea8e3d6015Hung-ying Tyan } 8824a267a9158a62010cd76ab93681586ea8e3d6015Hung-ying Tyan 8832d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public void setListener(ISipSessionListener listener) { 8843d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan synchronized (SipService.this) { 8853d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan mProxy.setListener(listener); 8862d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 8873d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan try { 88897963794af1e18674dd111e3ad344d90b16c922cHung-ying Tyan int state = (mSession == null) 88984a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan ? SipSession.State.READY_TO_CALL 89097963794af1e18674dd111e3ad344d90b16c922cHung-ying Tyan : mSession.getState(); 89184a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan if ((state == SipSession.State.REGISTERING) 89284a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan || (state == SipSession.State.DEREGISTERING)) { 8933d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan mProxy.onRegistering(mSession); 8943d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan } else if (mRegistered) { 8953d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan int duration = (int) 8963d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan (mExpiryTime - SystemClock.elapsedRealtime()); 8973d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan mProxy.onRegistrationDone(mSession, duration); 89897963794af1e18674dd111e3ad344d90b16c922cHung-ying Tyan } else if (mErrorCode != SipErrorCode.NO_ERROR) { 8993d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan if (mErrorCode == SipErrorCode.TIME_OUT) { 9003d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan mProxy.onRegistrationTimeout(mSession); 9013d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan } else { 90297963794af1e18674dd111e3ad344d90b16c922cHung-ying Tyan mProxy.onRegistrationFailed(mSession, mErrorCode, 90397963794af1e18674dd111e3ad344d90b16c922cHung-ying Tyan mErrorMessage); 9043d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan } 905c2bd6162eddad0cdfdafc037142e043680ffa705Chia-chi Yeh } else if (mNetworkType == -1) { 906fb3a98b1d8d0ad040980d509c4c5341928b9460bHung-ying Tyan mProxy.onRegistrationFailed(mSession, 907fb3a98b1d8d0ad040980d509c4c5341928b9460bHung-ying Tyan SipErrorCode.DATA_CONNECTION_LOST, 908fb3a98b1d8d0ad040980d509c4c5341928b9460bHung-ying Tyan "no data connection"); 909fb3a98b1d8d0ad040980d509c4c5341928b9460bHung-ying Tyan } else if (!mRunning) { 910fb3a98b1d8d0ad040980d509c4c5341928b9460bHung-ying Tyan mProxy.onRegistrationFailed(mSession, 911fb3a98b1d8d0ad040980d509c4c5341928b9460bHung-ying Tyan SipErrorCode.CLIENT_ERROR, 912fb3a98b1d8d0ad040980d509c4c5341928b9460bHung-ying Tyan "registration not running"); 913fb3a98b1d8d0ad040980d509c4c5341928b9460bHung-ying Tyan } else { 914fb3a98b1d8d0ad040980d509c4c5341928b9460bHung-ying Tyan mProxy.onRegistrationFailed(mSession, 915fb3a98b1d8d0ad040980d509c4c5341928b9460bHung-ying Tyan SipErrorCode.IN_PROGRESS, 916fb3a98b1d8d0ad040980d509c4c5341928b9460bHung-ying Tyan String.valueOf(state)); 9173d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan } 9183d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan } catch (Throwable t) { 9193d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan Log.w(TAG, "setListener(): " + t); 9202d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 9212d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 9222d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 9232d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 9242d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public boolean isRegistered() { 9252d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return mRegistered; 9262d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 9272d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 928bd57eeafe034cf850225db403700b5dc5db5ebccHung-ying Tyan // timeout handler: re-register 9294a267a9158a62010cd76ab93681586ea8e3d6015Hung-ying Tyan @Override 9302d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public void run() { 931fb3a98b1d8d0ad040980d509c4c5341928b9460bHung-ying Tyan synchronized (SipService.this) { 932fb3a98b1d8d0ad040980d509c4c5341928b9460bHung-ying Tyan if (!mRunning) return; 933fb3a98b1d8d0ad040980d509c4c5341928b9460bHung-ying Tyan 934fb3a98b1d8d0ad040980d509c4c5341928b9460bHung-ying Tyan mErrorCode = SipErrorCode.NO_ERROR; 935fb3a98b1d8d0ad040980d509c4c5341928b9460bHung-ying Tyan mErrorMessage = null; 9364a267a9158a62010cd76ab93681586ea8e3d6015Hung-ying Tyan if (DEBUG) Log.d(TAG, "registering"); 937c2bd6162eddad0cdfdafc037142e043680ffa705Chia-chi Yeh if (mNetworkType != -1) { 938bd57eeafe034cf850225db403700b5dc5db5ebccHung-ying Tyan mMyWakeLock.acquire(mSession); 939bd57eeafe034cf850225db403700b5dc5db5ebccHung-ying Tyan mSession.register(EXPIRY_TIME); 940bd57eeafe034cf850225db403700b5dc5db5ebccHung-ying Tyan } 9412d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 9422d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 9432d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 9442d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private void restart(int duration) { 945cb6ee06f62c20ae036a206667097f20b837b11abChia-chi Yeh Log.d(TAG, "Refresh registration " + duration + "s later."); 9462d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mTimer.cancel(this); 9472d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mTimer.set(duration * 1000, this); 9482d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 9492d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 9502d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private int backoffDuration() { 9512d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang int duration = SHORT_EXPIRY_TIME * mBackoff; 9522d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if (duration > 3600) { 9532d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang duration = 3600; 9542d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } else { 9552d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mBackoff *= 2; 9562d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 9572d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return duration; 9582d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 9592d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 9602d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang @Override 9612d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public void onRegistering(ISipSession session) { 962c7510581b81d63536db7d46ca8533106c8cf57c6Hung-ying Tyan if (DEBUG) Log.d(TAG, "onRegistering(): " + session); 9632d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang synchronized (SipService.this) { 964fb3a98b1d8d0ad040980d509c4c5341928b9460bHung-ying Tyan if (notCurrentSession(session)) return; 965fb3a98b1d8d0ad040980d509c4c5341928b9460bHung-ying Tyan 9662d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mRegistered = false; 9673d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan mProxy.onRegistering(session); 9682d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 9692d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 9702d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 971fb3a98b1d8d0ad040980d509c4c5341928b9460bHung-ying Tyan private boolean notCurrentSession(ISipSession session) { 972fb3a98b1d8d0ad040980d509c4c5341928b9460bHung-ying Tyan if (session != mSession) { 973fb3a98b1d8d0ad040980d509c4c5341928b9460bHung-ying Tyan ((SipSessionGroup.SipSessionImpl) session).setListener(null); 974bd57eeafe034cf850225db403700b5dc5db5ebccHung-ying Tyan mMyWakeLock.release(session); 975fb3a98b1d8d0ad040980d509c4c5341928b9460bHung-ying Tyan return true; 976fb3a98b1d8d0ad040980d509c4c5341928b9460bHung-ying Tyan } 977fb3a98b1d8d0ad040980d509c4c5341928b9460bHung-ying Tyan return !mRunning; 978fb3a98b1d8d0ad040980d509c4c5341928b9460bHung-ying Tyan } 979fb3a98b1d8d0ad040980d509c4c5341928b9460bHung-ying Tyan 9802d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang @Override 9812d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public void onRegistrationDone(ISipSession session, int duration) { 982c7510581b81d63536db7d46ca8533106c8cf57c6Hung-ying Tyan if (DEBUG) Log.d(TAG, "onRegistrationDone(): " + session); 9832d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang synchronized (SipService.this) { 984fb3a98b1d8d0ad040980d509c4c5341928b9460bHung-ying Tyan if (notCurrentSession(session)) return; 9853d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan 9863d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan mProxy.onRegistrationDone(session, duration); 9873d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan 9882d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if (duration > 0) { 9892d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mExpiryTime = SystemClock.elapsedRealtime() 9902d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang + (duration * 1000); 9912d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 9922d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if (!mRegistered) { 9932d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mRegistered = true; 9942d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang // allow some overlap to avoid call drop during renew 9952d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang duration -= MIN_EXPIRY_TIME; 9962d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if (duration < MIN_EXPIRY_TIME) { 9972d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang duration = MIN_EXPIRY_TIME; 9982d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 9992d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang restart(duration); 10002d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 10014a267a9158a62010cd76ab93681586ea8e3d6015Hung-ying Tyan SipProfile localProfile = mSession.getLocalProfile(); 10024a267a9158a62010cd76ab93681586ea8e3d6015Hung-ying Tyan if ((mKeepAliveSession == null) && (isBehindNAT(mLocalIp) 10034a267a9158a62010cd76ab93681586ea8e3d6015Hung-ying Tyan || localProfile.getSendKeepAlive())) { 1004129d0b08fdf9588f7c8feeb9db3def30973c092eHung-ying Tyan startKeepAliveProcess(getKeepAliveInterval()); 10052d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 10062d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 1007bd57eeafe034cf850225db403700b5dc5db5ebccHung-ying Tyan mMyWakeLock.release(session); 10082d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } else { 10092d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mRegistered = false; 10102d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mExpiryTime = -1L; 1011c7510581b81d63536db7d46ca8533106c8cf57c6Hung-ying Tyan if (DEBUG) Log.d(TAG, "Refresh registration immediately"); 10122d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang run(); 10132d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 10142d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 10152d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 10162d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 10172d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang @Override 101897963794af1e18674dd111e3ad344d90b16c922cHung-ying Tyan public void onRegistrationFailed(ISipSession session, int errorCode, 101997963794af1e18674dd111e3ad344d90b16c922cHung-ying Tyan String message) { 1020c7510581b81d63536db7d46ca8533106c8cf57c6Hung-ying Tyan if (DEBUG) Log.d(TAG, "onRegistrationFailed(): " + session + ": " 102197963794af1e18674dd111e3ad344d90b16c922cHung-ying Tyan + SipErrorCode.toString(errorCode) + ": " + message); 10222d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang synchronized (SipService.this) { 1023fb3a98b1d8d0ad040980d509c4c5341928b9460bHung-ying Tyan if (notCurrentSession(session)) return; 10243d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan 1025ee8a884f3504c981be8a1d6888b4590a0a394e05Hung-ying Tyan switch (errorCode) { 1026ee8a884f3504c981be8a1d6888b4590a0a394e05Hung-ying Tyan case SipErrorCode.INVALID_CREDENTIALS: 1027ee8a884f3504c981be8a1d6888b4590a0a394e05Hung-ying Tyan case SipErrorCode.SERVER_UNREACHABLE: 1028ee8a884f3504c981be8a1d6888b4590a0a394e05Hung-ying Tyan if (DEBUG) Log.d(TAG, " pause auto-registration"); 1029ee8a884f3504c981be8a1d6888b4590a0a394e05Hung-ying Tyan stop(); 1030685b61b7117dbae94c5ceb5de4546ad23a4d3d0fHung-ying Tyan break; 1031ee8a884f3504c981be8a1d6888b4590a0a394e05Hung-ying Tyan default: 1032ee8a884f3504c981be8a1d6888b4590a0a394e05Hung-ying Tyan restartLater(); 10332d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 1034fb3a98b1d8d0ad040980d509c4c5341928b9460bHung-ying Tyan 1035fb3a98b1d8d0ad040980d509c4c5341928b9460bHung-ying Tyan mErrorCode = errorCode; 1036fb3a98b1d8d0ad040980d509c4c5341928b9460bHung-ying Tyan mErrorMessage = message; 1037fb3a98b1d8d0ad040980d509c4c5341928b9460bHung-ying Tyan mProxy.onRegistrationFailed(session, errorCode, message); 1038bd57eeafe034cf850225db403700b5dc5db5ebccHung-ying Tyan mMyWakeLock.release(session); 10392d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 10402d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 10412d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 10422d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang @Override 10432d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public void onRegistrationTimeout(ISipSession session) { 1044c7510581b81d63536db7d46ca8533106c8cf57c6Hung-ying Tyan if (DEBUG) Log.d(TAG, "onRegistrationTimeout(): " + session); 10452d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang synchronized (SipService.this) { 1046fb3a98b1d8d0ad040980d509c4c5341928b9460bHung-ying Tyan if (notCurrentSession(session)) return; 1047fb3a98b1d8d0ad040980d509c4c5341928b9460bHung-ying Tyan 10483d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan mErrorCode = SipErrorCode.TIME_OUT; 10493d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan mProxy.onRegistrationTimeout(session); 1050ee8a884f3504c981be8a1d6888b4590a0a394e05Hung-ying Tyan restartLater(); 1051bd57eeafe034cf850225db403700b5dc5db5ebccHung-ying Tyan mMyWakeLock.release(session); 10522d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 10532d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 10542d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 1055ee8a884f3504c981be8a1d6888b4590a0a394e05Hung-ying Tyan private void restartLater() { 10562d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mRegistered = false; 10572d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang restart(backoffDuration()); 10582d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 10592d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 10602d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 10612d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private class ConnectivityReceiver extends BroadcastReceiver { 10622d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang @Override 1063ee59e6a9fc69241b286acb7b55a22b8393c81222Chia-chi Yeh public void onReceive(Context context, Intent intent) { 1064ee59e6a9fc69241b286acb7b55a22b8393c81222Chia-chi Yeh Bundle bundle = intent.getExtras(); 1065ee59e6a9fc69241b286acb7b55a22b8393c81222Chia-chi Yeh if (bundle != null) { 1066ee59e6a9fc69241b286acb7b55a22b8393c81222Chia-chi Yeh final NetworkInfo info = (NetworkInfo) 1067ee59e6a9fc69241b286acb7b55a22b8393c81222Chia-chi Yeh bundle.get(ConnectivityManager.EXTRA_NETWORK_INFO); 1068c4b87477c076d61062950becc132b7483e3fb198Hung-ying Tyan 1069ee59e6a9fc69241b286acb7b55a22b8393c81222Chia-chi Yeh // Run the handler in MyExecutor to be protected by wake lock 1070ee59e6a9fc69241b286acb7b55a22b8393c81222Chia-chi Yeh mExecutor.execute(new Runnable() { 1071ee59e6a9fc69241b286acb7b55a22b8393c81222Chia-chi Yeh public void run() { 1072ee59e6a9fc69241b286acb7b55a22b8393c81222Chia-chi Yeh onConnectivityChanged(info); 10732d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 1074ee59e6a9fc69241b286acb7b55a22b8393c81222Chia-chi Yeh }); 10752d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 10762d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 1077ee59e6a9fc69241b286acb7b55a22b8393c81222Chia-chi Yeh } 1078ee59e6a9fc69241b286acb7b55a22b8393c81222Chia-chi Yeh 1079ee59e6a9fc69241b286acb7b55a22b8393c81222Chia-chi Yeh private void registerReceivers() { 1080ee59e6a9fc69241b286acb7b55a22b8393c81222Chia-chi Yeh mContext.registerReceiver(mConnectivityReceiver, 1081ee59e6a9fc69241b286acb7b55a22b8393c81222Chia-chi Yeh new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION)); 1082ee59e6a9fc69241b286acb7b55a22b8393c81222Chia-chi Yeh if (DEBUG) Log.d(TAG, " +++ register receivers"); 1083ee59e6a9fc69241b286acb7b55a22b8393c81222Chia-chi Yeh } 10842d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 1085ee59e6a9fc69241b286acb7b55a22b8393c81222Chia-chi Yeh private void unregisterReceivers() { 1086ee59e6a9fc69241b286acb7b55a22b8393c81222Chia-chi Yeh mContext.unregisterReceiver(mConnectivityReceiver); 1087ee59e6a9fc69241b286acb7b55a22b8393c81222Chia-chi Yeh if (DEBUG) Log.d(TAG, " --- unregister receivers"); 1088ee59e6a9fc69241b286acb7b55a22b8393c81222Chia-chi Yeh 1089ee59e6a9fc69241b286acb7b55a22b8393c81222Chia-chi Yeh // Reset variables maintained by ConnectivityReceiver. 1090ee59e6a9fc69241b286acb7b55a22b8393c81222Chia-chi Yeh mWifiLock.release(); 1091c2bd6162eddad0cdfdafc037142e043680ffa705Chia-chi Yeh mNetworkType = -1; 1092c2bd6162eddad0cdfdafc037142e043680ffa705Chia-chi Yeh } 1093c2bd6162eddad0cdfdafc037142e043680ffa705Chia-chi Yeh 1094c2bd6162eddad0cdfdafc037142e043680ffa705Chia-chi Yeh private void updateWakeLocks() { 1095c2bd6162eddad0cdfdafc037142e043680ffa705Chia-chi Yeh for (SipSessionGroupExt group : mSipGroups.values()) { 1096c2bd6162eddad0cdfdafc037142e043680ffa705Chia-chi Yeh if (group.isOpenedToReceiveCalls()) { 1097c2bd6162eddad0cdfdafc037142e043680ffa705Chia-chi Yeh // Also grab the WifiLock when we are disconnected, so the 1098c2bd6162eddad0cdfdafc037142e043680ffa705Chia-chi Yeh // system will keep trying to reconnect. It will be released 1099c2bd6162eddad0cdfdafc037142e043680ffa705Chia-chi Yeh // when the system eventually connects to something else. 1100c2bd6162eddad0cdfdafc037142e043680ffa705Chia-chi Yeh if (mNetworkType == ConnectivityManager.TYPE_WIFI || mNetworkType == -1) { 1101c2bd6162eddad0cdfdafc037142e043680ffa705Chia-chi Yeh mWifiLock.acquire(); 1102c2bd6162eddad0cdfdafc037142e043680ffa705Chia-chi Yeh } else { 1103c2bd6162eddad0cdfdafc037142e043680ffa705Chia-chi Yeh mWifiLock.release(); 1104c2bd6162eddad0cdfdafc037142e043680ffa705Chia-chi Yeh } 1105c2bd6162eddad0cdfdafc037142e043680ffa705Chia-chi Yeh return; 1106c2bd6162eddad0cdfdafc037142e043680ffa705Chia-chi Yeh } 1107c2bd6162eddad0cdfdafc037142e043680ffa705Chia-chi Yeh } 1108c2bd6162eddad0cdfdafc037142e043680ffa705Chia-chi Yeh mWifiLock.release(); 1109c2bd6162eddad0cdfdafc037142e043680ffa705Chia-chi Yeh mMyWakeLock.reset(); // in case there's a leak 1110ee59e6a9fc69241b286acb7b55a22b8393c81222Chia-chi Yeh } 1111ee59e6a9fc69241b286acb7b55a22b8393c81222Chia-chi Yeh 1112ee59e6a9fc69241b286acb7b55a22b8393c81222Chia-chi Yeh private synchronized void onConnectivityChanged(NetworkInfo info) { 1113ee59e6a9fc69241b286acb7b55a22b8393c81222Chia-chi Yeh // We only care about the default network, and getActiveNetworkInfo() 1114ee59e6a9fc69241b286acb7b55a22b8393c81222Chia-chi Yeh // is the only way to distinguish them. However, as broadcasts are 1115ee59e6a9fc69241b286acb7b55a22b8393c81222Chia-chi Yeh // delivered asynchronously, we might miss DISCONNECTED events from 1116ee59e6a9fc69241b286acb7b55a22b8393c81222Chia-chi Yeh // getActiveNetworkInfo(), which is critical to our SIP stack. To 1117ee59e6a9fc69241b286acb7b55a22b8393c81222Chia-chi Yeh // solve this, if it is a DISCONNECTED event to our current network, 1118ee59e6a9fc69241b286acb7b55a22b8393c81222Chia-chi Yeh // respect it. Otherwise get a new one from getActiveNetworkInfo(). 1119c2bd6162eddad0cdfdafc037142e043680ffa705Chia-chi Yeh if (info == null || info.isConnected() || info.getType() != mNetworkType) { 112012bec5ddf58ad3a69728810480e6194c806567d6Hung-ying Tyan ConnectivityManager cm = (ConnectivityManager) 112112bec5ddf58ad3a69728810480e6194c806567d6Hung-ying Tyan mContext.getSystemService(Context.CONNECTIVITY_SERVICE); 1122ee59e6a9fc69241b286acb7b55a22b8393c81222Chia-chi Yeh info = cm.getActiveNetworkInfo(); 112312bec5ddf58ad3a69728810480e6194c806567d6Hung-ying Tyan } 112412bec5ddf58ad3a69728810480e6194c806567d6Hung-ying Tyan 1125ee59e6a9fc69241b286acb7b55a22b8393c81222Chia-chi Yeh // Some devices limit SIP on Wi-Fi. In this case, if we are not on 1126ee59e6a9fc69241b286acb7b55a22b8393c81222Chia-chi Yeh // Wi-Fi, treat it as a DISCONNECTED event. 1127c2bd6162eddad0cdfdafc037142e043680ffa705Chia-chi Yeh int networkType = (info != null && info.isConnected()) ? info.getType() : -1; 1128c2bd6162eddad0cdfdafc037142e043680ffa705Chia-chi Yeh if (mSipOnWifiOnly && networkType != ConnectivityManager.TYPE_WIFI) { 1129c2bd6162eddad0cdfdafc037142e043680ffa705Chia-chi Yeh networkType = -1; 1130c2bd6162eddad0cdfdafc037142e043680ffa705Chia-chi Yeh } 11312d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 1132ee59e6a9fc69241b286acb7b55a22b8393c81222Chia-chi Yeh // Ignore the event if the current active network is not changed. 1133c2bd6162eddad0cdfdafc037142e043680ffa705Chia-chi Yeh if (mNetworkType == networkType) { 1134ee59e6a9fc69241b286acb7b55a22b8393c81222Chia-chi Yeh return; 1135ee59e6a9fc69241b286acb7b55a22b8393c81222Chia-chi Yeh } 1136ee59e6a9fc69241b286acb7b55a22b8393c81222Chia-chi Yeh if (DEBUG) { 1137ee59e6a9fc69241b286acb7b55a22b8393c81222Chia-chi Yeh Log.d(TAG, "onConnectivityChanged(): " + mNetworkType + 1138ee59e6a9fc69241b286acb7b55a22b8393c81222Chia-chi Yeh " -> " + networkType); 1139ee59e6a9fc69241b286acb7b55a22b8393c81222Chia-chi Yeh } 11402d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 1141ee59e6a9fc69241b286acb7b55a22b8393c81222Chia-chi Yeh try { 1142c2bd6162eddad0cdfdafc037142e043680ffa705Chia-chi Yeh if (mNetworkType != -1) { 1143ee59e6a9fc69241b286acb7b55a22b8393c81222Chia-chi Yeh mLocalIp = null; 1144ee59e6a9fc69241b286acb7b55a22b8393c81222Chia-chi Yeh stopPortMappingMeasurement(); 1145ee59e6a9fc69241b286acb7b55a22b8393c81222Chia-chi Yeh for (SipSessionGroupExt group : mSipGroups.values()) { 1146ee59e6a9fc69241b286acb7b55a22b8393c81222Chia-chi Yeh group.onConnectivityChanged(false); 1147ee59e6a9fc69241b286acb7b55a22b8393c81222Chia-chi Yeh } 11482d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 1149ee59e6a9fc69241b286acb7b55a22b8393c81222Chia-chi Yeh mNetworkType = networkType; 1150b17eae9e227475a323f61519abc8a7d35ddf8828Hung-ying Tyan 1151c2bd6162eddad0cdfdafc037142e043680ffa705Chia-chi Yeh if (mNetworkType != -1) { 1152ee59e6a9fc69241b286acb7b55a22b8393c81222Chia-chi Yeh mLocalIp = determineLocalIp(); 1153ee59e6a9fc69241b286acb7b55a22b8393c81222Chia-chi Yeh mKeepAliveInterval = -1; 1154ee59e6a9fc69241b286acb7b55a22b8393c81222Chia-chi Yeh mLastGoodKeepAliveInterval = DEFAULT_KEEPALIVE_INTERVAL; 1155ee59e6a9fc69241b286acb7b55a22b8393c81222Chia-chi Yeh for (SipSessionGroupExt group : mSipGroups.values()) { 1156ee59e6a9fc69241b286acb7b55a22b8393c81222Chia-chi Yeh group.onConnectivityChanged(true); 11572d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 11582d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 1159c2bd6162eddad0cdfdafc037142e043680ffa705Chia-chi Yeh updateWakeLocks(); 1160ee59e6a9fc69241b286acb7b55a22b8393c81222Chia-chi Yeh } catch (SipException e) { 1161ee59e6a9fc69241b286acb7b55a22b8393c81222Chia-chi Yeh Log.e(TAG, "onConnectivityChanged()", e); 11622d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 11632d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 11642d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 1165bd57eeafe034cf850225db403700b5dc5db5ebccHung-ying Tyan private static Looper createLooper() { 1166bd57eeafe034cf850225db403700b5dc5db5ebccHung-ying Tyan HandlerThread thread = new HandlerThread("SipService.Executor"); 1167bd57eeafe034cf850225db403700b5dc5db5ebccHung-ying Tyan thread.start(); 1168bd57eeafe034cf850225db403700b5dc5db5ebccHung-ying Tyan return thread.getLooper(); 1169bd57eeafe034cf850225db403700b5dc5db5ebccHung-ying Tyan } 1170bd57eeafe034cf850225db403700b5dc5db5ebccHung-ying Tyan 1171bd57eeafe034cf850225db403700b5dc5db5ebccHung-ying Tyan // Executes immediate tasks in a single thread. 1172bd57eeafe034cf850225db403700b5dc5db5ebccHung-ying Tyan // Hold/release wake lock for running tasks 11735621554033089d1c07d53f56e8cd9787125d6e28Hung-ying Tyan private class MyExecutor extends Handler implements Executor { 1174b17eae9e227475a323f61519abc8a7d35ddf8828Hung-ying Tyan MyExecutor() { 1175b17eae9e227475a323f61519abc8a7d35ddf8828Hung-ying Tyan super(createLooper()); 1176b17eae9e227475a323f61519abc8a7d35ddf8828Hung-ying Tyan } 1177b17eae9e227475a323f61519abc8a7d35ddf8828Hung-ying Tyan 11785621554033089d1c07d53f56e8cd9787125d6e28Hung-ying Tyan @Override 11795621554033089d1c07d53f56e8cd9787125d6e28Hung-ying Tyan public void execute(Runnable task) { 1180bd57eeafe034cf850225db403700b5dc5db5ebccHung-ying Tyan mMyWakeLock.acquire(task); 1181b17eae9e227475a323f61519abc8a7d35ddf8828Hung-ying Tyan Message.obtain(this, 0/* don't care */, task).sendToTarget(); 1182b17eae9e227475a323f61519abc8a7d35ddf8828Hung-ying Tyan } 1183b17eae9e227475a323f61519abc8a7d35ddf8828Hung-ying Tyan 1184b17eae9e227475a323f61519abc8a7d35ddf8828Hung-ying Tyan @Override 1185b17eae9e227475a323f61519abc8a7d35ddf8828Hung-ying Tyan public void handleMessage(Message msg) { 1186b17eae9e227475a323f61519abc8a7d35ddf8828Hung-ying Tyan if (msg.obj instanceof Runnable) { 1187bd57eeafe034cf850225db403700b5dc5db5ebccHung-ying Tyan executeInternal((Runnable) msg.obj); 1188b17eae9e227475a323f61519abc8a7d35ddf8828Hung-ying Tyan } else { 1189b17eae9e227475a323f61519abc8a7d35ddf8828Hung-ying Tyan Log.w(TAG, "can't handle msg: " + msg); 1190b17eae9e227475a323f61519abc8a7d35ddf8828Hung-ying Tyan } 1191b17eae9e227475a323f61519abc8a7d35ddf8828Hung-ying Tyan } 1192bd57eeafe034cf850225db403700b5dc5db5ebccHung-ying Tyan 1193bd57eeafe034cf850225db403700b5dc5db5ebccHung-ying Tyan private void executeInternal(Runnable task) { 1194bd57eeafe034cf850225db403700b5dc5db5ebccHung-ying Tyan try { 1195bd57eeafe034cf850225db403700b5dc5db5ebccHung-ying Tyan task.run(); 1196bd57eeafe034cf850225db403700b5dc5db5ebccHung-ying Tyan } catch (Throwable t) { 1197bd57eeafe034cf850225db403700b5dc5db5ebccHung-ying Tyan Log.e(TAG, "run task: " + task, t); 1198bd57eeafe034cf850225db403700b5dc5db5ebccHung-ying Tyan } finally { 1199bd57eeafe034cf850225db403700b5dc5db5ebccHung-ying Tyan mMyWakeLock.release(task); 1200bd57eeafe034cf850225db403700b5dc5db5ebccHung-ying Tyan } 1201bd57eeafe034cf850225db403700b5dc5db5ebccHung-ying Tyan } 1202bd57eeafe034cf850225db403700b5dc5db5ebccHung-ying Tyan } 12032d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang} 1204