SipService.java revision 37f93394fe5c7cfede3a780214fa99a9e2a69133
19c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan/* 29c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan * Copyright (C) 2010, The Android Open Source Project 39c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan * 49c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan * Licensed under the Apache License, Version 2.0 (the "License"); 59c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan * you may not use this file except in compliance with the License. 69c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan * You may obtain a copy of the License at 79c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan * 89c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan * http://www.apache.org/licenses/LICENSE-2.0 99c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan * 109c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan * Unless required by applicable law or agreed to in writing, software 119c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan * distributed under the License is distributed on an "AS IS" BASIS, 129c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 139c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan * See the License for the specific language governing permissions and 149c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan * limitations under the License. 159c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan */ 169c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 179c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanpackage com.android.server.sip; 189c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 199c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.app.AlarmManager; 209c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.app.PendingIntent; 219c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.content.BroadcastReceiver; 229c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.content.Context; 239c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.content.Intent; 249c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.content.IntentFilter; 259c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.net.ConnectivityManager; 269c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.net.NetworkInfo; 279c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.net.sip.ISipService; 289c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.net.sip.ISipSession; 299c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.net.sip.ISipSessionListener; 309c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.net.sip.SipErrorCode; 319c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.net.sip.SipManager; 329c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.net.sip.SipProfile; 339c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.net.sip.SipSession; 349c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.net.sip.SipSessionAdapter; 359c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.net.wifi.WifiManager; 369c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.os.Binder; 379c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.os.Bundle; 389c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.os.Handler; 399c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.os.HandlerThread; 409c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.os.Looper; 419c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.os.Message; 42257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyanimport android.os.PowerManager; 43a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyanimport android.os.Process; 449c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.os.RemoteException; 459c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.os.ServiceManager; 469c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.os.SystemClock; 479c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.text.TextUtils; 489c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.util.Log; 499c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 509c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport java.io.IOException; 519c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport java.net.DatagramSocket; 529c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport java.net.InetAddress; 539c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport java.net.UnknownHostException; 54a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyanimport java.util.ArrayList; 559c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport java.util.Collection; 569c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport java.util.Comparator; 579c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport java.util.HashMap; 589c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport java.util.Iterator; 599c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport java.util.Map; 609c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport java.util.Timer; 619c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport java.util.TimerTask; 629c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport java.util.TreeSet; 634cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyanimport java.util.concurrent.Executor; 649c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport javax.sip.SipException; 659c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 669c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan/** 679c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan * @hide 689c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan */ 699c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanpublic final class SipService extends ISipService.Stub { 70acedadc1967457ac2f8981c67f884fd8c0ee853cHung-ying Tyan static final String TAG = "SipService"; 71acedadc1967457ac2f8981c67f884fd8c0ee853cHung-ying Tyan static final boolean DEBUGV = false; 728a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan static final boolean DEBUG = true; 739c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private static final int EXPIRY_TIME = 3600; 749c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private static final int SHORT_EXPIRY_TIME = 10; 759c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private static final int MIN_EXPIRY_TIME = 60; 768a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan private static final int DEFAULT_KEEPALIVE_INTERVAL = 10; // in seconds 77cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan private static final int DEFAULT_MAX_KEEPALIVE_INTERVAL = 120; // in seconds 789c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 799c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private Context mContext; 809c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private String mLocalIp; 819c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private String mNetworkType; 829c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private boolean mConnected; 834cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan private SipWakeupTimer mTimer; 8487e304ce2e55588dfbec18406bf910e5adcfa3a4Chung-yih Wang private WifiScanProcess mWifiScanProcess; 859c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private WifiManager.WifiLock mWifiLock; 869c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private boolean mWifiOnly; 87987b505b1c190ff0e5a05d2cc20c9b08d2b99b18Hung-ying Tyan private BroadcastReceiver mWifiStateReceiver = null; 88987b505b1c190ff0e5a05d2cc20c9b08d2b99b18Hung-ying Tyan 89469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang private IntervalMeasurementProcess mIntervalMeasurementProcess; 909c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 914cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan private MyExecutor mExecutor = new MyExecutor(); 929c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 939c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // SipProfile URI --> group 949c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private Map<String, SipSessionGroupExt> mSipGroups = 959c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan new HashMap<String, SipSessionGroupExt>(); 969c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 979c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // session ID --> session 989c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private Map<String, ISipSession> mPendingSessions = 999c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan new HashMap<String, ISipSession>(); 1009c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 1019c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private ConnectivityReceiver mConnectivityReceiver; 1029abf73f1bde7b1617603c888650dbda9d6a7fddfHung-ying Tyan private boolean mWifiEnabled; 103acedadc1967457ac2f8981c67f884fd8c0ee853cHung-ying Tyan private SipWakeLock mMyWakeLock; 104469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang private int mKeepAliveInterval; 105cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan private int mLastGoodKeepAliveInterval = DEFAULT_KEEPALIVE_INTERVAL; 1069c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 1079c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan /** 1089c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan * Starts the SIP service. Do nothing if the SIP API is not supported on the 1099c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan * device. 1109c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan */ 1119c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public static void start(Context context) { 1129c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (SipManager.isApiSupported(context)) { 1139c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan ServiceManager.addService("sip", new SipService(context)); 11422523a59d879cf47f1e9c202d001d569fad4f69eHung-ying Tyan context.sendBroadcast(new Intent(SipManager.ACTION_SIP_SERVICE_UP)); 115dc7545495e1ef8bad32cd78775f4dc072015eea0Hung-ying Tyan if (DEBUG) Log.d(TAG, "SIP service started"); 1169c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 1179c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 1189c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 1199c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private SipService(Context context) { 1209c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (DEBUG) Log.d(TAG, " service started!"); 1219c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mContext = context; 1229c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mConnectivityReceiver = new ConnectivityReceiver(); 123acedadc1967457ac2f8981c67f884fd8c0ee853cHung-ying Tyan mMyWakeLock = new SipWakeLock((PowerManager) 124257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan context.getSystemService(Context.POWER_SERVICE)); 1259c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 1264cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan mTimer = new SipWakeupTimer(context, mExecutor); 1279c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mWifiOnly = SipManager.isSipWifiOnly(context); 1289c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 1299c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 130987b505b1c190ff0e5a05d2cc20c9b08d2b99b18Hung-ying Tyan private BroadcastReceiver createWifiBroadcastReceiver() { 131987b505b1c190ff0e5a05d2cc20c9b08d2b99b18Hung-ying Tyan return new BroadcastReceiver() { 132987b505b1c190ff0e5a05d2cc20c9b08d2b99b18Hung-ying Tyan @Override 133987b505b1c190ff0e5a05d2cc20c9b08d2b99b18Hung-ying Tyan public void onReceive(Context context, Intent intent) { 134987b505b1c190ff0e5a05d2cc20c9b08d2b99b18Hung-ying Tyan String action = intent.getAction(); 135987b505b1c190ff0e5a05d2cc20c9b08d2b99b18Hung-ying Tyan if (WifiManager.WIFI_STATE_CHANGED_ACTION.equals(action)) { 136987b505b1c190ff0e5a05d2cc20c9b08d2b99b18Hung-ying Tyan int state = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, 137987b505b1c190ff0e5a05d2cc20c9b08d2b99b18Hung-ying Tyan WifiManager.WIFI_STATE_UNKNOWN); 138987b505b1c190ff0e5a05d2cc20c9b08d2b99b18Hung-ying Tyan synchronized (SipService.this) { 139987b505b1c190ff0e5a05d2cc20c9b08d2b99b18Hung-ying Tyan switch (state) { 140987b505b1c190ff0e5a05d2cc20c9b08d2b99b18Hung-ying Tyan case WifiManager.WIFI_STATE_ENABLED: 141987b505b1c190ff0e5a05d2cc20c9b08d2b99b18Hung-ying Tyan mWifiEnabled = true; 142987b505b1c190ff0e5a05d2cc20c9b08d2b99b18Hung-ying Tyan if (anyOpenedToReceiveCalls()) grabWifiLock(); 143987b505b1c190ff0e5a05d2cc20c9b08d2b99b18Hung-ying Tyan break; 144987b505b1c190ff0e5a05d2cc20c9b08d2b99b18Hung-ying Tyan case WifiManager.WIFI_STATE_DISABLED: 145987b505b1c190ff0e5a05d2cc20c9b08d2b99b18Hung-ying Tyan mWifiEnabled = false; 146987b505b1c190ff0e5a05d2cc20c9b08d2b99b18Hung-ying Tyan releaseWifiLock(); 147987b505b1c190ff0e5a05d2cc20c9b08d2b99b18Hung-ying Tyan break; 148987b505b1c190ff0e5a05d2cc20c9b08d2b99b18Hung-ying Tyan } 1499abf73f1bde7b1617603c888650dbda9d6a7fddfHung-ying Tyan } 1509abf73f1bde7b1617603c888650dbda9d6a7fddfHung-ying Tyan } 151f452fd81f1a308428b0bfbae883fddb9caced878Chung-yih Wang } 152987b505b1c190ff0e5a05d2cc20c9b08d2b99b18Hung-ying Tyan }; 153f452fd81f1a308428b0bfbae883fddb9caced878Chung-yih Wang }; 154f452fd81f1a308428b0bfbae883fddb9caced878Chung-yih Wang 155dc7545495e1ef8bad32cd78775f4dc072015eea0Hung-ying Tyan private void registerReceivers() { 156dc7545495e1ef8bad32cd78775f4dc072015eea0Hung-ying Tyan mContext.registerReceiver(mConnectivityReceiver, 157dc7545495e1ef8bad32cd78775f4dc072015eea0Hung-ying Tyan new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION)); 158987b505b1c190ff0e5a05d2cc20c9b08d2b99b18Hung-ying Tyan if (SipManager.isSipWifiOnly(mContext)) { 159987b505b1c190ff0e5a05d2cc20c9b08d2b99b18Hung-ying Tyan mWifiStateReceiver = createWifiBroadcastReceiver(); 160987b505b1c190ff0e5a05d2cc20c9b08d2b99b18Hung-ying Tyan mContext.registerReceiver(mWifiStateReceiver, 161987b505b1c190ff0e5a05d2cc20c9b08d2b99b18Hung-ying Tyan new IntentFilter(WifiManager.WIFI_STATE_CHANGED_ACTION)); 162987b505b1c190ff0e5a05d2cc20c9b08d2b99b18Hung-ying Tyan } 163dc7545495e1ef8bad32cd78775f4dc072015eea0Hung-ying Tyan if (DEBUG) Log.d(TAG, " +++ register receivers"); 164dc7545495e1ef8bad32cd78775f4dc072015eea0Hung-ying Tyan } 165dc7545495e1ef8bad32cd78775f4dc072015eea0Hung-ying Tyan 166dc7545495e1ef8bad32cd78775f4dc072015eea0Hung-ying Tyan private void unregisterReceivers() { 167dc7545495e1ef8bad32cd78775f4dc072015eea0Hung-ying Tyan mContext.unregisterReceiver(mConnectivityReceiver); 168987b505b1c190ff0e5a05d2cc20c9b08d2b99b18Hung-ying Tyan if (SipManager.isSipWifiOnly(mContext)) { 169987b505b1c190ff0e5a05d2cc20c9b08d2b99b18Hung-ying Tyan mContext.unregisterReceiver(mWifiStateReceiver); 170987b505b1c190ff0e5a05d2cc20c9b08d2b99b18Hung-ying Tyan } 171dc7545495e1ef8bad32cd78775f4dc072015eea0Hung-ying Tyan if (DEBUG) Log.d(TAG, " --- unregister receivers"); 172dc7545495e1ef8bad32cd78775f4dc072015eea0Hung-ying Tyan } 173dc7545495e1ef8bad32cd78775f4dc072015eea0Hung-ying Tyan 1749c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public synchronized SipProfile[] getListOfProfiles() { 1758127b35b75c13f853dc8eb2fed8bba4bf99e3eedHung-ying Tyan mContext.enforceCallingOrSelfPermission( 1768127b35b75c13f853dc8eb2fed8bba4bf99e3eedHung-ying Tyan android.Manifest.permission.USE_SIP, null); 177a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan boolean isCallerRadio = isCallerRadio(); 178a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan ArrayList<SipProfile> profiles = new ArrayList<SipProfile>(); 1799c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan for (SipSessionGroupExt group : mSipGroups.values()) { 180a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan if (isCallerRadio || isCallerCreator(group)) { 181a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan profiles.add(group.getLocalProfile()); 182a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan } 1839c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 184a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan return profiles.toArray(new SipProfile[profiles.size()]); 1859c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 1869c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 187dc7545495e1ef8bad32cd78775f4dc072015eea0Hung-ying Tyan public synchronized void open(SipProfile localProfile) { 1888127b35b75c13f853dc8eb2fed8bba4bf99e3eedHung-ying Tyan mContext.enforceCallingOrSelfPermission( 1898127b35b75c13f853dc8eb2fed8bba4bf99e3eedHung-ying Tyan android.Manifest.permission.USE_SIP, null); 1909c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan localProfile.setCallingUid(Binder.getCallingUid()); 1919c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan try { 192dc7545495e1ef8bad32cd78775f4dc072015eea0Hung-ying Tyan boolean addingFirstProfile = mSipGroups.isEmpty(); 1939c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan createGroup(localProfile); 194dc7545495e1ef8bad32cd78775f4dc072015eea0Hung-ying Tyan if (addingFirstProfile && !mSipGroups.isEmpty()) registerReceivers(); 1959c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } catch (SipException e) { 1969c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Log.e(TAG, "openToMakeCalls()", e); 1979c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // TODO: how to send the exception back 1989c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 1999c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 2009c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 2019c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public synchronized void open3(SipProfile localProfile, 202845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan PendingIntent incomingCallPendingIntent, 203845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan ISipSessionListener listener) { 2048127b35b75c13f853dc8eb2fed8bba4bf99e3eedHung-ying Tyan mContext.enforceCallingOrSelfPermission( 2058127b35b75c13f853dc8eb2fed8bba4bf99e3eedHung-ying Tyan android.Manifest.permission.USE_SIP, null); 2069c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan localProfile.setCallingUid(Binder.getCallingUid()); 207845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan if (incomingCallPendingIntent == null) { 208845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan Log.w(TAG, "incomingCallPendingIntent cannot be null; " 209845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan + "the profile is not opened"); 210a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan return; 2119c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 2129c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (DEBUG) Log.d(TAG, "open3: " + localProfile.getUriString() + ": " 213845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan + incomingCallPendingIntent + ": " + listener); 2149c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan try { 215dc7545495e1ef8bad32cd78775f4dc072015eea0Hung-ying Tyan boolean addingFirstProfile = mSipGroups.isEmpty(); 2169c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan SipSessionGroupExt group = createGroup(localProfile, 217845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan incomingCallPendingIntent, listener); 218dc7545495e1ef8bad32cd78775f4dc072015eea0Hung-ying Tyan if (addingFirstProfile && !mSipGroups.isEmpty()) registerReceivers(); 2199c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (localProfile.getAutoRegistration()) { 2209c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan group.openToReceiveCalls(); 2219abf73f1bde7b1617603c888650dbda9d6a7fddfHung-ying Tyan if (mWifiEnabled) grabWifiLock(); 2229c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 2239c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } catch (SipException e) { 2249c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Log.e(TAG, "openToReceiveCalls()", e); 2259c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // TODO: how to send the exception back 2269c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 2279c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 2289c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 229a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan private boolean isCallerCreator(SipSessionGroupExt group) { 230a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan SipProfile profile = group.getLocalProfile(); 231a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan return (profile.getCallingUid() == Binder.getCallingUid()); 232a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan } 233a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan 234a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan private boolean isCallerCreatorOrRadio(SipSessionGroupExt group) { 235a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan return (isCallerRadio() || isCallerCreator(group)); 236a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan } 237a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan 238a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan private boolean isCallerRadio() { 239a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan return (Binder.getCallingUid() == Process.PHONE_UID); 240a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan } 241a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan 2429c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public synchronized void close(String localProfileUri) { 2438127b35b75c13f853dc8eb2fed8bba4bf99e3eedHung-ying Tyan mContext.enforceCallingOrSelfPermission( 2448127b35b75c13f853dc8eb2fed8bba4bf99e3eedHung-ying Tyan android.Manifest.permission.USE_SIP, null); 245a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan SipSessionGroupExt group = mSipGroups.get(localProfileUri); 246a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan if (group == null) return; 247a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan if (!isCallerCreatorOrRadio(group)) { 2486d9d99615a30de0675271553552c3c7b49311354Joe Onorato Log.w(TAG, "only creator or radio can close this profile"); 249a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan return; 2509c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 251a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan 252a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan group = mSipGroups.remove(localProfileUri); 253a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan notifyProfileRemoved(group.getLocalProfile()); 254a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan group.close(); 255257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan 256617479363dcafe01bfa1fa025e1d9d122864a0ceHung-ying Tyan if (!anyOpenedToReceiveCalls()) { 257257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan releaseWifiLock(); 258257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan mMyWakeLock.reset(); // in case there's leak 259257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan } 260dc7545495e1ef8bad32cd78775f4dc072015eea0Hung-ying Tyan if (mSipGroups.isEmpty()) unregisterReceivers(); 2619c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 2629c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 2639c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public synchronized boolean isOpened(String localProfileUri) { 2648127b35b75c13f853dc8eb2fed8bba4bf99e3eedHung-ying Tyan mContext.enforceCallingOrSelfPermission( 2658127b35b75c13f853dc8eb2fed8bba4bf99e3eedHung-ying Tyan android.Manifest.permission.USE_SIP, null); 2669c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan SipSessionGroupExt group = mSipGroups.get(localProfileUri); 267a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan if (group == null) return false; 268a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan if (isCallerCreatorOrRadio(group)) { 269617479363dcafe01bfa1fa025e1d9d122864a0ceHung-ying Tyan return true; 270a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan } else { 2716d9d99615a30de0675271553552c3c7b49311354Joe Onorato Log.w(TAG, "only creator or radio can query on the profile"); 272a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan return false; 273a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan } 2749c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 2759c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 2769c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public synchronized boolean isRegistered(String localProfileUri) { 2778127b35b75c13f853dc8eb2fed8bba4bf99e3eedHung-ying Tyan mContext.enforceCallingOrSelfPermission( 2788127b35b75c13f853dc8eb2fed8bba4bf99e3eedHung-ying Tyan android.Manifest.permission.USE_SIP, null); 2799c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan SipSessionGroupExt group = mSipGroups.get(localProfileUri); 280a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan if (group == null) return false; 281a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan if (isCallerCreatorOrRadio(group)) { 282a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan return group.isRegistered(); 283a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan } else { 2846d9d99615a30de0675271553552c3c7b49311354Joe Onorato Log.w(TAG, "only creator or radio can query on the profile"); 285a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan return false; 286a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan } 2879c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 2889c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 2899c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public synchronized void setRegistrationListener(String localProfileUri, 2909c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan ISipSessionListener listener) { 2918127b35b75c13f853dc8eb2fed8bba4bf99e3eedHung-ying Tyan mContext.enforceCallingOrSelfPermission( 2928127b35b75c13f853dc8eb2fed8bba4bf99e3eedHung-ying Tyan android.Manifest.permission.USE_SIP, null); 2939c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan SipSessionGroupExt group = mSipGroups.get(localProfileUri); 294a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan if (group == null) return; 295a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan if (isCallerCreator(group)) { 296a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan group.setListener(listener); 297a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan } else { 2986d9d99615a30de0675271553552c3c7b49311354Joe Onorato Log.w(TAG, "only creator can set listener on the profile"); 299a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan } 3009c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 3019c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 3029c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public synchronized ISipSession createSession(SipProfile localProfile, 3039c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan ISipSessionListener listener) { 3048127b35b75c13f853dc8eb2fed8bba4bf99e3eedHung-ying Tyan mContext.enforceCallingOrSelfPermission( 3058127b35b75c13f853dc8eb2fed8bba4bf99e3eedHung-ying Tyan android.Manifest.permission.USE_SIP, null); 3069c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan localProfile.setCallingUid(Binder.getCallingUid()); 3079c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (!mConnected) return null; 3089c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan try { 3099c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan SipSessionGroupExt group = createGroup(localProfile); 3109c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return group.createSession(listener); 3119c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } catch (SipException e) { 3126d9d99615a30de0675271553552c3c7b49311354Joe Onorato if (DEBUG) Log.d(TAG, "createSession()", e); 3139c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return null; 3149c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 3159c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 3169c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 3179c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public synchronized ISipSession getPendingSession(String callId) { 3188127b35b75c13f853dc8eb2fed8bba4bf99e3eedHung-ying Tyan mContext.enforceCallingOrSelfPermission( 3198127b35b75c13f853dc8eb2fed8bba4bf99e3eedHung-ying Tyan android.Manifest.permission.USE_SIP, null); 3209c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (callId == null) return null; 3219c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return mPendingSessions.get(callId); 3229c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 3239c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 3249c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private String determineLocalIp() { 3259c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan try { 3269c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan DatagramSocket s = new DatagramSocket(); 3279c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan s.connect(InetAddress.getByName("192.168.1.1"), 80); 3289c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return s.getLocalAddress().getHostAddress(); 3299c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } catch (IOException e) { 3306d9d99615a30de0675271553552c3c7b49311354Joe Onorato if (DEBUG) Log.d(TAG, "determineLocalIp()", e); 3319c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // dont do anything; there should be a connectivity change going 3329c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return null; 3339c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 3349c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 3359c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 3369c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private SipSessionGroupExt createGroup(SipProfile localProfile) 3379c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan throws SipException { 3389c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan String key = localProfile.getUriString(); 3399c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan SipSessionGroupExt group = mSipGroups.get(key); 3409c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (group == null) { 3419c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan group = new SipSessionGroupExt(localProfile, null, null); 3429c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mSipGroups.put(key, group); 3439c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan notifyProfileAdded(localProfile); 344a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan } else if (!isCallerCreator(group)) { 345a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan throw new SipException("only creator can access the profile"); 3469c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 3479c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return group; 3489c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 3499c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 3509c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private SipSessionGroupExt createGroup(SipProfile localProfile, 351845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan PendingIntent incomingCallPendingIntent, 352845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan ISipSessionListener listener) throws SipException { 3539c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan String key = localProfile.getUriString(); 3549c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan SipSessionGroupExt group = mSipGroups.get(key); 3559c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (group != null) { 356a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan if (!isCallerCreator(group)) { 357a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan throw new SipException("only creator can access the profile"); 358a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan } 359845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan group.setIncomingCallPendingIntent(incomingCallPendingIntent); 3609c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan group.setListener(listener); 3619c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else { 3629c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan group = new SipSessionGroupExt(localProfile, 363845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan incomingCallPendingIntent, listener); 3649c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mSipGroups.put(key, group); 3659c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan notifyProfileAdded(localProfile); 3669c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 3679c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return group; 3689c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 3699c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 3709c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private void notifyProfileAdded(SipProfile localProfile) { 3719c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (DEBUG) Log.d(TAG, "notify: profile added: " + localProfile); 3729c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Intent intent = new Intent(SipManager.ACTION_SIP_ADD_PHONE); 3739c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan intent.putExtra(SipManager.EXTRA_LOCAL_URI, localProfile.getUriString()); 3749c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mContext.sendBroadcast(intent); 3759c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 3769c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 3779c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private void notifyProfileRemoved(SipProfile localProfile) { 3789c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (DEBUG) Log.d(TAG, "notify: profile removed: " + localProfile); 3799c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Intent intent = new Intent(SipManager.ACTION_SIP_REMOVE_PHONE); 3809c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan intent.putExtra(SipManager.EXTRA_LOCAL_URI, localProfile.getUriString()); 3819c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mContext.sendBroadcast(intent); 3829c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 3839c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 384617479363dcafe01bfa1fa025e1d9d122864a0ceHung-ying Tyan private boolean anyOpenedToReceiveCalls() { 3859c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan for (SipSessionGroupExt group : mSipGroups.values()) { 386617479363dcafe01bfa1fa025e1d9d122864a0ceHung-ying Tyan if (group.isOpenedToReceiveCalls()) return true; 3879c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 3889c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return false; 3899c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 3909c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 3919c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private void grabWifiLock() { 3929c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (mWifiLock == null) { 3938a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan if (DEBUG) Log.d(TAG, "acquire wifi lock"); 3949c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mWifiLock = ((WifiManager) 3959c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mContext.getSystemService(Context.WIFI_SERVICE)) 3969c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan .createWifiLock(WifiManager.WIFI_MODE_FULL, TAG); 3979c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mWifiLock.acquire(); 39887e304ce2e55588dfbec18406bf910e5adcfa3a4Chung-yih Wang if (!mConnected) startWifiScanner(); 3999c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 4009c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 4019c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 4029c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private void releaseWifiLock() { 4039c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (mWifiLock != null) { 4048a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan if (DEBUG) Log.d(TAG, "release wifi lock"); 4059c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mWifiLock.release(); 4069c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mWifiLock = null; 40787e304ce2e55588dfbec18406bf910e5adcfa3a4Chung-yih Wang stopWifiScanner(); 40887e304ce2e55588dfbec18406bf910e5adcfa3a4Chung-yih Wang } 40987e304ce2e55588dfbec18406bf910e5adcfa3a4Chung-yih Wang } 41087e304ce2e55588dfbec18406bf910e5adcfa3a4Chung-yih Wang 41187e304ce2e55588dfbec18406bf910e5adcfa3a4Chung-yih Wang private synchronized void startWifiScanner() { 41287e304ce2e55588dfbec18406bf910e5adcfa3a4Chung-yih Wang if (mWifiScanProcess == null) { 41387e304ce2e55588dfbec18406bf910e5adcfa3a4Chung-yih Wang mWifiScanProcess = new WifiScanProcess(); 41487e304ce2e55588dfbec18406bf910e5adcfa3a4Chung-yih Wang } 41587e304ce2e55588dfbec18406bf910e5adcfa3a4Chung-yih Wang mWifiScanProcess.start(); 41687e304ce2e55588dfbec18406bf910e5adcfa3a4Chung-yih Wang } 41787e304ce2e55588dfbec18406bf910e5adcfa3a4Chung-yih Wang 41887e304ce2e55588dfbec18406bf910e5adcfa3a4Chung-yih Wang private synchronized void stopWifiScanner() { 41987e304ce2e55588dfbec18406bf910e5adcfa3a4Chung-yih Wang if (mWifiScanProcess != null) { 42087e304ce2e55588dfbec18406bf910e5adcfa3a4Chung-yih Wang mWifiScanProcess.stop(); 4219c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 4229c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 4239c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 4249c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private synchronized void onConnectivityChanged( 4259c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan String type, boolean connected) { 4269c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (DEBUG) Log.d(TAG, "onConnectivityChanged(): " 4279c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan + mNetworkType + (mConnected? " CONNECTED" : " DISCONNECTED") 4289c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan + " --> " + type + (connected? " CONNECTED" : " DISCONNECTED")); 4299c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 4309c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan boolean sameType = type.equals(mNetworkType); 4319c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (!sameType && !connected) return; 4329c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 4339c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan boolean wasWifi = "WIFI".equalsIgnoreCase(mNetworkType); 4349c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan boolean isWifi = "WIFI".equalsIgnoreCase(type); 4359c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan boolean wifiOff = (isWifi && !connected) || (wasWifi && !sameType); 4369c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan boolean wifiOn = isWifi && connected; 4379c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 4389c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan try { 4399c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan boolean wasConnected = mConnected; 4409c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mNetworkType = type; 4419c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mConnected = connected; 4429c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 4439c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (wasConnected) { 4449c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mLocalIp = null; 44537f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh stopPortMappingMeasurement(); 4469c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan for (SipSessionGroupExt group : mSipGroups.values()) { 4479c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan group.onConnectivityChanged(false); 4489c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 4499c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 4509c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 4519c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (connected) { 4529c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mLocalIp = determineLocalIp(); 453469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang mKeepAliveInterval = -1; 454cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan mLastGoodKeepAliveInterval = DEFAULT_KEEPALIVE_INTERVAL; 4559c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan for (SipSessionGroupExt group : mSipGroups.values()) { 4569c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan group.onConnectivityChanged(true); 4579c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 45887e304ce2e55588dfbec18406bf910e5adcfa3a4Chung-yih Wang if (isWifi && (mWifiLock != null)) stopWifiScanner(); 459257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan } else { 460257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan mMyWakeLock.reset(); // in case there's a leak 46187e304ce2e55588dfbec18406bf910e5adcfa3a4Chung-yih Wang if (isWifi && (mWifiLock != null)) startWifiScanner(); 4629c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 4639c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } catch (SipException e) { 4649c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Log.e(TAG, "onConnectivityChanged()", e); 4659c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 4669c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 4679c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 468469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang private void stopPortMappingMeasurement() { 469469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang if (mIntervalMeasurementProcess != null) { 470469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang mIntervalMeasurementProcess.stop(); 471469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang mIntervalMeasurementProcess = null; 472469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang } 473469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang } 474469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang 4758a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan private void startPortMappingLifetimeMeasurement( 4768a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan SipProfile localProfile) { 477cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan startPortMappingLifetimeMeasurement(localProfile, 478cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan DEFAULT_MAX_KEEPALIVE_INTERVAL); 47944ccfb03bb349a90546ddb3dc0063cbf4aaddaf1Hung-ying Tyan } 48044ccfb03bb349a90546ddb3dc0063cbf4aaddaf1Hung-ying Tyan 48144ccfb03bb349a90546ddb3dc0063cbf4aaddaf1Hung-ying Tyan private void startPortMappingLifetimeMeasurement( 48244ccfb03bb349a90546ddb3dc0063cbf4aaddaf1Hung-ying Tyan SipProfile localProfile, int maxInterval) { 4838a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan if ((mIntervalMeasurementProcess == null) 4848a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan && (mKeepAliveInterval == -1) 4858a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan && isBehindNAT(mLocalIp)) { 4868a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan Log.d(TAG, "start NAT port mapping timeout measurement on " 4878a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan + localProfile.getUriString()); 4888a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan 489cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan int minInterval = mLastGoodKeepAliveInterval; 490cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan if (minInterval >= maxInterval) { 491cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan // If mLastGoodKeepAliveInterval also does not work, reset it 492cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan // to the default min 493cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan minInterval = mLastGoodKeepAliveInterval 494cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan = DEFAULT_KEEPALIVE_INTERVAL; 495cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan Log.d(TAG, " reset min interval to " + minInterval); 496cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan } 497cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan mIntervalMeasurementProcess = new IntervalMeasurementProcess( 498cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan localProfile, minInterval, maxInterval); 4998a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan mIntervalMeasurementProcess.start(); 5008a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan } 501469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang } 502469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang 50344ccfb03bb349a90546ddb3dc0063cbf4aaddaf1Hung-ying Tyan private void restartPortMappingLifetimeMeasurement( 50444ccfb03bb349a90546ddb3dc0063cbf4aaddaf1Hung-ying Tyan SipProfile localProfile, int maxInterval) { 50544ccfb03bb349a90546ddb3dc0063cbf4aaddaf1Hung-ying Tyan stopPortMappingMeasurement(); 50644ccfb03bb349a90546ddb3dc0063cbf4aaddaf1Hung-ying Tyan mKeepAliveInterval = -1; 50744ccfb03bb349a90546ddb3dc0063cbf4aaddaf1Hung-ying Tyan startPortMappingLifetimeMeasurement(localProfile, maxInterval); 50844ccfb03bb349a90546ddb3dc0063cbf4aaddaf1Hung-ying Tyan } 50944ccfb03bb349a90546ddb3dc0063cbf4aaddaf1Hung-ying Tyan 5109c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private synchronized void addPendingSession(ISipSession session) { 5119c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan try { 5123f4d44657ccad3ed02ed0e1354387b14b07dc011Hung-ying Tyan cleanUpPendingSessions(); 5139c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mPendingSessions.put(session.getCallId(), session); 5143f4d44657ccad3ed02ed0e1354387b14b07dc011Hung-ying Tyan if (DEBUG) Log.d(TAG, "#pending sess=" + mPendingSessions.size()); 5159c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } catch (RemoteException e) { 5169c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // should not happen with a local call 5179c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Log.e(TAG, "addPendingSession()", e); 5189c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 5199c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 5209c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 5213f4d44657ccad3ed02ed0e1354387b14b07dc011Hung-ying Tyan private void cleanUpPendingSessions() throws RemoteException { 5223f4d44657ccad3ed02ed0e1354387b14b07dc011Hung-ying Tyan Map.Entry<String, ISipSession>[] entries = 5233f4d44657ccad3ed02ed0e1354387b14b07dc011Hung-ying Tyan mPendingSessions.entrySet().toArray( 5243f4d44657ccad3ed02ed0e1354387b14b07dc011Hung-ying Tyan new Map.Entry[mPendingSessions.size()]); 5253f4d44657ccad3ed02ed0e1354387b14b07dc011Hung-ying Tyan for (Map.Entry<String, ISipSession> entry : entries) { 5263f4d44657ccad3ed02ed0e1354387b14b07dc011Hung-ying Tyan if (entry.getValue().getState() != SipSession.State.INCOMING_CALL) { 5273f4d44657ccad3ed02ed0e1354387b14b07dc011Hung-ying Tyan mPendingSessions.remove(entry.getKey()); 5283f4d44657ccad3ed02ed0e1354387b14b07dc011Hung-ying Tyan } 5293f4d44657ccad3ed02ed0e1354387b14b07dc011Hung-ying Tyan } 5303f4d44657ccad3ed02ed0e1354387b14b07dc011Hung-ying Tyan } 5313f4d44657ccad3ed02ed0e1354387b14b07dc011Hung-ying Tyan 532ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan private synchronized boolean callingSelf(SipSessionGroupExt ringingGroup, 533ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan SipSessionGroup.SipSessionImpl ringingSession) { 534ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan String callId = ringingSession.getCallId(); 535ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan for (SipSessionGroupExt group : mSipGroups.values()) { 536ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan if ((group != ringingGroup) && group.containsSession(callId)) { 537ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan if (DEBUG) Log.d(TAG, "call self: " 538ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan + ringingSession.getLocalProfile().getUriString() 539ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan + " -> " + group.getLocalProfile().getUriString()); 540ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan return true; 541ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan } 542ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan } 543ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan return false; 544ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan } 545ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan 5468a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan private synchronized void onKeepAliveIntervalChanged() { 5478a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan for (SipSessionGroupExt group : mSipGroups.values()) { 5488a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan group.onKeepAliveIntervalChanged(); 5498a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan } 5508a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan } 5518a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan 5528a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan private int getKeepAliveInterval() { 5538a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan return (mKeepAliveInterval < 0) 554cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan ? mLastGoodKeepAliveInterval 5558a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan : mKeepAliveInterval; 5568a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan } 5578a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan 5588a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan private boolean isBehindNAT(String address) { 5598a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan try { 5608a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan byte[] d = InetAddress.getByName(address).getAddress(); 5618a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan if ((d[0] == 10) || 5628a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan (((0x000000FF & ((int)d[0])) == 172) && 5638a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan ((0x000000F0 & ((int)d[1])) == 16)) || 5648a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan (((0x000000FF & ((int)d[0])) == 192) && 5658a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan ((0x000000FF & ((int)d[1])) == 168))) { 5668a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan return true; 5678a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan } 5688a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan } catch (UnknownHostException e) { 5698a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan Log.e(TAG, "isBehindAT()" + address, e); 5708a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan } 5718a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan return false; 5728a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan } 573ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan 5749c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private class SipSessionGroupExt extends SipSessionAdapter { 5759c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private SipSessionGroup mSipGroup; 576845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan private PendingIntent mIncomingCallPendingIntent; 577617479363dcafe01bfa1fa025e1d9d122864a0ceHung-ying Tyan private boolean mOpenedToReceiveCalls; 5789c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 5799c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private AutoRegistrationProcess mAutoRegistration = 5809c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan new AutoRegistrationProcess(); 5819c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 5829c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public SipSessionGroupExt(SipProfile localProfile, 583845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan PendingIntent incomingCallPendingIntent, 5849c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan ISipSessionListener listener) throws SipException { 5859c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan String password = localProfile.getPassword(); 5869c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan SipProfile p = duplicate(localProfile); 5879c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mSipGroup = createSipSessionGroup(mLocalIp, p, password); 588845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan mIncomingCallPendingIntent = incomingCallPendingIntent; 5899c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mAutoRegistration.setListener(listener); 5909c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 5919c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 5929c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public SipProfile getLocalProfile() { 5939c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return mSipGroup.getLocalProfile(); 5949c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 5959c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 596ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan public boolean containsSession(String callId) { 597ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan return mSipGroup.containsSession(callId); 598ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan } 599ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan 6008a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan public void onKeepAliveIntervalChanged() { 6018a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan mAutoRegistration.onKeepAliveIntervalChanged(); 6028a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan } 6038a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan 6048a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan // TODO: remove this method once SipWakeupTimer can better handle variety 6058a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan // of timeout values 6068a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan void setWakeupTimer(SipWakeupTimer timer) { 6078a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan mSipGroup.setWakeupTimer(timer); 6088a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan } 6098a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan 6109c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // network connectivity is tricky because network can be disconnected 6119c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // at any instant so need to deal with exceptions carefully even when 6129c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // you think you are connected 6139c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private SipSessionGroup createSipSessionGroup(String localIp, 6149c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan SipProfile localProfile, String password) throws SipException { 6159c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan try { 616acedadc1967457ac2f8981c67f884fd8c0ee853cHung-ying Tyan return new SipSessionGroup(localIp, localProfile, password, 6178a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan mTimer, mMyWakeLock); 6189c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } catch (IOException e) { 6199c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // network disconnected 6209c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Log.w(TAG, "createSipSessionGroup(): network disconnected?"); 6219c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (localIp != null) { 6229c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return createSipSessionGroup(null, localProfile, password); 6239c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else { 6249c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // recursive 6256d9d99615a30de0675271553552c3c7b49311354Joe Onorato Log.wtf(TAG, "impossible! recursive!"); 6269c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan throw new RuntimeException("createSipSessionGroup"); 6279c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 6289c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 6299c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 6309c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 6319c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private SipProfile duplicate(SipProfile p) { 6329c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan try { 6339c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return new SipProfile.Builder(p).setPassword("*").build(); 6349c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } catch (Exception e) { 6359c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Log.wtf(TAG, "duplicate()", e); 6369c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan throw new RuntimeException("duplicate profile", e); 6379c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 6389c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 6399c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 6409c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public void setListener(ISipSessionListener listener) { 6419c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mAutoRegistration.setListener(listener); 6429c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 6439c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 644845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan public void setIncomingCallPendingIntent(PendingIntent pIntent) { 645845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan mIncomingCallPendingIntent = pIntent; 6469c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 6479c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 6489c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public void openToReceiveCalls() throws SipException { 649617479363dcafe01bfa1fa025e1d9d122864a0ceHung-ying Tyan mOpenedToReceiveCalls = true; 6509c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (mConnected) { 6519c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mSipGroup.openToReceiveCalls(this); 6529c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mAutoRegistration.start(mSipGroup); 6539c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 6549c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (DEBUG) Log.d(TAG, " openToReceiveCalls: " + getUri() + ": " 655845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan + mIncomingCallPendingIntent); 6569c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 6579c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 6589c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public void onConnectivityChanged(boolean connected) 6599c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan throws SipException { 6609c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mSipGroup.onConnectivityChanged(); 6619c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (connected) { 6629c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan resetGroup(mLocalIp); 663617479363dcafe01bfa1fa025e1d9d122864a0ceHung-ying Tyan if (mOpenedToReceiveCalls) openToReceiveCalls(); 6649c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else { 665617479363dcafe01bfa1fa025e1d9d122864a0ceHung-ying Tyan // close mSipGroup but remember mOpenedToReceiveCalls 6669c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (DEBUG) Log.d(TAG, " close auto reg temporarily: " 667845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan + getUri() + ": " + mIncomingCallPendingIntent); 6689c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mSipGroup.close(); 6699c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mAutoRegistration.stop(); 6709c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 6719c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 6729c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 6739c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private void resetGroup(String localIp) throws SipException { 6749c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan try { 6759c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mSipGroup.reset(localIp); 6769c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } catch (IOException e) { 6779c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // network disconnected 6789c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Log.w(TAG, "resetGroup(): network disconnected?"); 6799c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (localIp != null) { 6809c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan resetGroup(null); // reset w/o local IP 6819c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else { 6829c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // recursive 6839c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Log.wtf(TAG, "impossible!"); 6849c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan throw new RuntimeException("resetGroup"); 6859c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 6869c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 6879c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 6889c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 6899c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public void close() { 690617479363dcafe01bfa1fa025e1d9d122864a0ceHung-ying Tyan mOpenedToReceiveCalls = false; 6919c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mSipGroup.close(); 6929c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mAutoRegistration.stop(); 6939c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (DEBUG) Log.d(TAG, " close: " + getUri() + ": " 694845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan + mIncomingCallPendingIntent); 6959c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 6969c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 6979c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public ISipSession createSession(ISipSessionListener listener) { 6989c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return mSipGroup.createSession(listener); 6999c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 7009c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 7019c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan @Override 702845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan public void onRinging(ISipSession s, SipProfile caller, 7039c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan String sessionDescription) { 704acedadc1967457ac2f8981c67f884fd8c0ee853cHung-ying Tyan if (DEBUGV) Log.d(TAG, "<<<<< onRinging()"); 705845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan SipSessionGroup.SipSessionImpl session = 706845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan (SipSessionGroup.SipSessionImpl) s; 7079c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan synchronized (SipService.this) { 7089c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan try { 709ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan if (!isRegistered() || callingSelf(this, session)) { 7109c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan session.endCall(); 7119c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return; 7129c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 7139c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 7149c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // send out incoming call broadcast 7159c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan addPendingSession(session); 7169c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Intent intent = SipManager.createIncomingCallBroadcast( 717845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan session.getCallId(), sessionDescription); 7189c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (DEBUG) Log.d(TAG, " ringing~~ " + getUri() + ": " 7199c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan + caller.getUri() + ": " + session.getCallId() 720845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan + " " + mIncomingCallPendingIntent); 721845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan mIncomingCallPendingIntent.send(mContext, 722845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan SipManager.INCOMING_CALL_RESULT_CODE, intent); 723845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan } catch (PendingIntent.CanceledException e) { 724845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan Log.w(TAG, "pendingIntent is canceled, drop incoming call"); 725845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan session.endCall(); 7269c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 7279c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 7289c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 7299c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 7309c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan @Override 7319c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public void onError(ISipSession session, int errorCode, 7329c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan String message) { 7339c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (DEBUG) Log.d(TAG, "sip session error: " 7349c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan + SipErrorCode.toString(errorCode) + ": " + message); 7359c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 7369c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 737617479363dcafe01bfa1fa025e1d9d122864a0ceHung-ying Tyan public boolean isOpenedToReceiveCalls() { 738617479363dcafe01bfa1fa025e1d9d122864a0ceHung-ying Tyan return mOpenedToReceiveCalls; 7399c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 7409c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 7419c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public boolean isRegistered() { 7429c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return mAutoRegistration.isRegistered(); 7439c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 7449c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 7459c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private String getUri() { 7469c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return mSipGroup.getLocalProfileUri(); 7479c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 7489c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 7499c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 75087e304ce2e55588dfbec18406bf910e5adcfa3a4Chung-yih Wang private class WifiScanProcess implements Runnable { 75187e304ce2e55588dfbec18406bf910e5adcfa3a4Chung-yih Wang private static final String TAG = "\\WIFI_SCAN/"; 75287e304ce2e55588dfbec18406bf910e5adcfa3a4Chung-yih Wang private static final int INTERVAL = 60; 75387e304ce2e55588dfbec18406bf910e5adcfa3a4Chung-yih Wang private boolean mRunning = false; 75487e304ce2e55588dfbec18406bf910e5adcfa3a4Chung-yih Wang 75587e304ce2e55588dfbec18406bf910e5adcfa3a4Chung-yih Wang private WifiManager mWifiManager; 75687e304ce2e55588dfbec18406bf910e5adcfa3a4Chung-yih Wang 75787e304ce2e55588dfbec18406bf910e5adcfa3a4Chung-yih Wang public void start() { 75887e304ce2e55588dfbec18406bf910e5adcfa3a4Chung-yih Wang if (mRunning) return; 75987e304ce2e55588dfbec18406bf910e5adcfa3a4Chung-yih Wang mRunning = true; 76087e304ce2e55588dfbec18406bf910e5adcfa3a4Chung-yih Wang mTimer.set(INTERVAL * 1000, this); 76187e304ce2e55588dfbec18406bf910e5adcfa3a4Chung-yih Wang } 76287e304ce2e55588dfbec18406bf910e5adcfa3a4Chung-yih Wang 76387e304ce2e55588dfbec18406bf910e5adcfa3a4Chung-yih Wang WifiScanProcess() { 76487e304ce2e55588dfbec18406bf910e5adcfa3a4Chung-yih Wang mWifiManager = (WifiManager) 76587e304ce2e55588dfbec18406bf910e5adcfa3a4Chung-yih Wang mContext.getSystemService(Context.WIFI_SERVICE); 76687e304ce2e55588dfbec18406bf910e5adcfa3a4Chung-yih Wang } 76787e304ce2e55588dfbec18406bf910e5adcfa3a4Chung-yih Wang 76887e304ce2e55588dfbec18406bf910e5adcfa3a4Chung-yih Wang public void run() { 76987e304ce2e55588dfbec18406bf910e5adcfa3a4Chung-yih Wang // scan and associate now 77087e304ce2e55588dfbec18406bf910e5adcfa3a4Chung-yih Wang if (DEBUGV) Log.v(TAG, "just wake up here for wifi scanning..."); 77187e304ce2e55588dfbec18406bf910e5adcfa3a4Chung-yih Wang mWifiManager.startScanActive(); 77287e304ce2e55588dfbec18406bf910e5adcfa3a4Chung-yih Wang } 77387e304ce2e55588dfbec18406bf910e5adcfa3a4Chung-yih Wang 77487e304ce2e55588dfbec18406bf910e5adcfa3a4Chung-yih Wang public void stop() { 77587e304ce2e55588dfbec18406bf910e5adcfa3a4Chung-yih Wang mRunning = false; 77687e304ce2e55588dfbec18406bf910e5adcfa3a4Chung-yih Wang mTimer.cancel(this); 77787e304ce2e55588dfbec18406bf910e5adcfa3a4Chung-yih Wang } 77887e304ce2e55588dfbec18406bf910e5adcfa3a4Chung-yih Wang } 77987e304ce2e55588dfbec18406bf910e5adcfa3a4Chung-yih Wang 7807d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan private class IntervalMeasurementProcess implements Runnable, 7818a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan SipSessionGroup.KeepAliveProcessCallback { 7828a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan private static final String TAG = "SipKeepAliveInterval"; 7837d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan private static final int MIN_INTERVAL = 5; // in seconds 7848a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan private static final int PASS_THRESHOLD = 10; 78544ccfb03bb349a90546ddb3dc0063cbf4aaddaf1Hung-ying Tyan private static final int MAX_RETRY_COUNT = 5; 7867d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan private static final int NAT_MEASUREMENT_RETRY_INTERVAL = 120; // in seconds 78737f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh private SipProfile mLocalProfile; 788469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang private SipSessionGroupExt mGroup; 789469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang private SipSessionGroup.SipSessionImpl mSession; 790cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan private int mMinInterval; 79144ccfb03bb349a90546ddb3dc0063cbf4aaddaf1Hung-ying Tyan private int mMaxInterval; 79244ccfb03bb349a90546ddb3dc0063cbf4aaddaf1Hung-ying Tyan private int mInterval; 79337f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh private int mPassCount; 79444ccfb03bb349a90546ddb3dc0063cbf4aaddaf1Hung-ying Tyan 795cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan public IntervalMeasurementProcess(SipProfile localProfile, 796cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan int minInterval, int maxInterval) { 797cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan mMaxInterval = maxInterval; 798cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan mMinInterval = minInterval; 79937f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh mLocalProfile = localProfile; 800469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang } 801469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang 802469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang public void start() { 8038a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan synchronized (SipService.this) { 80437f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh if (mSession != null) { 80537f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh return; 8067d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan } 80737f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh 80837f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh mInterval = (mMaxInterval + mMinInterval) / 2; 80937f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh mPassCount = 0; 81037f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh 81137f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh // Don't start measurement if the interval is too small 81237f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh if (mInterval < DEFAULT_KEEPALIVE_INTERVAL || checkTermination()) { 81337f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh Log.w(TAG, "measurement aborted; interval=[" + 81437f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh mMinInterval + "," + mMaxInterval + "]"); 81537f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh return; 81637f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh } 81737f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh 8188a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan try { 81937f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh Log.d(TAG, "start measurement w interval=" + mInterval); 82037f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh 82137f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh mGroup = new SipSessionGroupExt(mLocalProfile, null, null); 82237f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh // TODO: remove this line once SipWakeupTimer can better handle 82337f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh // variety of timeout values 82437f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh mGroup.setWakeupTimer(new SipWakeupTimer(mContext, mExecutor)); 82537f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh 82637f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh mSession = (SipSessionGroup.SipSessionImpl) 82737f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh mGroup.createSession(null); 8288a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan mSession.startKeepAliveProcess(mInterval, this); 82937f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh } catch (Throwable t) { 83037f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh onError(SipErrorCode.CLIENT_ERROR, t.toString()); 8318a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan } 8328a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan } 833469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang } 834469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang 835469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang public void stop() { 8368a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan synchronized (SipService.this) { 8377d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan if (mSession != null) { 8387d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan mSession.stopKeepAliveProcess(); 8397d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan mSession = null; 8407d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan } 84137f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh if (mGroup != null) { 84237f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh mGroup.close(); 84337f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh mGroup = null; 84437f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh } 8457d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan mTimer.cancel(this); 846469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang } 847469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang } 848469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang 8498a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan private void restart() { 850469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang synchronized (SipService.this) { 8517d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan // Return immediately if the measurement process is stopped 8527d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan if (mSession == null) return; 8537d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan 8547d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan Log.d(TAG, "restart measurement w interval=" + mInterval); 855469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang try { 8568a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan mSession.stopKeepAliveProcess(); 8577d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan mPassCount = 0; 8588a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan mSession.startKeepAliveProcess(mInterval, this); 8598a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan } catch (SipException e) { 8608a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan Log.e(TAG, "restart()", e); 861469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang } 862469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang } 863469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang } 864469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang 865cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan private boolean checkTermination() { 866cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan return ((mMaxInterval - mMinInterval) < MIN_INTERVAL); 867cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan } 868cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan 8698a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan // SipSessionGroup.KeepAliveProcessCallback 8708a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan @Override 8718a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan public void onResponse(boolean portChanged) { 8729c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan synchronized (SipService.this) { 8738a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan if (!portChanged) { 87444ccfb03bb349a90546ddb3dc0063cbf4aaddaf1Hung-ying Tyan if (++mPassCount != PASS_THRESHOLD) return; 8758a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan // update the interval, since the current interval is good to 8768a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan // keep the port mapping. 877cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan if (mKeepAliveInterval > 0) { 878cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan mLastGoodKeepAliveInterval = mKeepAliveInterval; 879cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan } 8808a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan mKeepAliveInterval = mMinInterval = mInterval; 8818a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan if (DEBUG) { 8828a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan Log.d(TAG, "measured good keepalive interval: " 8838a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan + mKeepAliveInterval); 884257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan } 8858a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan onKeepAliveIntervalChanged(); 8868a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan } else { 8878a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan // Since the rport is changed, shorten the interval. 8888a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan mMaxInterval = mInterval; 8898a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan } 890cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan if (checkTermination()) { 8918a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan // update mKeepAliveInterval and stop measurement. 8928a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan stop(); 893cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan // If all the measurements failed, we still set it to 894cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan // mMinInterval; If mMinInterval still doesn't work, a new 895cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan // measurement with min interval=DEFAULT_KEEPALIVE_INTERVAL 896cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan // will be conducted. 8978a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan mKeepAliveInterval = mMinInterval; 8988a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan if (DEBUG) { 8998a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan Log.d(TAG, "measured keepalive interval: " 9008a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan + mKeepAliveInterval); 901469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang } 9028a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan } else { 9038a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan // calculate the new interval and continue. 9048a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan mInterval = (mMaxInterval + mMinInterval) / 2; 9058a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan if (DEBUG) { 9068a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan Log.d(TAG, "current interval: " + mKeepAliveInterval 9078a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan + ", test new interval: " + mInterval); 9088a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan } 9098a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan restart(); 9109c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 9119c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 9129c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 9139c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 9148a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan // SipSessionGroup.KeepAliveProcessCallback 9158a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan @Override 9168a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan public void onError(int errorCode, String description) { 9177d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan Log.w(TAG, "interval measurement error: " + description); 9187d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan restartLater(); 9197d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan } 9207d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan 9217d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan // timeout handler 9227d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan @Override 9237d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan public void run() { 9247d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan mTimer.cancel(this); 9257d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan restart(); 9267d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan } 9277d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan 9287d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan private void restartLater() { 9298a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan synchronized (SipService.this) { 9307d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan int interval = NAT_MEASUREMENT_RETRY_INTERVAL; 9317d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan Log.d(TAG, "Retry measurement " + interval + "s later."); 9327d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan mTimer.cancel(this); 9337d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan mTimer.set(interval * 1000, this); 9348a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan } 9359c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 9369c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 9379c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 9389c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private class AutoRegistrationProcess extends SipSessionAdapter 9398a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan implements Runnable, SipSessionGroup.KeepAliveProcessCallback { 9407d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan private static final int MIN_KEEPALIVE_SUCCESS_COUNT = 10; 9418a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan private String TAG = "SipAudoReg"; 9427d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan 9439c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private SipSessionGroup.SipSessionImpl mSession; 9448a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan private SipSessionGroup.SipSessionImpl mKeepAliveSession; 9459c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private SipSessionListenerProxy mProxy = new SipSessionListenerProxy(); 9469c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private int mBackoff = 1; 9479c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private boolean mRegistered; 9489c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private long mExpiryTime; 9499c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private int mErrorCode; 9509c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private String mErrorMessage; 951d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan private boolean mRunning = false; 9529c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 9537d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan private int mKeepAliveSuccessCount = 0; 9547d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan 9559c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private String getAction() { 9569c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return toString(); 9579c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 9589c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 9599c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public void start(SipSessionGroup group) { 960d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan if (!mRunning) { 961d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan mRunning = true; 9629c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mBackoff = 1; 9639c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mSession = (SipSessionGroup.SipSessionImpl) 9649c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan group.createSession(this); 9659c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // return right away if no active network connection. 9669c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (mSession == null) return; 9679c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 9689c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // start unregistration to clear up old registration at server 9699c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // TODO: when rfc5626 is deployed, use reg-id and sip.instance 9709c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // in registration to avoid adding duplicate entries to server 971257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan mMyWakeLock.acquire(mSession); 9729c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mSession.unregister(); 9738a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan if (DEBUG) TAG = mSession.getLocalProfile().getUriString(); 9748a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan if (DEBUG) Log.d(TAG, "start AutoRegistrationProcess"); 9759c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 9769c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 9779c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 9787d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan private void startKeepAliveProcess(int interval) { 9797d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan Log.d(TAG, "start keepalive w interval=" + interval); 9807d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan if (mKeepAliveSession == null) { 9817d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan mKeepAliveSession = mSession.duplicate(); 9827d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan } else { 9837d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan mKeepAliveSession.stopKeepAliveProcess(); 9847d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan } 9857d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan try { 9867d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan mKeepAliveSession.startKeepAliveProcess(interval, this); 9877d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan } catch (SipException e) { 9887d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan Log.e(TAG, "failed to start keepalive w interval=" + interval, 9897d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan e); 9907d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan } 9917d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan } 9927d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan 9937d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan private void stopKeepAliveProcess() { 9947d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan if (mKeepAliveSession != null) { 9957d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan mKeepAliveSession.stopKeepAliveProcess(); 9967d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan mKeepAliveSession = null; 9977d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan } 9987d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan mKeepAliveSuccessCount = 0; 9997d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan } 10007d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan 10018a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan // SipSessionGroup.KeepAliveProcessCallback 10028a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan @Override 10038a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan public void onResponse(boolean portChanged) { 10048a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan synchronized (SipService.this) { 100544ccfb03bb349a90546ddb3dc0063cbf4aaddaf1Hung-ying Tyan if (portChanged) { 10067d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan int interval = getKeepAliveInterval(); 10077d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan if (mKeepAliveSuccessCount < MIN_KEEPALIVE_SUCCESS_COUNT) { 10087d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan Log.i(TAG, "keepalive doesn't work with interval " 10097d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan + interval + ", past success count=" 10107d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan + mKeepAliveSuccessCount); 10117d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan if (interval > DEFAULT_KEEPALIVE_INTERVAL) { 10127d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan restartPortMappingLifetimeMeasurement( 10137d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan mSession.getLocalProfile(), interval); 10147d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan mKeepAliveSuccessCount = 0; 10157d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan } 10167d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan } else { 10177d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan Log.i(TAG, "keep keepalive going with interval " 10187d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan + interval + ", past success count=" 10197d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan + mKeepAliveSuccessCount); 10207d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan mKeepAliveSuccessCount /= 2; 10217d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan } 102244ccfb03bb349a90546ddb3dc0063cbf4aaddaf1Hung-ying Tyan } else { 102344ccfb03bb349a90546ddb3dc0063cbf4aaddaf1Hung-ying Tyan // Start keep-alive interval measurement on the first 102444ccfb03bb349a90546ddb3dc0063cbf4aaddaf1Hung-ying Tyan // successfully kept-alive SipSessionGroup 102544ccfb03bb349a90546ddb3dc0063cbf4aaddaf1Hung-ying Tyan startPortMappingLifetimeMeasurement( 102644ccfb03bb349a90546ddb3dc0063cbf4aaddaf1Hung-ying Tyan mSession.getLocalProfile()); 10277d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan mKeepAliveSuccessCount++; 102844ccfb03bb349a90546ddb3dc0063cbf4aaddaf1Hung-ying Tyan } 10298a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan 10308a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan if (!mRunning || !portChanged) return; 10319dbe2c72276b9968593054dcfd39fd5135a574aaHung-ying Tyan 10329dbe2c72276b9968593054dcfd39fd5135a574aaHung-ying Tyan // The keep alive process is stopped when port is changed; 10339dbe2c72276b9968593054dcfd39fd5135a574aaHung-ying Tyan // Nullify the session so that the process can be restarted 10349dbe2c72276b9968593054dcfd39fd5135a574aaHung-ying Tyan // again when the re-registration is done 10359dbe2c72276b9968593054dcfd39fd5135a574aaHung-ying Tyan mKeepAliveSession = null; 10369dbe2c72276b9968593054dcfd39fd5135a574aaHung-ying Tyan 10378a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan // Acquire wake lock for the registration process. The 10388a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan // lock will be released when registration is complete. 10398a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan mMyWakeLock.acquire(mSession); 10408a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan mSession.register(EXPIRY_TIME); 10418a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan } 10428a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan } 10438a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan 10448a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan // SipSessionGroup.KeepAliveProcessCallback 10458a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan @Override 10468a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan public void onError(int errorCode, String description) { 10478a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan Log.e(TAG, "keepalive error: " + description); 104844ccfb03bb349a90546ddb3dc0063cbf4aaddaf1Hung-ying Tyan onResponse(true); // re-register immediately 10498a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan } 10508a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan 10519c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public void stop() { 1052d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan if (!mRunning) return; 1053d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan mRunning = false; 1054257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan mMyWakeLock.release(mSession); 1055257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan if (mSession != null) { 1056257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan mSession.setListener(null); 1057257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan if (mConnected && mRegistered) mSession.unregister(); 1058257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan } 1059d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan 10609c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mTimer.cancel(this); 10617d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan stopKeepAliveProcess(); 10629c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 1063d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan mRegistered = false; 1064d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan setListener(mProxy.getListener()); 10659c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 10669c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 10678a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan public void onKeepAliveIntervalChanged() { 10688a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan if (mKeepAliveSession != null) { 10698a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan int newInterval = getKeepAliveInterval(); 10708a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan if (DEBUGV) { 10718a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan Log.v(TAG, "restart keepalive w interval=" + newInterval); 10728a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan } 10737d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan mKeepAliveSuccessCount = 0; 10747d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan startKeepAliveProcess(newInterval); 10758a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan } 10768a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan } 10778a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan 10789c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public void setListener(ISipSessionListener listener) { 10799c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan synchronized (SipService.this) { 10809c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mProxy.setListener(listener); 10819c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 10829c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan try { 10839c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan int state = (mSession == null) 10849c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan ? SipSession.State.READY_TO_CALL 10859c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan : mSession.getState(); 10869c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if ((state == SipSession.State.REGISTERING) 10879c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan || (state == SipSession.State.DEREGISTERING)) { 10889c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mProxy.onRegistering(mSession); 10899c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else if (mRegistered) { 10909c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan int duration = (int) 10919c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan (mExpiryTime - SystemClock.elapsedRealtime()); 10929c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mProxy.onRegistrationDone(mSession, duration); 10939c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else if (mErrorCode != SipErrorCode.NO_ERROR) { 10949c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (mErrorCode == SipErrorCode.TIME_OUT) { 10959c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mProxy.onRegistrationTimeout(mSession); 10969c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else { 10979c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mProxy.onRegistrationFailed(mSession, mErrorCode, 10989c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mErrorMessage); 10999c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 1100d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan } else if (!mConnected) { 1101d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan mProxy.onRegistrationFailed(mSession, 1102d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan SipErrorCode.DATA_CONNECTION_LOST, 1103d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan "no data connection"); 1104d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan } else if (!mRunning) { 1105d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan mProxy.onRegistrationFailed(mSession, 1106d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan SipErrorCode.CLIENT_ERROR, 1107d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan "registration not running"); 1108d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan } else { 1109d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan mProxy.onRegistrationFailed(mSession, 1110d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan SipErrorCode.IN_PROGRESS, 1111d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan String.valueOf(state)); 11129c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 11139c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } catch (Throwable t) { 11149c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Log.w(TAG, "setListener(): " + t); 11159c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 11169c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 11179c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 11189c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 11199c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public boolean isRegistered() { 11209c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return mRegistered; 11219c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 11229c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 1123257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan // timeout handler: re-register 11248a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan @Override 11259c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public void run() { 1126d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan synchronized (SipService.this) { 1127d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan if (!mRunning) return; 1128d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan 1129d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan mErrorCode = SipErrorCode.NO_ERROR; 1130d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan mErrorMessage = null; 11318a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan if (DEBUG) Log.d(TAG, "registering"); 1132257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan if (mConnected) { 1133257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan mMyWakeLock.acquire(mSession); 1134257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan mSession.register(EXPIRY_TIME); 1135257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan } 11369c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 11379c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 11389c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 11399c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private void restart(int duration) { 11409c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (DEBUG) Log.d(TAG, "Refresh registration " + duration + "s later."); 11419c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mTimer.cancel(this); 11429c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mTimer.set(duration * 1000, this); 11439c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 11449c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 11459c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private int backoffDuration() { 11469c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan int duration = SHORT_EXPIRY_TIME * mBackoff; 11479c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (duration > 3600) { 11489c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan duration = 3600; 11499c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else { 11509c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mBackoff *= 2; 11519c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 11529c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return duration; 11539c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 11549c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 11559c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan @Override 11569c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public void onRegistering(ISipSession session) { 11579c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (DEBUG) Log.d(TAG, "onRegistering(): " + session); 11589c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan synchronized (SipService.this) { 1159d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan if (notCurrentSession(session)) return; 1160d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan 11619c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mRegistered = false; 11629c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mProxy.onRegistering(session); 11639c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 11649c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 11659c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 1166d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan private boolean notCurrentSession(ISipSession session) { 1167d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan if (session != mSession) { 1168d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan ((SipSessionGroup.SipSessionImpl) session).setListener(null); 1169257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan mMyWakeLock.release(session); 1170d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan return true; 1171d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan } 1172d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan return !mRunning; 1173d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan } 1174d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan 11759c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan @Override 11769c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public void onRegistrationDone(ISipSession session, int duration) { 11779c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (DEBUG) Log.d(TAG, "onRegistrationDone(): " + session); 11789c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan synchronized (SipService.this) { 1179d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan if (notCurrentSession(session)) return; 11809c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 11819c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mProxy.onRegistrationDone(session, duration); 11829c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 11839c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (duration > 0) { 11849c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mExpiryTime = SystemClock.elapsedRealtime() 11859c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan + (duration * 1000); 11869c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 11879c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (!mRegistered) { 11889c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mRegistered = true; 11899c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // allow some overlap to avoid call drop during renew 11909c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan duration -= MIN_EXPIRY_TIME; 11919c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (duration < MIN_EXPIRY_TIME) { 11929c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan duration = MIN_EXPIRY_TIME; 11939c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 11949c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan restart(duration); 11959c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 11968a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan SipProfile localProfile = mSession.getLocalProfile(); 11978a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan if ((mKeepAliveSession == null) && (isBehindNAT(mLocalIp) 11988a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan || localProfile.getSendKeepAlive())) { 11997d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan startKeepAliveProcess(getKeepAliveInterval()); 12009c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 12019c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 1202257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan mMyWakeLock.release(session); 12039c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else { 12049c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mRegistered = false; 12059c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mExpiryTime = -1L; 12069c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (DEBUG) Log.d(TAG, "Refresh registration immediately"); 12079c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan run(); 12089c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 12099c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 12109c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 12119c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 12129c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan @Override 12139c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public void onRegistrationFailed(ISipSession session, int errorCode, 12149c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan String message) { 12159c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (DEBUG) Log.d(TAG, "onRegistrationFailed(): " + session + ": " 12169c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan + SipErrorCode.toString(errorCode) + ": " + message); 12179c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan synchronized (SipService.this) { 1218d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan if (notCurrentSession(session)) return; 12199c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 1220fcc474636f42243cfce960158373b9c49636a556Hung-ying Tyan switch (errorCode) { 1221fcc474636f42243cfce960158373b9c49636a556Hung-ying Tyan case SipErrorCode.INVALID_CREDENTIALS: 1222fcc474636f42243cfce960158373b9c49636a556Hung-ying Tyan case SipErrorCode.SERVER_UNREACHABLE: 1223fcc474636f42243cfce960158373b9c49636a556Hung-ying Tyan if (DEBUG) Log.d(TAG, " pause auto-registration"); 1224fcc474636f42243cfce960158373b9c49636a556Hung-ying Tyan stop(); 12250b88a073712b1510db7c636f89c4e19f0131449aHung-ying Tyan break; 1226fcc474636f42243cfce960158373b9c49636a556Hung-ying Tyan default: 1227fcc474636f42243cfce960158373b9c49636a556Hung-ying Tyan restartLater(); 12289c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 1229d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan 1230d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan mErrorCode = errorCode; 1231d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan mErrorMessage = message; 1232d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan mProxy.onRegistrationFailed(session, errorCode, message); 1233257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan mMyWakeLock.release(session); 12349c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 12359c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 12369c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 12379c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan @Override 12389c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public void onRegistrationTimeout(ISipSession session) { 12399c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (DEBUG) Log.d(TAG, "onRegistrationTimeout(): " + session); 12409c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan synchronized (SipService.this) { 1241d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan if (notCurrentSession(session)) return; 1242d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan 12439c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mErrorCode = SipErrorCode.TIME_OUT; 12449c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mProxy.onRegistrationTimeout(session); 1245fcc474636f42243cfce960158373b9c49636a556Hung-ying Tyan restartLater(); 1246257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan mMyWakeLock.release(session); 12479c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 12489c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 12499c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 1250fcc474636f42243cfce960158373b9c49636a556Hung-ying Tyan private void restartLater() { 12519c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mRegistered = false; 12529c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan restart(backoffDuration()); 12539c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 12549c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 12559c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 12569c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private class ConnectivityReceiver extends BroadcastReceiver { 12579c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private Timer mTimer = new Timer(); 12589c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private MyTimerTask mTask; 12599c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 12609c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan @Override 1261257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan public void onReceive(final Context context, final Intent intent) { 1262257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan // Run the handler in MyExecutor to be protected by wake lock 12634cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan mExecutor.execute(new Runnable() { 1264257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan public void run() { 1265257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan onReceiveInternal(context, intent); 1266257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan } 1267257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan }); 1268257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan } 1269257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan 1270257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan private void onReceiveInternal(Context context, Intent intent) { 12719c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan String action = intent.getAction(); 12729c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) { 12739c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Bundle b = intent.getExtras(); 12749c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (b != null) { 12759c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan NetworkInfo netInfo = (NetworkInfo) 12769c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan b.get(ConnectivityManager.EXTRA_NETWORK_INFO); 12779c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan String type = netInfo.getTypeName(); 12789c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan NetworkInfo.State state = netInfo.getState(); 12799c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 12809c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (mWifiOnly && (netInfo.getType() != 12819c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan ConnectivityManager.TYPE_WIFI)) { 12829c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (DEBUG) { 12839c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Log.d(TAG, "Wifi only, other connectivity ignored: " 12849c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan + type); 12859c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 12869c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return; 12879c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 12889c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 12899c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan NetworkInfo activeNetInfo = getActiveNetworkInfo(); 12909c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (DEBUG) { 12919c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (activeNetInfo != null) { 12929c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Log.d(TAG, "active network: " 12939c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan + activeNetInfo.getTypeName() 12949c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan + ((activeNetInfo.getState() == NetworkInfo.State.CONNECTED) 12959c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan ? " CONNECTED" : " DISCONNECTED")); 12969c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else { 12979c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Log.d(TAG, "active network: null"); 12989c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 12999c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 13009c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if ((state == NetworkInfo.State.CONNECTED) 13019c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan && (activeNetInfo != null) 13029c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan && (activeNetInfo.getType() != netInfo.getType())) { 13039c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (DEBUG) Log.d(TAG, "ignore connect event: " + type 13049c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan + ", active: " + activeNetInfo.getTypeName()); 13059c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return; 13069c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 13079c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 13089c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (state == NetworkInfo.State.CONNECTED) { 13099c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (DEBUG) Log.d(TAG, "Connectivity alert: CONNECTED " + type); 13109c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan onChanged(type, true); 13119c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else if (state == NetworkInfo.State.DISCONNECTED) { 13129c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (DEBUG) Log.d(TAG, "Connectivity alert: DISCONNECTED " + type); 13139c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan onChanged(type, false); 13149c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else { 13159c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (DEBUG) Log.d(TAG, "Connectivity alert not processed: " 13169c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan + state + " " + type); 13179c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 13189c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 13199c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 13209c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 13219c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 13229c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private NetworkInfo getActiveNetworkInfo() { 13239c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan ConnectivityManager cm = (ConnectivityManager) 13249c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mContext.getSystemService(Context.CONNECTIVITY_SERVICE); 13259c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return cm.getActiveNetworkInfo(); 13269c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 13279c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 13289c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private void onChanged(String type, boolean connected) { 13299c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan synchronized (SipService.this) { 13309c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // When turning on WIFI, it needs some time for network 13319c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // connectivity to get stabile so we defer good news (because 13329c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // we want to skip the interim ones) but deliver bad news 13339c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // immediately 13349c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (connected) { 1335f4a38e8e2f83402d2307edf67ef79b6f74990c8bHung-ying Tyan if (mTask != null) { 1336f4a38e8e2f83402d2307edf67ef79b6f74990c8bHung-ying Tyan mTask.cancel(); 1337f4a38e8e2f83402d2307edf67ef79b6f74990c8bHung-ying Tyan mMyWakeLock.release(mTask); 1338f4a38e8e2f83402d2307edf67ef79b6f74990c8bHung-ying Tyan } 13399c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mTask = new MyTimerTask(type, connected); 13409c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mTimer.schedule(mTask, 2 * 1000L); 1341257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan // hold wakup lock so that we can finish changes before the 1342257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan // device goes to sleep 1343257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan mMyWakeLock.acquire(mTask); 13449c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else { 13459c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if ((mTask != null) && mTask.mNetworkType.equals(type)) { 13469c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mTask.cancel(); 1347257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan mMyWakeLock.release(mTask); 13489c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 13499c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan onConnectivityChanged(type, false); 13509c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 13519c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 13529c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 13539c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 13549c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private class MyTimerTask extends TimerTask { 13559c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private boolean mConnected; 13569c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private String mNetworkType; 13579c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 13589c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public MyTimerTask(String type, boolean connected) { 13599c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mNetworkType = type; 13609c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mConnected = connected; 13619c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 13629c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 1363d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan // timeout handler 13649c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan @Override 13659c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public void run() { 13669c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // delegate to mExecutor 13674cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan mExecutor.execute(new Runnable() { 13689c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public void run() { 13699c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan realRun(); 13709c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 13719c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan }); 13729c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 13739c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 13749c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private void realRun() { 13759c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan synchronized (SipService.this) { 13769c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (mTask != this) { 13779c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Log.w(TAG, " unexpected task: " + mNetworkType 13789c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan + (mConnected ? " CONNECTED" : "DISCONNECTED")); 1379f4a38e8e2f83402d2307edf67ef79b6f74990c8bHung-ying Tyan mMyWakeLock.release(this); 13809c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return; 13819c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 13829c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mTask = null; 13839c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (DEBUG) Log.d(TAG, " deliver change for " + mNetworkType 13849c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan + (mConnected ? " CONNECTED" : "DISCONNECTED")); 13859c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan onConnectivityChanged(mNetworkType, mConnected); 1386257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan mMyWakeLock.release(this); 13879c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 13889c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 13899c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 13909c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 13919c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 1392257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan private static Looper createLooper() { 1393257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan HandlerThread thread = new HandlerThread("SipService.Executor"); 1394257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan thread.start(); 1395257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan return thread.getLooper(); 1396257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan } 1397257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan 1398257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan // Executes immediate tasks in a single thread. 1399257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan // Hold/release wake lock for running tasks 14004cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan private class MyExecutor extends Handler implements Executor { 14019c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan MyExecutor() { 14029c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan super(createLooper()); 14039c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 14049c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 14054cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan @Override 14064cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan public void execute(Runnable task) { 1407257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan mMyWakeLock.acquire(task); 14089c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Message.obtain(this, 0/* don't care */, task).sendToTarget(); 14099c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 14109c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 14119c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan @Override 14129c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public void handleMessage(Message msg) { 14139c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (msg.obj instanceof Runnable) { 1414257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan executeInternal((Runnable) msg.obj); 14159c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else { 14169c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Log.w(TAG, "can't handle msg: " + msg); 14179c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 14189c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 1419257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan 1420257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan private void executeInternal(Runnable task) { 1421257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan try { 1422257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan task.run(); 1423257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan } catch (Throwable t) { 1424257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan Log.e(TAG, "run task: " + task, t); 1425257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan } finally { 1426257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan mMyWakeLock.release(task); 1427257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan } 1428257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan } 1429257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan } 14309c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan} 1431