SipService.java revision dc7545495e1ef8bad32cd78775f4dc072015eea0
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; 639c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport javax.sip.SipException; 649c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 659c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan/** 669c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan * @hide 679c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan */ 689c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanpublic final class SipService extends ISipService.Stub { 69acedadc1967457ac2f8981c67f884fd8c0ee853cHung-ying Tyan static final String TAG = "SipService"; 70acedadc1967457ac2f8981c67f884fd8c0ee853cHung-ying Tyan static final boolean DEBUGV = false; 716d9d99615a30de0675271553552c3c7b49311354Joe Onorato private static final boolean DEBUG = false; 729c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private static final boolean DEBUG_TIMER = DEBUG && false; 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; 769c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 779c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private Context mContext; 789c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private String mLocalIp; 799c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private String mNetworkType; 809c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private boolean mConnected; 819c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private WakeupTimer mTimer; 8287e304ce2e55588dfbec18406bf910e5adcfa3a4Chung-yih Wang private WifiScanProcess mWifiScanProcess; 839c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private WifiManager.WifiLock mWifiLock; 849c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private boolean mWifiOnly; 859c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 869c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private MyExecutor mExecutor; 879c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 889c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // SipProfile URI --> group 899c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private Map<String, SipSessionGroupExt> mSipGroups = 909c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan new HashMap<String, SipSessionGroupExt>(); 919c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 929c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // session ID --> session 939c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private Map<String, ISipSession> mPendingSessions = 949c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan new HashMap<String, ISipSession>(); 959c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 969c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private ConnectivityReceiver mConnectivityReceiver; 979abf73f1bde7b1617603c888650dbda9d6a7fddfHung-ying Tyan private boolean mWifiEnabled; 98acedadc1967457ac2f8981c67f884fd8c0ee853cHung-ying Tyan private SipWakeLock mMyWakeLock; 999c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 1009c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan /** 1019c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan * Starts the SIP service. Do nothing if the SIP API is not supported on the 1029c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan * device. 1039c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan */ 1049c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public static void start(Context context) { 1059c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (SipManager.isApiSupported(context)) { 1069c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan ServiceManager.addService("sip", new SipService(context)); 10722523a59d879cf47f1e9c202d001d569fad4f69eHung-ying Tyan context.sendBroadcast(new Intent(SipManager.ACTION_SIP_SERVICE_UP)); 108dc7545495e1ef8bad32cd78775f4dc072015eea0Hung-ying Tyan if (DEBUG) Log.d(TAG, "SIP service started"); 1099c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 1109c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 1119c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 1129c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private SipService(Context context) { 1139c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (DEBUG) Log.d(TAG, " service started!"); 1149c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mContext = context; 1159c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mConnectivityReceiver = new ConnectivityReceiver(); 116acedadc1967457ac2f8981c67f884fd8c0ee853cHung-ying Tyan mMyWakeLock = new SipWakeLock((PowerManager) 117257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan context.getSystemService(Context.POWER_SERVICE)); 1189c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 1199c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mTimer = new WakeupTimer(context); 1209c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mWifiOnly = SipManager.isSipWifiOnly(context); 1219c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 1229c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 123dc7545495e1ef8bad32cd78775f4dc072015eea0Hung-ying Tyan private BroadcastReceiver mWifiStateReceiver = new BroadcastReceiver() { 124f452fd81f1a308428b0bfbae883fddb9caced878Chung-yih Wang @Override 125f452fd81f1a308428b0bfbae883fddb9caced878Chung-yih Wang public void onReceive(Context context, Intent intent) { 126f452fd81f1a308428b0bfbae883fddb9caced878Chung-yih Wang String action = intent.getAction(); 1279abf73f1bde7b1617603c888650dbda9d6a7fddfHung-ying Tyan if (WifiManager.WIFI_STATE_CHANGED_ACTION.equals(action)) { 1289abf73f1bde7b1617603c888650dbda9d6a7fddfHung-ying Tyan int state = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, 1299abf73f1bde7b1617603c888650dbda9d6a7fddfHung-ying Tyan WifiManager.WIFI_STATE_UNKNOWN); 1309abf73f1bde7b1617603c888650dbda9d6a7fddfHung-ying Tyan synchronized (SipService.this) { 1319abf73f1bde7b1617603c888650dbda9d6a7fddfHung-ying Tyan switch (state) { 1329abf73f1bde7b1617603c888650dbda9d6a7fddfHung-ying Tyan case WifiManager.WIFI_STATE_ENABLED: 1339abf73f1bde7b1617603c888650dbda9d6a7fddfHung-ying Tyan mWifiEnabled = true; 134617479363dcafe01bfa1fa025e1d9d122864a0ceHung-ying Tyan if (anyOpenedToReceiveCalls()) grabWifiLock(); 1359abf73f1bde7b1617603c888650dbda9d6a7fddfHung-ying Tyan break; 1369abf73f1bde7b1617603c888650dbda9d6a7fddfHung-ying Tyan case WifiManager.WIFI_STATE_DISABLED: 1379abf73f1bde7b1617603c888650dbda9d6a7fddfHung-ying Tyan mWifiEnabled = false; 1389abf73f1bde7b1617603c888650dbda9d6a7fddfHung-ying Tyan releaseWifiLock(); 1399abf73f1bde7b1617603c888650dbda9d6a7fddfHung-ying Tyan break; 1409abf73f1bde7b1617603c888650dbda9d6a7fddfHung-ying Tyan } 1419abf73f1bde7b1617603c888650dbda9d6a7fddfHung-ying Tyan } 142f452fd81f1a308428b0bfbae883fddb9caced878Chung-yih Wang } 143f452fd81f1a308428b0bfbae883fddb9caced878Chung-yih Wang } 144f452fd81f1a308428b0bfbae883fddb9caced878Chung-yih Wang }; 145f452fd81f1a308428b0bfbae883fddb9caced878Chung-yih Wang 146dc7545495e1ef8bad32cd78775f4dc072015eea0Hung-ying Tyan private void registerReceivers() { 147dc7545495e1ef8bad32cd78775f4dc072015eea0Hung-ying Tyan mContext.registerReceiver(mConnectivityReceiver, 148dc7545495e1ef8bad32cd78775f4dc072015eea0Hung-ying Tyan new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION)); 149dc7545495e1ef8bad32cd78775f4dc072015eea0Hung-ying Tyan mContext.registerReceiver(mWifiStateReceiver, 150dc7545495e1ef8bad32cd78775f4dc072015eea0Hung-ying Tyan new IntentFilter(WifiManager.WIFI_STATE_CHANGED_ACTION)); 151dc7545495e1ef8bad32cd78775f4dc072015eea0Hung-ying Tyan if (DEBUG) Log.d(TAG, " +++ register receivers"); 152dc7545495e1ef8bad32cd78775f4dc072015eea0Hung-ying Tyan } 153dc7545495e1ef8bad32cd78775f4dc072015eea0Hung-ying Tyan 154dc7545495e1ef8bad32cd78775f4dc072015eea0Hung-ying Tyan private void unregisterReceivers() { 155dc7545495e1ef8bad32cd78775f4dc072015eea0Hung-ying Tyan mContext.unregisterReceiver(mConnectivityReceiver); 156dc7545495e1ef8bad32cd78775f4dc072015eea0Hung-ying Tyan mContext.unregisterReceiver(mWifiStateReceiver); 157dc7545495e1ef8bad32cd78775f4dc072015eea0Hung-ying Tyan if (DEBUG) Log.d(TAG, " --- unregister receivers"); 158dc7545495e1ef8bad32cd78775f4dc072015eea0Hung-ying Tyan } 159dc7545495e1ef8bad32cd78775f4dc072015eea0Hung-ying Tyan 1609c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private MyExecutor getExecutor() { 1619c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // create mExecutor lazily 1629c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (mExecutor == null) mExecutor = new MyExecutor(); 1639c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return mExecutor; 1649c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 1659c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 1669c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public synchronized SipProfile[] getListOfProfiles() { 1678127b35b75c13f853dc8eb2fed8bba4bf99e3eedHung-ying Tyan mContext.enforceCallingOrSelfPermission( 1688127b35b75c13f853dc8eb2fed8bba4bf99e3eedHung-ying Tyan android.Manifest.permission.USE_SIP, null); 169a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan boolean isCallerRadio = isCallerRadio(); 170a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan ArrayList<SipProfile> profiles = new ArrayList<SipProfile>(); 1719c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan for (SipSessionGroupExt group : mSipGroups.values()) { 172a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan if (isCallerRadio || isCallerCreator(group)) { 173a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan profiles.add(group.getLocalProfile()); 174a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan } 1759c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 176a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan return profiles.toArray(new SipProfile[profiles.size()]); 1779c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 1789c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 179dc7545495e1ef8bad32cd78775f4dc072015eea0Hung-ying Tyan public synchronized void open(SipProfile localProfile) { 1808127b35b75c13f853dc8eb2fed8bba4bf99e3eedHung-ying Tyan mContext.enforceCallingOrSelfPermission( 1818127b35b75c13f853dc8eb2fed8bba4bf99e3eedHung-ying Tyan android.Manifest.permission.USE_SIP, null); 1829c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan localProfile.setCallingUid(Binder.getCallingUid()); 1839c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan try { 184dc7545495e1ef8bad32cd78775f4dc072015eea0Hung-ying Tyan boolean addingFirstProfile = mSipGroups.isEmpty(); 1859c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan createGroup(localProfile); 186dc7545495e1ef8bad32cd78775f4dc072015eea0Hung-ying Tyan if (addingFirstProfile && !mSipGroups.isEmpty()) registerReceivers(); 1879c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } catch (SipException e) { 1889c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Log.e(TAG, "openToMakeCalls()", e); 1899c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // TODO: how to send the exception back 1909c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 1919c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 1929c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 1939c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public synchronized void open3(SipProfile localProfile, 194845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan PendingIntent incomingCallPendingIntent, 195845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan ISipSessionListener listener) { 1968127b35b75c13f853dc8eb2fed8bba4bf99e3eedHung-ying Tyan mContext.enforceCallingOrSelfPermission( 1978127b35b75c13f853dc8eb2fed8bba4bf99e3eedHung-ying Tyan android.Manifest.permission.USE_SIP, null); 1989c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan localProfile.setCallingUid(Binder.getCallingUid()); 199845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan if (incomingCallPendingIntent == null) { 200845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan Log.w(TAG, "incomingCallPendingIntent cannot be null; " 201845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan + "the profile is not opened"); 202a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan return; 2039c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 2049c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (DEBUG) Log.d(TAG, "open3: " + localProfile.getUriString() + ": " 205845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan + incomingCallPendingIntent + ": " + listener); 2069c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan try { 207dc7545495e1ef8bad32cd78775f4dc072015eea0Hung-ying Tyan boolean addingFirstProfile = mSipGroups.isEmpty(); 2089c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan SipSessionGroupExt group = createGroup(localProfile, 209845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan incomingCallPendingIntent, listener); 210dc7545495e1ef8bad32cd78775f4dc072015eea0Hung-ying Tyan if (addingFirstProfile && !mSipGroups.isEmpty()) registerReceivers(); 2119c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (localProfile.getAutoRegistration()) { 2129c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan group.openToReceiveCalls(); 2139abf73f1bde7b1617603c888650dbda9d6a7fddfHung-ying Tyan if (mWifiEnabled) grabWifiLock(); 2149c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 2159c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } catch (SipException e) { 2169c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Log.e(TAG, "openToReceiveCalls()", e); 2179c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // TODO: how to send the exception back 2189c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 2199c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 2209c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 221a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan private boolean isCallerCreator(SipSessionGroupExt group) { 222a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan SipProfile profile = group.getLocalProfile(); 223a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan return (profile.getCallingUid() == Binder.getCallingUid()); 224a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan } 225a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan 226a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan private boolean isCallerCreatorOrRadio(SipSessionGroupExt group) { 227a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan return (isCallerRadio() || isCallerCreator(group)); 228a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan } 229a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan 230a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan private boolean isCallerRadio() { 231a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan return (Binder.getCallingUid() == Process.PHONE_UID); 232a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan } 233a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan 2349c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public synchronized void close(String localProfileUri) { 2358127b35b75c13f853dc8eb2fed8bba4bf99e3eedHung-ying Tyan mContext.enforceCallingOrSelfPermission( 2368127b35b75c13f853dc8eb2fed8bba4bf99e3eedHung-ying Tyan android.Manifest.permission.USE_SIP, null); 237a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan SipSessionGroupExt group = mSipGroups.get(localProfileUri); 238a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan if (group == null) return; 239a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan if (!isCallerCreatorOrRadio(group)) { 2406d9d99615a30de0675271553552c3c7b49311354Joe Onorato Log.w(TAG, "only creator or radio can close this profile"); 241a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan return; 2429c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 243a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan 244a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan group = mSipGroups.remove(localProfileUri); 245a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan notifyProfileRemoved(group.getLocalProfile()); 246a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan group.close(); 247257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan 248617479363dcafe01bfa1fa025e1d9d122864a0ceHung-ying Tyan if (!anyOpenedToReceiveCalls()) { 249257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan releaseWifiLock(); 250257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan mMyWakeLock.reset(); // in case there's leak 251257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan } 252dc7545495e1ef8bad32cd78775f4dc072015eea0Hung-ying Tyan if (mSipGroups.isEmpty()) unregisterReceivers(); 2539c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 2549c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 2559c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public synchronized boolean isOpened(String localProfileUri) { 2568127b35b75c13f853dc8eb2fed8bba4bf99e3eedHung-ying Tyan mContext.enforceCallingOrSelfPermission( 2578127b35b75c13f853dc8eb2fed8bba4bf99e3eedHung-ying Tyan android.Manifest.permission.USE_SIP, null); 2589c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan SipSessionGroupExt group = mSipGroups.get(localProfileUri); 259a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan if (group == null) return false; 260a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan if (isCallerCreatorOrRadio(group)) { 261617479363dcafe01bfa1fa025e1d9d122864a0ceHung-ying Tyan return true; 262a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan } else { 2636d9d99615a30de0675271553552c3c7b49311354Joe Onorato Log.w(TAG, "only creator or radio can query on the profile"); 264a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan return false; 265a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan } 2669c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 2679c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 2689c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public synchronized boolean isRegistered(String localProfileUri) { 2698127b35b75c13f853dc8eb2fed8bba4bf99e3eedHung-ying Tyan mContext.enforceCallingOrSelfPermission( 2708127b35b75c13f853dc8eb2fed8bba4bf99e3eedHung-ying Tyan android.Manifest.permission.USE_SIP, null); 2719c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan SipSessionGroupExt group = mSipGroups.get(localProfileUri); 272a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan if (group == null) return false; 273a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan if (isCallerCreatorOrRadio(group)) { 274a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan return group.isRegistered(); 275a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan } else { 2766d9d99615a30de0675271553552c3c7b49311354Joe Onorato Log.w(TAG, "only creator or radio can query on the profile"); 277a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan return false; 278a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan } 2799c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 2809c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 2819c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public synchronized void setRegistrationListener(String localProfileUri, 2829c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan ISipSessionListener listener) { 2838127b35b75c13f853dc8eb2fed8bba4bf99e3eedHung-ying Tyan mContext.enforceCallingOrSelfPermission( 2848127b35b75c13f853dc8eb2fed8bba4bf99e3eedHung-ying Tyan android.Manifest.permission.USE_SIP, null); 2859c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan SipSessionGroupExt group = mSipGroups.get(localProfileUri); 286a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan if (group == null) return; 287a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan if (isCallerCreator(group)) { 288a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan group.setListener(listener); 289a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan } else { 2906d9d99615a30de0675271553552c3c7b49311354Joe Onorato Log.w(TAG, "only creator can set listener on the profile"); 291a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan } 2929c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 2939c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 2949c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public synchronized ISipSession createSession(SipProfile localProfile, 2959c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan ISipSessionListener listener) { 2968127b35b75c13f853dc8eb2fed8bba4bf99e3eedHung-ying Tyan mContext.enforceCallingOrSelfPermission( 2978127b35b75c13f853dc8eb2fed8bba4bf99e3eedHung-ying Tyan android.Manifest.permission.USE_SIP, null); 2989c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan localProfile.setCallingUid(Binder.getCallingUid()); 2999c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (!mConnected) return null; 3009c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan try { 3019c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan SipSessionGroupExt group = createGroup(localProfile); 3029c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return group.createSession(listener); 3039c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } catch (SipException e) { 3046d9d99615a30de0675271553552c3c7b49311354Joe Onorato if (DEBUG) Log.d(TAG, "createSession()", e); 3059c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return null; 3069c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 3079c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 3089c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 3099c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public synchronized ISipSession getPendingSession(String callId) { 3108127b35b75c13f853dc8eb2fed8bba4bf99e3eedHung-ying Tyan mContext.enforceCallingOrSelfPermission( 3118127b35b75c13f853dc8eb2fed8bba4bf99e3eedHung-ying Tyan android.Manifest.permission.USE_SIP, null); 3129c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (callId == null) return null; 3139c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return mPendingSessions.get(callId); 3149c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 3159c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 3169c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private String determineLocalIp() { 3179c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan try { 3189c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan DatagramSocket s = new DatagramSocket(); 3199c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan s.connect(InetAddress.getByName("192.168.1.1"), 80); 3209c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return s.getLocalAddress().getHostAddress(); 3219c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } catch (IOException e) { 3226d9d99615a30de0675271553552c3c7b49311354Joe Onorato if (DEBUG) Log.d(TAG, "determineLocalIp()", e); 3239c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // dont do anything; there should be a connectivity change going 3249c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return null; 3259c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 3269c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 3279c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 3289c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private SipSessionGroupExt createGroup(SipProfile localProfile) 3299c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan throws SipException { 3309c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan String key = localProfile.getUriString(); 3319c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan SipSessionGroupExt group = mSipGroups.get(key); 3329c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (group == null) { 3339c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan group = new SipSessionGroupExt(localProfile, null, null); 3349c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mSipGroups.put(key, group); 3359c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan notifyProfileAdded(localProfile); 336a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan } else if (!isCallerCreator(group)) { 337a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan throw new SipException("only creator can access the profile"); 3389c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 3399c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return group; 3409c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 3419c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 3429c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private SipSessionGroupExt createGroup(SipProfile localProfile, 343845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan PendingIntent incomingCallPendingIntent, 344845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan ISipSessionListener listener) throws SipException { 3459c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan String key = localProfile.getUriString(); 3469c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan SipSessionGroupExt group = mSipGroups.get(key); 3479c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (group != null) { 348a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan if (!isCallerCreator(group)) { 349a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan throw new SipException("only creator can access the profile"); 350a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan } 351845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan group.setIncomingCallPendingIntent(incomingCallPendingIntent); 3529c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan group.setListener(listener); 3539c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else { 3549c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan group = new SipSessionGroupExt(localProfile, 355845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan incomingCallPendingIntent, listener); 3569c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mSipGroups.put(key, group); 3579c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan notifyProfileAdded(localProfile); 3589c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 3599c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return group; 3609c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 3619c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 3629c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private void notifyProfileAdded(SipProfile localProfile) { 3639c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (DEBUG) Log.d(TAG, "notify: profile added: " + localProfile); 3649c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Intent intent = new Intent(SipManager.ACTION_SIP_ADD_PHONE); 3659c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan intent.putExtra(SipManager.EXTRA_LOCAL_URI, localProfile.getUriString()); 3669c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mContext.sendBroadcast(intent); 3679c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 3689c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 3699c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private void notifyProfileRemoved(SipProfile localProfile) { 3709c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (DEBUG) Log.d(TAG, "notify: profile removed: " + localProfile); 3719c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Intent intent = new Intent(SipManager.ACTION_SIP_REMOVE_PHONE); 3729c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan intent.putExtra(SipManager.EXTRA_LOCAL_URI, localProfile.getUriString()); 3739c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mContext.sendBroadcast(intent); 3749c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 3759c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 376617479363dcafe01bfa1fa025e1d9d122864a0ceHung-ying Tyan private boolean anyOpenedToReceiveCalls() { 3779c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan for (SipSessionGroupExt group : mSipGroups.values()) { 378617479363dcafe01bfa1fa025e1d9d122864a0ceHung-ying Tyan if (group.isOpenedToReceiveCalls()) return true; 3799c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 3809c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return false; 3819c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 3829c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 3839c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private void grabWifiLock() { 3849c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (mWifiLock == null) { 3859abf73f1bde7b1617603c888650dbda9d6a7fddfHung-ying Tyan if (DEBUG) Log.d(TAG, "~~~~~~~~~~~~~~~~~~~~~ acquire wifi lock"); 3869c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mWifiLock = ((WifiManager) 3879c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mContext.getSystemService(Context.WIFI_SERVICE)) 3889c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan .createWifiLock(WifiManager.WIFI_MODE_FULL, TAG); 3899c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mWifiLock.acquire(); 39087e304ce2e55588dfbec18406bf910e5adcfa3a4Chung-yih Wang if (!mConnected) startWifiScanner(); 3919c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 3929c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 3939c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 3949c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private void releaseWifiLock() { 3959c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (mWifiLock != null) { 3969abf73f1bde7b1617603c888650dbda9d6a7fddfHung-ying Tyan if (DEBUG) Log.d(TAG, "~~~~~~~~~~~~~~~~~~~~~ release wifi lock"); 3979c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mWifiLock.release(); 3989c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mWifiLock = null; 39987e304ce2e55588dfbec18406bf910e5adcfa3a4Chung-yih Wang stopWifiScanner(); 40087e304ce2e55588dfbec18406bf910e5adcfa3a4Chung-yih Wang } 40187e304ce2e55588dfbec18406bf910e5adcfa3a4Chung-yih Wang } 40287e304ce2e55588dfbec18406bf910e5adcfa3a4Chung-yih Wang 40387e304ce2e55588dfbec18406bf910e5adcfa3a4Chung-yih Wang private synchronized void startWifiScanner() { 40487e304ce2e55588dfbec18406bf910e5adcfa3a4Chung-yih Wang if (mWifiScanProcess == null) { 40587e304ce2e55588dfbec18406bf910e5adcfa3a4Chung-yih Wang mWifiScanProcess = new WifiScanProcess(); 40687e304ce2e55588dfbec18406bf910e5adcfa3a4Chung-yih Wang } 40787e304ce2e55588dfbec18406bf910e5adcfa3a4Chung-yih Wang mWifiScanProcess.start(); 40887e304ce2e55588dfbec18406bf910e5adcfa3a4Chung-yih Wang } 40987e304ce2e55588dfbec18406bf910e5adcfa3a4Chung-yih Wang 41087e304ce2e55588dfbec18406bf910e5adcfa3a4Chung-yih Wang private synchronized void stopWifiScanner() { 41187e304ce2e55588dfbec18406bf910e5adcfa3a4Chung-yih Wang if (mWifiScanProcess != null) { 41287e304ce2e55588dfbec18406bf910e5adcfa3a4Chung-yih Wang mWifiScanProcess.stop(); 4139c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 4149c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 4159c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 4169c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private synchronized void onConnectivityChanged( 4179c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan String type, boolean connected) { 4189c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (DEBUG) Log.d(TAG, "onConnectivityChanged(): " 4199c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan + mNetworkType + (mConnected? " CONNECTED" : " DISCONNECTED") 4209c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan + " --> " + type + (connected? " CONNECTED" : " DISCONNECTED")); 4219c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 4229c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan boolean sameType = type.equals(mNetworkType); 4239c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (!sameType && !connected) return; 4249c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 4259c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan boolean wasWifi = "WIFI".equalsIgnoreCase(mNetworkType); 4269c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan boolean isWifi = "WIFI".equalsIgnoreCase(type); 4279c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan boolean wifiOff = (isWifi && !connected) || (wasWifi && !sameType); 4289c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan boolean wifiOn = isWifi && connected; 4299c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 4309c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan try { 4319c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan boolean wasConnected = mConnected; 4329c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mNetworkType = type; 4339c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mConnected = connected; 4349c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 4359c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (wasConnected) { 4369c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mLocalIp = null; 4379c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan for (SipSessionGroupExt group : mSipGroups.values()) { 4389c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan group.onConnectivityChanged(false); 4399c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 4409c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 4419c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 4429c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (connected) { 4439c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mLocalIp = determineLocalIp(); 4449c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan for (SipSessionGroupExt group : mSipGroups.values()) { 4459c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan group.onConnectivityChanged(true); 4469c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 44787e304ce2e55588dfbec18406bf910e5adcfa3a4Chung-yih Wang if (isWifi && (mWifiLock != null)) stopWifiScanner(); 448257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan } else { 449257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan mMyWakeLock.reset(); // in case there's a leak 45087e304ce2e55588dfbec18406bf910e5adcfa3a4Chung-yih Wang if (isWifi && (mWifiLock != null)) startWifiScanner(); 4519c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 4529c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } catch (SipException e) { 4539c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Log.e(TAG, "onConnectivityChanged()", e); 4549c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 4559c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 4569c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 4579c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private synchronized void addPendingSession(ISipSession session) { 4589c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan try { 4593f4d44657ccad3ed02ed0e1354387b14b07dc011Hung-ying Tyan cleanUpPendingSessions(); 4609c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mPendingSessions.put(session.getCallId(), session); 4613f4d44657ccad3ed02ed0e1354387b14b07dc011Hung-ying Tyan if (DEBUG) Log.d(TAG, "#pending sess=" + mPendingSessions.size()); 4629c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } catch (RemoteException e) { 4639c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // should not happen with a local call 4649c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Log.e(TAG, "addPendingSession()", e); 4659c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 4669c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 4679c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 4683f4d44657ccad3ed02ed0e1354387b14b07dc011Hung-ying Tyan private void cleanUpPendingSessions() throws RemoteException { 4693f4d44657ccad3ed02ed0e1354387b14b07dc011Hung-ying Tyan Map.Entry<String, ISipSession>[] entries = 4703f4d44657ccad3ed02ed0e1354387b14b07dc011Hung-ying Tyan mPendingSessions.entrySet().toArray( 4713f4d44657ccad3ed02ed0e1354387b14b07dc011Hung-ying Tyan new Map.Entry[mPendingSessions.size()]); 4723f4d44657ccad3ed02ed0e1354387b14b07dc011Hung-ying Tyan for (Map.Entry<String, ISipSession> entry : entries) { 4733f4d44657ccad3ed02ed0e1354387b14b07dc011Hung-ying Tyan if (entry.getValue().getState() != SipSession.State.INCOMING_CALL) { 4743f4d44657ccad3ed02ed0e1354387b14b07dc011Hung-ying Tyan mPendingSessions.remove(entry.getKey()); 4753f4d44657ccad3ed02ed0e1354387b14b07dc011Hung-ying Tyan } 4763f4d44657ccad3ed02ed0e1354387b14b07dc011Hung-ying Tyan } 4773f4d44657ccad3ed02ed0e1354387b14b07dc011Hung-ying Tyan } 4783f4d44657ccad3ed02ed0e1354387b14b07dc011Hung-ying Tyan 479ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan private synchronized boolean callingSelf(SipSessionGroupExt ringingGroup, 480ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan SipSessionGroup.SipSessionImpl ringingSession) { 481ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan String callId = ringingSession.getCallId(); 482ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan for (SipSessionGroupExt group : mSipGroups.values()) { 483ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan if ((group != ringingGroup) && group.containsSession(callId)) { 484ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan if (DEBUG) Log.d(TAG, "call self: " 485ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan + ringingSession.getLocalProfile().getUriString() 486ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan + " -> " + group.getLocalProfile().getUriString()); 487ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan return true; 488ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan } 489ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan } 490ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan return false; 491ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan } 492ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan 493ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan 4949c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private class SipSessionGroupExt extends SipSessionAdapter { 4959c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private SipSessionGroup mSipGroup; 496845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan private PendingIntent mIncomingCallPendingIntent; 497617479363dcafe01bfa1fa025e1d9d122864a0ceHung-ying Tyan private boolean mOpenedToReceiveCalls; 4989c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 4999c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private AutoRegistrationProcess mAutoRegistration = 5009c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan new AutoRegistrationProcess(); 5019c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 5029c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public SipSessionGroupExt(SipProfile localProfile, 503845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan PendingIntent incomingCallPendingIntent, 5049c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan ISipSessionListener listener) throws SipException { 5059c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan String password = localProfile.getPassword(); 5069c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan SipProfile p = duplicate(localProfile); 5079c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mSipGroup = createSipSessionGroup(mLocalIp, p, password); 508845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan mIncomingCallPendingIntent = incomingCallPendingIntent; 5099c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mAutoRegistration.setListener(listener); 5109c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 5119c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 5129c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public SipProfile getLocalProfile() { 5139c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return mSipGroup.getLocalProfile(); 5149c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 5159c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 516ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan public boolean containsSession(String callId) { 517ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan return mSipGroup.containsSession(callId); 518ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan } 519ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan 5209c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // network connectivity is tricky because network can be disconnected 5219c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // at any instant so need to deal with exceptions carefully even when 5229c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // you think you are connected 5239c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private SipSessionGroup createSipSessionGroup(String localIp, 5249c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan SipProfile localProfile, String password) throws SipException { 5259c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan try { 526acedadc1967457ac2f8981c67f884fd8c0ee853cHung-ying Tyan return new SipSessionGroup(localIp, localProfile, password, 527acedadc1967457ac2f8981c67f884fd8c0ee853cHung-ying Tyan mMyWakeLock); 5289c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } catch (IOException e) { 5299c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // network disconnected 5309c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Log.w(TAG, "createSipSessionGroup(): network disconnected?"); 5319c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (localIp != null) { 5329c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return createSipSessionGroup(null, localProfile, password); 5339c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else { 5349c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // recursive 5356d9d99615a30de0675271553552c3c7b49311354Joe Onorato Log.wtf(TAG, "impossible! recursive!"); 5369c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan throw new RuntimeException("createSipSessionGroup"); 5379c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 5389c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 5399c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 5409c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 5419c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private SipProfile duplicate(SipProfile p) { 5429c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan try { 5439c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return new SipProfile.Builder(p).setPassword("*").build(); 5449c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } catch (Exception e) { 5459c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Log.wtf(TAG, "duplicate()", e); 5469c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan throw new RuntimeException("duplicate profile", e); 5479c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 5489c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 5499c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 5509c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public void setListener(ISipSessionListener listener) { 5519c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mAutoRegistration.setListener(listener); 5529c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 5539c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 554845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan public void setIncomingCallPendingIntent(PendingIntent pIntent) { 555845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan mIncomingCallPendingIntent = pIntent; 5569c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 5579c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 5589c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public void openToReceiveCalls() throws SipException { 559617479363dcafe01bfa1fa025e1d9d122864a0ceHung-ying Tyan mOpenedToReceiveCalls = true; 5609c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (mConnected) { 5619c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mSipGroup.openToReceiveCalls(this); 5629c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mAutoRegistration.start(mSipGroup); 5639c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 5649c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (DEBUG) Log.d(TAG, " openToReceiveCalls: " + getUri() + ": " 565845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan + mIncomingCallPendingIntent); 5669c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 5679c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 5689c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public void onConnectivityChanged(boolean connected) 5699c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan throws SipException { 5709c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mSipGroup.onConnectivityChanged(); 5719c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (connected) { 5729c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan resetGroup(mLocalIp); 573617479363dcafe01bfa1fa025e1d9d122864a0ceHung-ying Tyan if (mOpenedToReceiveCalls) openToReceiveCalls(); 5749c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else { 575617479363dcafe01bfa1fa025e1d9d122864a0ceHung-ying Tyan // close mSipGroup but remember mOpenedToReceiveCalls 5769c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (DEBUG) Log.d(TAG, " close auto reg temporarily: " 577845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan + getUri() + ": " + mIncomingCallPendingIntent); 5789c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mSipGroup.close(); 5799c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mAutoRegistration.stop(); 5809c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 5819c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 5829c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 5839c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private void resetGroup(String localIp) throws SipException { 5849c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan try { 5859c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mSipGroup.reset(localIp); 5869c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } catch (IOException e) { 5879c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // network disconnected 5889c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Log.w(TAG, "resetGroup(): network disconnected?"); 5899c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (localIp != null) { 5909c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan resetGroup(null); // reset w/o local IP 5919c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else { 5929c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // recursive 5939c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Log.wtf(TAG, "impossible!"); 5949c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan throw new RuntimeException("resetGroup"); 5959c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 5969c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 5979c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 5989c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 5999c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public void close() { 600617479363dcafe01bfa1fa025e1d9d122864a0ceHung-ying Tyan mOpenedToReceiveCalls = false; 6019c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mSipGroup.close(); 6029c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mAutoRegistration.stop(); 6039c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (DEBUG) Log.d(TAG, " close: " + getUri() + ": " 604845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan + mIncomingCallPendingIntent); 6059c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 6069c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 6079c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public ISipSession createSession(ISipSessionListener listener) { 6089c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return mSipGroup.createSession(listener); 6099c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 6109c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 6119c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan @Override 612845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan public void onRinging(ISipSession s, SipProfile caller, 6139c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan String sessionDescription) { 614acedadc1967457ac2f8981c67f884fd8c0ee853cHung-ying Tyan if (DEBUGV) Log.d(TAG, "<<<<< onRinging()"); 615845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan SipSessionGroup.SipSessionImpl session = 616845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan (SipSessionGroup.SipSessionImpl) s; 6179c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan synchronized (SipService.this) { 6189c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan try { 619ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan if (!isRegistered() || callingSelf(this, session)) { 6209c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan session.endCall(); 6219c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return; 6229c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 6239c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 6249c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // send out incoming call broadcast 6259c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan addPendingSession(session); 6269c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Intent intent = SipManager.createIncomingCallBroadcast( 627845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan session.getCallId(), sessionDescription); 6289c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (DEBUG) Log.d(TAG, " ringing~~ " + getUri() + ": " 6299c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan + caller.getUri() + ": " + session.getCallId() 630845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan + " " + mIncomingCallPendingIntent); 631845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan mIncomingCallPendingIntent.send(mContext, 632845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan SipManager.INCOMING_CALL_RESULT_CODE, intent); 633845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan } catch (PendingIntent.CanceledException e) { 634845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan Log.w(TAG, "pendingIntent is canceled, drop incoming call"); 635845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan session.endCall(); 6369c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 6379c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 6389c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 6399c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 6409c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan @Override 6419c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public void onError(ISipSession session, int errorCode, 6429c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan String message) { 6439c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (DEBUG) Log.d(TAG, "sip session error: " 6449c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan + SipErrorCode.toString(errorCode) + ": " + message); 6459c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 6469c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 647617479363dcafe01bfa1fa025e1d9d122864a0ceHung-ying Tyan public boolean isOpenedToReceiveCalls() { 648617479363dcafe01bfa1fa025e1d9d122864a0ceHung-ying Tyan return mOpenedToReceiveCalls; 6499c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 6509c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 6519c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public boolean isRegistered() { 6529c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return mAutoRegistration.isRegistered(); 6539c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 6549c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 6559c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private String getUri() { 6569c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return mSipGroup.getLocalProfileUri(); 6579c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 6589c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 6599c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 66087e304ce2e55588dfbec18406bf910e5adcfa3a4Chung-yih Wang private class WifiScanProcess implements Runnable { 66187e304ce2e55588dfbec18406bf910e5adcfa3a4Chung-yih Wang private static final String TAG = "\\WIFI_SCAN/"; 66287e304ce2e55588dfbec18406bf910e5adcfa3a4Chung-yih Wang private static final int INTERVAL = 60; 66387e304ce2e55588dfbec18406bf910e5adcfa3a4Chung-yih Wang private boolean mRunning = false; 66487e304ce2e55588dfbec18406bf910e5adcfa3a4Chung-yih Wang 66587e304ce2e55588dfbec18406bf910e5adcfa3a4Chung-yih Wang private WifiManager mWifiManager; 66687e304ce2e55588dfbec18406bf910e5adcfa3a4Chung-yih Wang 66787e304ce2e55588dfbec18406bf910e5adcfa3a4Chung-yih Wang public void start() { 66887e304ce2e55588dfbec18406bf910e5adcfa3a4Chung-yih Wang if (mRunning) return; 66987e304ce2e55588dfbec18406bf910e5adcfa3a4Chung-yih Wang mRunning = true; 67087e304ce2e55588dfbec18406bf910e5adcfa3a4Chung-yih Wang mTimer.set(INTERVAL * 1000, this); 67187e304ce2e55588dfbec18406bf910e5adcfa3a4Chung-yih Wang } 67287e304ce2e55588dfbec18406bf910e5adcfa3a4Chung-yih Wang 67387e304ce2e55588dfbec18406bf910e5adcfa3a4Chung-yih Wang WifiScanProcess() { 67487e304ce2e55588dfbec18406bf910e5adcfa3a4Chung-yih Wang mWifiManager = (WifiManager) 67587e304ce2e55588dfbec18406bf910e5adcfa3a4Chung-yih Wang mContext.getSystemService(Context.WIFI_SERVICE); 67687e304ce2e55588dfbec18406bf910e5adcfa3a4Chung-yih Wang } 67787e304ce2e55588dfbec18406bf910e5adcfa3a4Chung-yih Wang 67887e304ce2e55588dfbec18406bf910e5adcfa3a4Chung-yih Wang public void run() { 67987e304ce2e55588dfbec18406bf910e5adcfa3a4Chung-yih Wang // scan and associate now 68087e304ce2e55588dfbec18406bf910e5adcfa3a4Chung-yih Wang if (DEBUGV) Log.v(TAG, "just wake up here for wifi scanning..."); 68187e304ce2e55588dfbec18406bf910e5adcfa3a4Chung-yih Wang mWifiManager.startScanActive(); 68287e304ce2e55588dfbec18406bf910e5adcfa3a4Chung-yih Wang } 68387e304ce2e55588dfbec18406bf910e5adcfa3a4Chung-yih Wang 68487e304ce2e55588dfbec18406bf910e5adcfa3a4Chung-yih Wang public void stop() { 68587e304ce2e55588dfbec18406bf910e5adcfa3a4Chung-yih Wang mRunning = false; 68687e304ce2e55588dfbec18406bf910e5adcfa3a4Chung-yih Wang mTimer.cancel(this); 68787e304ce2e55588dfbec18406bf910e5adcfa3a4Chung-yih Wang } 68887e304ce2e55588dfbec18406bf910e5adcfa3a4Chung-yih Wang } 68987e304ce2e55588dfbec18406bf910e5adcfa3a4Chung-yih Wang 690d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan // KeepAliveProcess is controlled by AutoRegistrationProcess. 691257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan // All methods will be invoked in sync with SipService.this. 6929c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private class KeepAliveProcess implements Runnable { 6939c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private static final String TAG = "\\KEEPALIVE/"; 6949c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private static final int INTERVAL = 10; 6959c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private SipSessionGroup.SipSessionImpl mSession; 696d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan private boolean mRunning = false; 6979c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 6989c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public KeepAliveProcess(SipSessionGroup.SipSessionImpl session) { 6999c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mSession = session; 7009c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 7019c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 7029c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public void start() { 703d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan if (mRunning) return; 704d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan mRunning = true; 7059c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mTimer.set(INTERVAL * 1000, this); 7069c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 7079c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 708d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan // timeout handler 7099c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public void run() { 7109c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan synchronized (SipService.this) { 711257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan if (!mRunning) return; 712d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan 713257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan if (DEBUGV) Log.v(TAG, "~~~ keepalive: " 714257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan + mSession.getLocalProfile().getUriString()); 715257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan SipSessionGroup.SipSessionImpl session = mSession.duplicate(); 716257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan try { 717257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan session.sendKeepAlive(); 718257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan if (session.isReRegisterRequired()) { 719257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan // Acquire wake lock for the registration process. The 720257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan // lock will be released when registration is complete. 721257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan mMyWakeLock.acquire(mSession); 722257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan mSession.register(EXPIRY_TIME); 723257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan } 724257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan } catch (Throwable t) { 725257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan Log.w(TAG, "keepalive error: " + t); 7269c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 7279c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 7289c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 7299c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 7309c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public void stop() { 731257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan if (DEBUGV && (mSession != null)) Log.v(TAG, "stop keepalive:" 732257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan + mSession.getLocalProfile().getUriString()); 733d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan mRunning = false; 734d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan mSession = null; 7359c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mTimer.cancel(this); 7369c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 7379c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 7389c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 7399c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private class AutoRegistrationProcess extends SipSessionAdapter 7409c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan implements Runnable { 7419c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private SipSessionGroup.SipSessionImpl mSession; 7429c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private SipSessionListenerProxy mProxy = new SipSessionListenerProxy(); 7439c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private KeepAliveProcess mKeepAliveProcess; 7449c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private int mBackoff = 1; 7459c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private boolean mRegistered; 7469c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private long mExpiryTime; 7479c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private int mErrorCode; 7489c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private String mErrorMessage; 749d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan private boolean mRunning = false; 7509c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 7519c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private String getAction() { 7529c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return toString(); 7539c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 7549c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 7559c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public void start(SipSessionGroup group) { 756d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan if (!mRunning) { 757d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan mRunning = true; 7589c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mBackoff = 1; 7599c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mSession = (SipSessionGroup.SipSessionImpl) 7609c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan group.createSession(this); 7619c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // return right away if no active network connection. 7629c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (mSession == null) return; 7639c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 7649c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // start unregistration to clear up old registration at server 7659c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // TODO: when rfc5626 is deployed, use reg-id and sip.instance 7669c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // in registration to avoid adding duplicate entries to server 767257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan mMyWakeLock.acquire(mSession); 7689c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mSession.unregister(); 7699c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (DEBUG) Log.d(TAG, "start AutoRegistrationProcess for " 7709c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan + mSession.getLocalProfile().getUriString()); 7719c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 7729c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 7739c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 7749c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public void stop() { 775d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan if (!mRunning) return; 776d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan mRunning = false; 777257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan mMyWakeLock.release(mSession); 778257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan if (mSession != null) { 779257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan mSession.setListener(null); 780257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan if (mConnected && mRegistered) mSession.unregister(); 781257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan } 782d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan 7839c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mTimer.cancel(this); 7849c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (mKeepAliveProcess != null) { 7859c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mKeepAliveProcess.stop(); 7869c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mKeepAliveProcess = null; 7879c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 7889c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 789d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan mRegistered = false; 790d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan setListener(mProxy.getListener()); 7919c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 7929c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 7939c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public void setListener(ISipSessionListener listener) { 7949c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan synchronized (SipService.this) { 7959c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mProxy.setListener(listener); 7969c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 7979c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan try { 7989c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan int state = (mSession == null) 7999c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan ? SipSession.State.READY_TO_CALL 8009c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan : mSession.getState(); 8019c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if ((state == SipSession.State.REGISTERING) 8029c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan || (state == SipSession.State.DEREGISTERING)) { 8039c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mProxy.onRegistering(mSession); 8049c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else if (mRegistered) { 8059c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan int duration = (int) 8069c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan (mExpiryTime - SystemClock.elapsedRealtime()); 8079c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mProxy.onRegistrationDone(mSession, duration); 8089c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else if (mErrorCode != SipErrorCode.NO_ERROR) { 8099c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (mErrorCode == SipErrorCode.TIME_OUT) { 8109c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mProxy.onRegistrationTimeout(mSession); 8119c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else { 8129c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mProxy.onRegistrationFailed(mSession, mErrorCode, 8139c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mErrorMessage); 8149c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 815d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan } else if (!mConnected) { 816d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan mProxy.onRegistrationFailed(mSession, 817d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan SipErrorCode.DATA_CONNECTION_LOST, 818d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan "no data connection"); 819d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan } else if (!mRunning) { 820d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan mProxy.onRegistrationFailed(mSession, 821d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan SipErrorCode.CLIENT_ERROR, 822d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan "registration not running"); 823d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan } else { 824d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan mProxy.onRegistrationFailed(mSession, 825d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan SipErrorCode.IN_PROGRESS, 826d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan String.valueOf(state)); 8279c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 8289c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } catch (Throwable t) { 8299c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Log.w(TAG, "setListener(): " + t); 8309c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 8319c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 8329c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 8339c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 8349c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public boolean isRegistered() { 8359c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return mRegistered; 8369c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 8379c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 838257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan // timeout handler: re-register 8399c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public void run() { 840d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan synchronized (SipService.this) { 841d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan if (!mRunning) return; 842d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan 843d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan mErrorCode = SipErrorCode.NO_ERROR; 844d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan mErrorMessage = null; 845d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan if (DEBUG) Log.d(TAG, "~~~ registering"); 846257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan if (mConnected) { 847257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan mMyWakeLock.acquire(mSession); 848257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan mSession.register(EXPIRY_TIME); 849257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan } 8509c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 8519c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 8529c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 8539c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private boolean isBehindNAT(String address) { 8549c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan try { 8559c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan byte[] d = InetAddress.getByName(address).getAddress(); 8569c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if ((d[0] == 10) || 8579c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan (((0x000000FF & ((int)d[0])) == 172) && 8589c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan ((0x000000F0 & ((int)d[1])) == 16)) || 8599c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan (((0x000000FF & ((int)d[0])) == 192) && 8609c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan ((0x000000FF & ((int)d[1])) == 168))) { 8619c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return true; 8629c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 8639c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } catch (UnknownHostException e) { 8649c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Log.e(TAG, "isBehindAT()" + address, e); 8659c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 8669c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return false; 8679c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 8689c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 8699c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private void restart(int duration) { 8709c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (DEBUG) Log.d(TAG, "Refresh registration " + duration + "s later."); 8719c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mTimer.cancel(this); 8729c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mTimer.set(duration * 1000, this); 8739c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 8749c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 8759c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private int backoffDuration() { 8769c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan int duration = SHORT_EXPIRY_TIME * mBackoff; 8779c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (duration > 3600) { 8789c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan duration = 3600; 8799c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else { 8809c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mBackoff *= 2; 8819c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 8829c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return duration; 8839c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 8849c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 8859c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan @Override 8869c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public void onRegistering(ISipSession session) { 8879c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (DEBUG) Log.d(TAG, "onRegistering(): " + session); 8889c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan synchronized (SipService.this) { 889d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan if (notCurrentSession(session)) return; 890d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan 8919c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mRegistered = false; 8929c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mProxy.onRegistering(session); 8939c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 8949c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 8959c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 896d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan private boolean notCurrentSession(ISipSession session) { 897d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan if (session != mSession) { 898d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan ((SipSessionGroup.SipSessionImpl) session).setListener(null); 899257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan mMyWakeLock.release(session); 900d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan return true; 901d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan } 902d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan return !mRunning; 903d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan } 904d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan 9059c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan @Override 9069c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public void onRegistrationDone(ISipSession session, int duration) { 9079c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (DEBUG) Log.d(TAG, "onRegistrationDone(): " + session); 9089c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan synchronized (SipService.this) { 909d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan if (notCurrentSession(session)) return; 9109c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 9119c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mProxy.onRegistrationDone(session, duration); 9129c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 9139c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (duration > 0) { 9149c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mSession.clearReRegisterRequired(); 9159c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mExpiryTime = SystemClock.elapsedRealtime() 9169c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan + (duration * 1000); 9179c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 9189c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (!mRegistered) { 9199c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mRegistered = true; 9209c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // allow some overlap to avoid call drop during renew 9219c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan duration -= MIN_EXPIRY_TIME; 9229c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (duration < MIN_EXPIRY_TIME) { 9239c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan duration = MIN_EXPIRY_TIME; 9249c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 9259c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan restart(duration); 9269c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 9279c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (isBehindNAT(mLocalIp) || 9289c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mSession.getLocalProfile().getSendKeepAlive()) { 9299c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (mKeepAliveProcess == null) { 9309c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mKeepAliveProcess = 9319c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan new KeepAliveProcess(mSession); 9329c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 9339c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mKeepAliveProcess.start(); 9349c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 9359c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 936257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan mMyWakeLock.release(session); 9379c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else { 9389c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mRegistered = false; 9399c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mExpiryTime = -1L; 9409c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (DEBUG) Log.d(TAG, "Refresh registration immediately"); 9419c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan run(); 9429c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 9439c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 9449c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 9459c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 9469c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan @Override 9479c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public void onRegistrationFailed(ISipSession session, int errorCode, 9489c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan String message) { 9499c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (DEBUG) Log.d(TAG, "onRegistrationFailed(): " + session + ": " 9509c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan + SipErrorCode.toString(errorCode) + ": " + message); 9519c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan synchronized (SipService.this) { 952d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan if (notCurrentSession(session)) return; 9539c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 954fcc474636f42243cfce960158373b9c49636a556Hung-ying Tyan switch (errorCode) { 955fcc474636f42243cfce960158373b9c49636a556Hung-ying Tyan case SipErrorCode.INVALID_CREDENTIALS: 956fcc474636f42243cfce960158373b9c49636a556Hung-ying Tyan case SipErrorCode.SERVER_UNREACHABLE: 957fcc474636f42243cfce960158373b9c49636a556Hung-ying Tyan if (DEBUG) Log.d(TAG, " pause auto-registration"); 958fcc474636f42243cfce960158373b9c49636a556Hung-ying Tyan stop(); 9590b88a073712b1510db7c636f89c4e19f0131449aHung-ying Tyan break; 960fcc474636f42243cfce960158373b9c49636a556Hung-ying Tyan default: 961fcc474636f42243cfce960158373b9c49636a556Hung-ying Tyan restartLater(); 9629c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 963d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan 964d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan mErrorCode = errorCode; 965d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan mErrorMessage = message; 966d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan mProxy.onRegistrationFailed(session, errorCode, message); 967257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan mMyWakeLock.release(session); 9689c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 9699c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 9709c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 9719c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan @Override 9729c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public void onRegistrationTimeout(ISipSession session) { 9739c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (DEBUG) Log.d(TAG, "onRegistrationTimeout(): " + session); 9749c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan synchronized (SipService.this) { 975d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan if (notCurrentSession(session)) return; 976d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan 9779c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mErrorCode = SipErrorCode.TIME_OUT; 9789c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mProxy.onRegistrationTimeout(session); 979fcc474636f42243cfce960158373b9c49636a556Hung-ying Tyan restartLater(); 980257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan mMyWakeLock.release(session); 9819c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 9829c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 9839c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 984fcc474636f42243cfce960158373b9c49636a556Hung-ying Tyan private void restartLater() { 9859c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mRegistered = false; 9869c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan restart(backoffDuration()); 9879c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (mKeepAliveProcess != null) { 9889c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mKeepAliveProcess.stop(); 9899c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mKeepAliveProcess = null; 9909c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 9919c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 9929c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 9939c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 9949c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private class ConnectivityReceiver extends BroadcastReceiver { 9959c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private Timer mTimer = new Timer(); 9969c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private MyTimerTask mTask; 9979c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 9989c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan @Override 999257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan public void onReceive(final Context context, final Intent intent) { 1000257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan // Run the handler in MyExecutor to be protected by wake lock 1001257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan getExecutor().execute(new Runnable() { 1002257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan public void run() { 1003257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan onReceiveInternal(context, intent); 1004257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan } 1005257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan }); 1006257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan } 1007257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan 1008257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan private void onReceiveInternal(Context context, Intent intent) { 10099c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan String action = intent.getAction(); 10109c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) { 10119c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Bundle b = intent.getExtras(); 10129c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (b != null) { 10139c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan NetworkInfo netInfo = (NetworkInfo) 10149c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan b.get(ConnectivityManager.EXTRA_NETWORK_INFO); 10159c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan String type = netInfo.getTypeName(); 10169c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan NetworkInfo.State state = netInfo.getState(); 10179c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 10189c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (mWifiOnly && (netInfo.getType() != 10199c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan ConnectivityManager.TYPE_WIFI)) { 10209c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (DEBUG) { 10219c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Log.d(TAG, "Wifi only, other connectivity ignored: " 10229c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan + type); 10239c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 10249c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return; 10259c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 10269c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 10279c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan NetworkInfo activeNetInfo = getActiveNetworkInfo(); 10289c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (DEBUG) { 10299c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (activeNetInfo != null) { 10309c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Log.d(TAG, "active network: " 10319c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan + activeNetInfo.getTypeName() 10329c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan + ((activeNetInfo.getState() == NetworkInfo.State.CONNECTED) 10339c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan ? " CONNECTED" : " DISCONNECTED")); 10349c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else { 10359c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Log.d(TAG, "active network: null"); 10369c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 10379c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 10389c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if ((state == NetworkInfo.State.CONNECTED) 10399c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan && (activeNetInfo != null) 10409c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan && (activeNetInfo.getType() != netInfo.getType())) { 10419c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (DEBUG) Log.d(TAG, "ignore connect event: " + type 10429c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan + ", active: " + activeNetInfo.getTypeName()); 10439c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return; 10449c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 10459c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 10469c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (state == NetworkInfo.State.CONNECTED) { 10479c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (DEBUG) Log.d(TAG, "Connectivity alert: CONNECTED " + type); 10489c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan onChanged(type, true); 10499c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else if (state == NetworkInfo.State.DISCONNECTED) { 10509c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (DEBUG) Log.d(TAG, "Connectivity alert: DISCONNECTED " + type); 10519c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan onChanged(type, false); 10529c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else { 10539c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (DEBUG) Log.d(TAG, "Connectivity alert not processed: " 10549c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan + state + " " + type); 10559c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 10569c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 10579c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 10589c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 10599c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 10609c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private NetworkInfo getActiveNetworkInfo() { 10619c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan ConnectivityManager cm = (ConnectivityManager) 10629c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mContext.getSystemService(Context.CONNECTIVITY_SERVICE); 10639c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return cm.getActiveNetworkInfo(); 10649c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 10659c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 10669c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private void onChanged(String type, boolean connected) { 10679c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan synchronized (SipService.this) { 10689c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // When turning on WIFI, it needs some time for network 10699c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // connectivity to get stabile so we defer good news (because 10709c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // we want to skip the interim ones) but deliver bad news 10719c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // immediately 10729c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (connected) { 10739c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (mTask != null) mTask.cancel(); 10749c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mTask = new MyTimerTask(type, connected); 10759c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mTimer.schedule(mTask, 2 * 1000L); 1076257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan // hold wakup lock so that we can finish changes before the 1077257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan // device goes to sleep 1078257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan mMyWakeLock.acquire(mTask); 10799c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else { 10809c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if ((mTask != null) && mTask.mNetworkType.equals(type)) { 10819c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mTask.cancel(); 1082257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan mMyWakeLock.release(mTask); 10839c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 10849c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan onConnectivityChanged(type, false); 10859c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 10869c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 10879c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 10889c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 10899c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private class MyTimerTask extends TimerTask { 10909c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private boolean mConnected; 10919c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private String mNetworkType; 10929c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 10939c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public MyTimerTask(String type, boolean connected) { 10949c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mNetworkType = type; 10959c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mConnected = connected; 10969c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 10979c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 1098d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan // timeout handler 10999c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan @Override 11009c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public void run() { 11019c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // delegate to mExecutor 1102257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan getExecutor().execute(new Runnable() { 11039c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public void run() { 11049c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan realRun(); 11059c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 11069c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan }); 11079c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 11089c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 11099c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private void realRun() { 11109c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan synchronized (SipService.this) { 11119c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (mTask != this) { 11129c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Log.w(TAG, " unexpected task: " + mNetworkType 11139c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan + (mConnected ? " CONNECTED" : "DISCONNECTED")); 11149c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return; 11159c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 11169c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mTask = null; 11179c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (DEBUG) Log.d(TAG, " deliver change for " + mNetworkType 11189c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan + (mConnected ? " CONNECTED" : "DISCONNECTED")); 11199c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan onConnectivityChanged(mNetworkType, mConnected); 1120257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan mMyWakeLock.release(this); 11219c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 11229c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 11239c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 11249c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 11259c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 11269c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan /** 11279c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan * Timer that can schedule events to occur even when the device is in sleep. 11289c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan * Only used internally in this package. 11299c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan */ 11309c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan class WakeupTimer extends BroadcastReceiver { 11319c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private static final String TAG = "_SIP.WkTimer_"; 11329c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private static final String TRIGGER_TIME = "TriggerTime"; 11339c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 11349c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private Context mContext; 11359c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private AlarmManager mAlarmManager; 11369c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 11379c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // runnable --> time to execute in SystemClock 11389c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private TreeSet<MyEvent> mEventQueue = 11399c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan new TreeSet<MyEvent>(new MyEventComparator()); 11409c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 11419c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private PendingIntent mPendingIntent; 11429c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 11439c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public WakeupTimer(Context context) { 11449c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mContext = context; 11459c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mAlarmManager = (AlarmManager) 11469c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan context.getSystemService(Context.ALARM_SERVICE); 11479c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 11489c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan IntentFilter filter = new IntentFilter(getAction()); 11499c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan context.registerReceiver(this, filter); 11509c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 11519c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 11529c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan /** 11539c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan * Stops the timer. No event can be scheduled after this method is called. 11549c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan */ 11559c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public synchronized void stop() { 11569c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mContext.unregisterReceiver(this); 11579c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (mPendingIntent != null) { 11589c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mAlarmManager.cancel(mPendingIntent); 11599c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mPendingIntent = null; 11609c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 11619c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mEventQueue.clear(); 11629c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mEventQueue = null; 11639c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 11649c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 11659c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private synchronized boolean stopped() { 11669c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (mEventQueue == null) { 11679c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Log.w(TAG, "Timer stopped"); 11689c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return true; 11699c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else { 11709c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return false; 11719c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 11729c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 11739c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 11749c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private void cancelAlarm() { 11759c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mAlarmManager.cancel(mPendingIntent); 11769c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mPendingIntent = null; 11779c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 11789c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 11799c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private void recalculatePeriods() { 11809c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (mEventQueue.isEmpty()) return; 11819c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 11829c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan MyEvent firstEvent = mEventQueue.first(); 11839c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan int minPeriod = firstEvent.mMaxPeriod; 11849c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan long minTriggerTime = firstEvent.mTriggerTime; 11859c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan for (MyEvent e : mEventQueue) { 11869c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan e.mPeriod = e.mMaxPeriod / minPeriod * minPeriod; 11879c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan int interval = (int) (e.mLastTriggerTime + e.mMaxPeriod 11889c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan - minTriggerTime); 11899c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan interval = interval / minPeriod * minPeriod; 11909c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan e.mTriggerTime = minTriggerTime + interval; 11919c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 11929c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan TreeSet<MyEvent> newQueue = new TreeSet<MyEvent>( 11939c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mEventQueue.comparator()); 11949c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan newQueue.addAll((Collection<MyEvent>) mEventQueue); 11959c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mEventQueue.clear(); 11969c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mEventQueue = newQueue; 11979c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (DEBUG_TIMER) { 11989c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Log.d(TAG, "queue re-calculated"); 11999c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan printQueue(); 12009c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 12019c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 12029c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 12039c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // Determines the period and the trigger time of the new event and insert it 12049c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // to the queue. 12059c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private void insertEvent(MyEvent event) { 12069c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan long now = SystemClock.elapsedRealtime(); 12079c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (mEventQueue.isEmpty()) { 12089c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan event.mTriggerTime = now + event.mPeriod; 12099c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mEventQueue.add(event); 12109c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return; 12119c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 12129c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan MyEvent firstEvent = mEventQueue.first(); 12139c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan int minPeriod = firstEvent.mPeriod; 12149c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (minPeriod <= event.mMaxPeriod) { 12159c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan event.mPeriod = event.mMaxPeriod / minPeriod * minPeriod; 12169c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan int interval = event.mMaxPeriod; 12179c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan interval -= (int) (firstEvent.mTriggerTime - now); 12189c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan interval = interval / minPeriod * minPeriod; 12199c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan event.mTriggerTime = firstEvent.mTriggerTime + interval; 12209c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mEventQueue.add(event); 12219c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else { 12229c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan long triggerTime = now + event.mPeriod; 12239c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (firstEvent.mTriggerTime < triggerTime) { 12249c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan event.mTriggerTime = firstEvent.mTriggerTime; 12259c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan event.mLastTriggerTime -= event.mPeriod; 12269c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else { 12279c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan event.mTriggerTime = triggerTime; 12289c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 12299c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mEventQueue.add(event); 12309c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan recalculatePeriods(); 12319c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 12329c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 12339c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 12349c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan /** 12359c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan * Sets a periodic timer. 12369c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan * 12379c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan * @param period the timer period; in milli-second 12389c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan * @param callback is called back when the timer goes off; the same callback 12399c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan * can be specified in multiple timer events 12409c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan */ 12419c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public synchronized void set(int period, Runnable callback) { 12429c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (stopped()) return; 12439c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 12449c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan long now = SystemClock.elapsedRealtime(); 12459c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan MyEvent event = new MyEvent(period, callback, now); 12469c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan insertEvent(event); 12479c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 12489c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (mEventQueue.first() == event) { 12499c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (mEventQueue.size() > 1) cancelAlarm(); 12509c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan scheduleNext(); 12519c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 12529c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 12539c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan long triggerTime = event.mTriggerTime; 12549c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (DEBUG_TIMER) { 12559c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Log.d(TAG, " add event " + event + " scheduled at " 12569c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan + showTime(triggerTime) + " at " + showTime(now) 12579c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan + ", #events=" + mEventQueue.size()); 12589c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan printQueue(); 12599c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 12609c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 12619c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 12629c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan /** 12639c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan * Cancels all the timer events with the specified callback. 12649c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan * 12659c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan * @param callback the callback 12669c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan */ 12679c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public synchronized void cancel(Runnable callback) { 12689c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (stopped() || mEventQueue.isEmpty()) return; 12699c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (DEBUG_TIMER) Log.d(TAG, "cancel:" + callback); 12709c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 12719c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan MyEvent firstEvent = mEventQueue.first(); 12729c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan for (Iterator<MyEvent> iter = mEventQueue.iterator(); 12739c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan iter.hasNext();) { 12749c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan MyEvent event = iter.next(); 12759c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (event.mCallback == callback) { 12769c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan iter.remove(); 12779c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (DEBUG_TIMER) Log.d(TAG, " cancel found:" + event); 12789c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 12799c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 12809c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (mEventQueue.isEmpty()) { 12819c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan cancelAlarm(); 12829c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else if (mEventQueue.first() != firstEvent) { 12839c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan cancelAlarm(); 12849c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan firstEvent = mEventQueue.first(); 12859c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan firstEvent.mPeriod = firstEvent.mMaxPeriod; 12869c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan firstEvent.mTriggerTime = firstEvent.mLastTriggerTime 12879c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan + firstEvent.mPeriod; 12889c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan recalculatePeriods(); 12899c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan scheduleNext(); 12909c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 12919c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (DEBUG_TIMER) { 12929c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Log.d(TAG, "after cancel:"); 12939c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan printQueue(); 12949c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 12959c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 12969c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 12979c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private void scheduleNext() { 12989c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (stopped() || mEventQueue.isEmpty()) return; 12999c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 13009c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (mPendingIntent != null) { 13019c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan throw new RuntimeException("pendingIntent is not null!"); 13029c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 13039c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 13049c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan MyEvent event = mEventQueue.first(); 13059c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Intent intent = new Intent(getAction()); 13069c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan intent.putExtra(TRIGGER_TIME, event.mTriggerTime); 13079c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan PendingIntent pendingIntent = mPendingIntent = 13089c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan PendingIntent.getBroadcast(mContext, 0, intent, 13099c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan PendingIntent.FLAG_UPDATE_CURRENT); 13109c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, 13119c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan event.mTriggerTime, pendingIntent); 13129c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 13139c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 13149c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan @Override 1315257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan public void onReceive(Context context, Intent intent) { 1316257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan // This callback is already protected by AlarmManager's wake lock. 13179c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan String action = intent.getAction(); 13189c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (getAction().equals(action) 13199c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan && intent.getExtras().containsKey(TRIGGER_TIME)) { 13209c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mPendingIntent = null; 13219c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan long triggerTime = intent.getLongExtra(TRIGGER_TIME, -1L); 13229c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan execute(triggerTime); 13239c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else { 13249c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Log.d(TAG, "unrecognized intent: " + intent); 13259c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 13269c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 13279c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 13289c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private void printQueue() { 13299c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan int count = 0; 13309c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan for (MyEvent event : mEventQueue) { 13319c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Log.d(TAG, " " + event + ": scheduled at " 13329c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan + showTime(event.mTriggerTime) + ": last at " 13339c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan + showTime(event.mLastTriggerTime)); 13349c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (++count >= 5) break; 13359c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 13369c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (mEventQueue.size() > count) { 13379c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Log.d(TAG, " ....."); 13389c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else if (count == 0) { 13399c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Log.d(TAG, " <empty>"); 13409c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 13419c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 13429c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 1343257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan private synchronized void execute(long triggerTime) { 13449c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (DEBUG_TIMER) Log.d(TAG, "time's up, triggerTime = " 13459c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan + showTime(triggerTime) + ": " + mEventQueue.size()); 13469c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (stopped() || mEventQueue.isEmpty()) return; 13479c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 13489c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan for (MyEvent event : mEventQueue) { 13499c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (event.mTriggerTime != triggerTime) break; 13509c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (DEBUG_TIMER) Log.d(TAG, "execute " + event); 13519c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 13529c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan event.mLastTriggerTime = event.mTriggerTime; 13539c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan event.mTriggerTime += event.mPeriod; 13549c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 1355257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan // run the callback in the handler thread to prevent deadlock 1356257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan getExecutor().execute(event.mCallback); 13579c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 13589c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (DEBUG_TIMER) { 13599c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Log.d(TAG, "after timeout execution"); 13609c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan printQueue(); 13619c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 13629c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan scheduleNext(); 13639c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 13649c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 13659c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private String getAction() { 13669c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return toString(); 13679c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 13689c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 13699c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private String showTime(long time) { 13709c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan int ms = (int) (time % 1000); 13719c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan int s = (int) (time / 1000); 13729c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan int m = s / 60; 13739c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan s %= 60; 13749c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return String.format("%d.%d.%d", m, s, ms); 13759c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 13769c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 13779c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 13789c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private static class MyEvent { 13799c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan int mPeriod; 13809c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan int mMaxPeriod; 13819c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan long mTriggerTime; 13829c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan long mLastTriggerTime; 13839c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Runnable mCallback; 13849c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 13859c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan MyEvent(int period, Runnable callback, long now) { 13869c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mPeriod = mMaxPeriod = period; 13879c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mCallback = callback; 13889c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mLastTriggerTime = now; 13899c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 13909c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 13919c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan @Override 13929c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public String toString() { 13939c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan String s = super.toString(); 13949c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan s = s.substring(s.indexOf("@")); 13959c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return s + ":" + (mPeriod / 1000) + ":" + (mMaxPeriod / 1000) + ":" 13969c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan + toString(mCallback); 13979c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 13989c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 13999c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private String toString(Object o) { 14009c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan String s = o.toString(); 14019c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan int index = s.indexOf("$"); 14029c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (index > 0) s = s.substring(index + 1); 14039c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return s; 14049c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 14059c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 14069c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 14079c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private static class MyEventComparator implements Comparator<MyEvent> { 14089c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public int compare(MyEvent e1, MyEvent e2) { 14099c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (e1 == e2) return 0; 14109c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan int diff = e1.mMaxPeriod - e2.mMaxPeriod; 14119c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (diff == 0) diff = -1; 14129c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return diff; 14139c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 14149c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 14159c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public boolean equals(Object that) { 14169c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return (this == that); 14179c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 14189c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 14199c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 1420257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan private static Looper createLooper() { 1421257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan HandlerThread thread = new HandlerThread("SipService.Executor"); 1422257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan thread.start(); 1423257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan return thread.getLooper(); 1424257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan } 1425257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan 1426257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan // Executes immediate tasks in a single thread. 1427257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan // Hold/release wake lock for running tasks 1428257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan private class MyExecutor extends Handler { 14299c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan MyExecutor() { 14309c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan super(createLooper()); 14319c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 14329c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 1433257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan void execute(Runnable task) { 1434257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan mMyWakeLock.acquire(task); 14359c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Message.obtain(this, 0/* don't care */, task).sendToTarget(); 14369c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 14379c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 14389c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan @Override 14399c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public void handleMessage(Message msg) { 14409c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (msg.obj instanceof Runnable) { 1441257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan executeInternal((Runnable) msg.obj); 14429c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else { 14439c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Log.w(TAG, "can't handle msg: " + msg); 14449c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 14459c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 1446257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan 1447257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan private void executeInternal(Runnable task) { 1448257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan try { 1449257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan task.run(); 1450257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan } catch (Throwable t) { 1451257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan Log.e(TAG, "run task: " + task, t); 1452257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan } finally { 1453257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan mMyWakeLock.release(task); 1454257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan } 1455257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan } 1456257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan } 14579c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan} 1458