SipService.java revision a072a6e3aa75c9bd038406a5067156463b58551b
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; 42a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyanimport android.os.Process; 439c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.os.RemoteException; 449c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.os.ServiceManager; 459c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.os.SystemClock; 469c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.text.TextUtils; 479c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.util.Log; 489c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 499c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport java.io.IOException; 509c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport java.net.DatagramSocket; 519c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport java.net.InetAddress; 529c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport java.net.UnknownHostException; 53a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyanimport java.util.ArrayList; 549c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport java.util.Collection; 559c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport java.util.Comparator; 569c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport java.util.HashMap; 579c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport java.util.Iterator; 589c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport java.util.Map; 599c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport java.util.Timer; 609c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport java.util.TimerTask; 619c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport java.util.TreeSet; 629c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport javax.sip.SipException; 639c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 649c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan/** 659c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan * @hide 669c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan */ 679c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanpublic final class SipService extends ISipService.Stub { 689c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private static final String TAG = "SipService"; 699c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private static final boolean DEBUG = true; 709c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private static final boolean DEBUG_TIMER = DEBUG && false; 719c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private static final int EXPIRY_TIME = 3600; 729c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private static final int SHORT_EXPIRY_TIME = 10; 739c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private static final int MIN_EXPIRY_TIME = 60; 749c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 759c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private Context mContext; 769c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private String mLocalIp; 779c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private String mNetworkType; 789c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private boolean mConnected; 799c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private WakeupTimer mTimer; 809c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private WifiManager.WifiLock mWifiLock; 819c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private boolean mWifiOnly; 829c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 839c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private MyExecutor mExecutor; 849c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 859c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // SipProfile URI --> group 869c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private Map<String, SipSessionGroupExt> mSipGroups = 879c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan new HashMap<String, SipSessionGroupExt>(); 889c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 899c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // session ID --> session 909c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private Map<String, ISipSession> mPendingSessions = 919c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan new HashMap<String, ISipSession>(); 929c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 939c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private ConnectivityReceiver mConnectivityReceiver; 949c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 959c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan /** 969c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan * Starts the SIP service. Do nothing if the SIP API is not supported on the 979c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan * device. 989c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan */ 999c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public static void start(Context context) { 1009c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (SipManager.isApiSupported(context)) { 1019c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan ServiceManager.addService("sip", new SipService(context)); 1029c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Log.i(TAG, "SIP service started"); 1039c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 1049c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 1059c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 1069c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private SipService(Context context) { 1079c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (DEBUG) Log.d(TAG, " service started!"); 1089c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mContext = context; 1099c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mConnectivityReceiver = new ConnectivityReceiver(); 1109c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan context.registerReceiver(mConnectivityReceiver, 1119c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION)); 1129c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 1139c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mTimer = new WakeupTimer(context); 1149c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mWifiOnly = SipManager.isSipWifiOnly(context); 1159c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 1169c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 1179c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private MyExecutor getExecutor() { 1189c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // create mExecutor lazily 1199c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (mExecutor == null) mExecutor = new MyExecutor(); 1209c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return mExecutor; 1219c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 1229c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 1239c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public synchronized SipProfile[] getListOfProfiles() { 124a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan boolean isCallerRadio = isCallerRadio(); 125a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan ArrayList<SipProfile> profiles = new ArrayList<SipProfile>(); 1269c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan for (SipSessionGroupExt group : mSipGroups.values()) { 127a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan if (isCallerRadio || isCallerCreator(group)) { 128a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan profiles.add(group.getLocalProfile()); 129a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan } 1309c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 131a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan return profiles.toArray(new SipProfile[profiles.size()]); 1329c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 1339c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 1349c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public void open(SipProfile localProfile) { 1359c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan localProfile.setCallingUid(Binder.getCallingUid()); 136a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan if (localProfile.getAutoRegistration() && isCallerRadio()) { 1379c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan openToReceiveCalls(localProfile); 1389c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else { 1399c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan openToMakeCalls(localProfile); 1409c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 1419c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 1429c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 1439c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private void openToMakeCalls(SipProfile localProfile) { 1449c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan try { 1459c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan createGroup(localProfile); 1469c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } catch (SipException e) { 1479c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Log.e(TAG, "openToMakeCalls()", e); 1489c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // TODO: how to send the exception back 1499c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 1509c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 1519c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 1529c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private void openToReceiveCalls(SipProfile localProfile) { 1539c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan open3(localProfile, SipManager.ACTION_SIP_INCOMING_CALL, null); 1549c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 1559c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 1569c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public synchronized void open3(SipProfile localProfile, 1579c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan String incomingCallBroadcastAction, ISipSessionListener listener) { 1589c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan localProfile.setCallingUid(Binder.getCallingUid()); 1599c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (TextUtils.isEmpty(incomingCallBroadcastAction)) { 160a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan Log.w(TAG, "empty broadcast action for incoming call"); 161a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan return; 162a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan } 163a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan if (incomingCallBroadcastAction.equals( 164a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan SipManager.ACTION_SIP_INCOMING_CALL) && !isCallerRadio()) { 165a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan Log.w(TAG, "failed to open the profile; " 166a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan + "the action string is reserved"); 167a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan return; 1689c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 1699c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (DEBUG) Log.d(TAG, "open3: " + localProfile.getUriString() + ": " 1709c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan + incomingCallBroadcastAction + ": " + listener); 1719c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan try { 1729c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan SipSessionGroupExt group = createGroup(localProfile, 1739c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan incomingCallBroadcastAction, listener); 1749c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (localProfile.getAutoRegistration()) { 1759c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan group.openToReceiveCalls(); 1769c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (isWifiOn()) grabWifiLock(); 1779c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 1789c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } catch (SipException e) { 1799c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Log.e(TAG, "openToReceiveCalls()", e); 1809c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // TODO: how to send the exception back 1819c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 1829c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 1839c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 184a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan private boolean isCallerCreator(SipSessionGroupExt group) { 185a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan SipProfile profile = group.getLocalProfile(); 186a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan return (profile.getCallingUid() == Binder.getCallingUid()); 187a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan } 188a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan 189a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan private boolean isCallerCreatorOrRadio(SipSessionGroupExt group) { 190a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan return (isCallerRadio() || isCallerCreator(group)); 191a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan } 192a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan 193a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan private boolean isCallerRadio() { 194a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan return (Binder.getCallingUid() == Process.PHONE_UID); 195a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan } 196a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan 1979c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public synchronized void close(String localProfileUri) { 198a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan SipSessionGroupExt group = mSipGroups.get(localProfileUri); 199a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan if (group == null) return; 200a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan if (!isCallerCreatorOrRadio(group)) { 201a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan Log.d(TAG, "only creator or radio can close this profile"); 202a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan return; 2039c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 204a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan 205a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan group = mSipGroups.remove(localProfileUri); 206a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan notifyProfileRemoved(group.getLocalProfile()); 207a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan group.close(); 208a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan if (isWifiOn() && !anyOpened()) releaseWifiLock(); 2099c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 2109c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 2119c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public synchronized boolean isOpened(String localProfileUri) { 2129c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan SipSessionGroupExt group = mSipGroups.get(localProfileUri); 213a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan if (group == null) return false; 214a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan if (isCallerCreatorOrRadio(group)) { 215a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan return group.isOpened(); 216a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan } else { 217a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan Log.i(TAG, "only creator or radio can query on the profile"); 218a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan return false; 219a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan } 2209c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 2219c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 2229c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public synchronized boolean isRegistered(String localProfileUri) { 2239c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan SipSessionGroupExt group = mSipGroups.get(localProfileUri); 224a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan if (group == null) return false; 225a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan if (isCallerCreatorOrRadio(group)) { 226a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan return group.isRegistered(); 227a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan } else { 228a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan Log.i(TAG, "only creator or radio can query on the profile"); 229a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan return false; 230a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan } 2319c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 2329c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 2339c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public synchronized void setRegistrationListener(String localProfileUri, 2349c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan ISipSessionListener listener) { 2359c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan SipSessionGroupExt group = mSipGroups.get(localProfileUri); 236a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan if (group == null) return; 237a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan if (isCallerCreator(group)) { 238a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan group.setListener(listener); 239a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan } else { 240a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan Log.i(TAG, "only creator can set listener on the profile"); 241a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan } 2429c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 2439c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 2449c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public synchronized ISipSession createSession(SipProfile localProfile, 2459c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan ISipSessionListener listener) { 2469c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan localProfile.setCallingUid(Binder.getCallingUid()); 2479c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (!mConnected) return null; 2489c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan try { 2499c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan SipSessionGroupExt group = createGroup(localProfile); 2509c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return group.createSession(listener); 2519c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } catch (SipException e) { 2529c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Log.w(TAG, "createSession()", e); 2539c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return null; 2549c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 2559c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 2569c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 2579c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public synchronized ISipSession getPendingSession(String callId) { 2589c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (callId == null) return null; 2599c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return mPendingSessions.get(callId); 2609c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 2619c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 2629c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private String determineLocalIp() { 2639c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan try { 2649c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan DatagramSocket s = new DatagramSocket(); 2659c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan s.connect(InetAddress.getByName("192.168.1.1"), 80); 2669c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return s.getLocalAddress().getHostAddress(); 2679c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } catch (IOException e) { 2689c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Log.w(TAG, "determineLocalIp()", e); 2699c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // dont do anything; there should be a connectivity change going 2709c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return null; 2719c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 2729c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 2739c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 2749c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private SipSessionGroupExt createGroup(SipProfile localProfile) 2759c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan throws SipException { 2769c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan String key = localProfile.getUriString(); 2779c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan SipSessionGroupExt group = mSipGroups.get(key); 2789c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (group == null) { 2799c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan group = new SipSessionGroupExt(localProfile, null, null); 2809c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mSipGroups.put(key, group); 2819c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan notifyProfileAdded(localProfile); 282a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan } else if (!isCallerCreator(group)) { 283a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan throw new SipException("only creator can access the profile"); 2849c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 2859c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return group; 2869c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 2879c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 2889c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private SipSessionGroupExt createGroup(SipProfile localProfile, 2899c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan String incomingCallBroadcastAction, ISipSessionListener listener) 2909c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan throws SipException { 2919c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan String key = localProfile.getUriString(); 2929c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan SipSessionGroupExt group = mSipGroups.get(key); 2939c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (group != null) { 294a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan if (!isCallerCreator(group)) { 295a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan throw new SipException("only creator can access the profile"); 296a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan } 2979c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan group.setIncomingCallBroadcastAction( 2989c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan incomingCallBroadcastAction); 2999c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan group.setListener(listener); 3009c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else { 3019c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan group = new SipSessionGroupExt(localProfile, 3029c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan incomingCallBroadcastAction, listener); 3039c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mSipGroups.put(key, group); 3049c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan notifyProfileAdded(localProfile); 3059c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 3069c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return group; 3079c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 3089c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 3099c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private void notifyProfileAdded(SipProfile localProfile) { 3109c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (DEBUG) Log.d(TAG, "notify: profile added: " + localProfile); 3119c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Intent intent = new Intent(SipManager.ACTION_SIP_ADD_PHONE); 3129c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan intent.putExtra(SipManager.EXTRA_LOCAL_URI, localProfile.getUriString()); 3139c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mContext.sendBroadcast(intent); 3149c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 3159c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 3169c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private void notifyProfileRemoved(SipProfile localProfile) { 3179c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (DEBUG) Log.d(TAG, "notify: profile removed: " + localProfile); 3189c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Intent intent = new Intent(SipManager.ACTION_SIP_REMOVE_PHONE); 3199c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan intent.putExtra(SipManager.EXTRA_LOCAL_URI, localProfile.getUriString()); 3209c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mContext.sendBroadcast(intent); 3219c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 3229c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 3239c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private boolean anyOpened() { 3249c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan for (SipSessionGroupExt group : mSipGroups.values()) { 3259c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (group.isOpened()) return true; 3269c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 3279c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return false; 3289c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 3299c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 3309c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private void grabWifiLock() { 3319c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (mWifiLock == null) { 3329c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (DEBUG) Log.d(TAG, "acquire wifi lock"); 3339c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mWifiLock = ((WifiManager) 3349c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mContext.getSystemService(Context.WIFI_SERVICE)) 3359c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan .createWifiLock(WifiManager.WIFI_MODE_FULL, TAG); 3369c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mWifiLock.acquire(); 3379c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 3389c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 3399c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 3409c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private void releaseWifiLock() { 3419c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (mWifiLock != null) { 3429c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (DEBUG) Log.d(TAG, "release wifi lock"); 3439c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mWifiLock.release(); 3449c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mWifiLock = null; 3459c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 3469c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 3479c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 3489c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private boolean isWifiOn() { 3499c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return "WIFI".equalsIgnoreCase(mNetworkType); 3509c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan //return (mConnected && "WIFI".equalsIgnoreCase(mNetworkType)); 3519c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 3529c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 3539c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private synchronized void onConnectivityChanged( 3549c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan String type, boolean connected) { 3559c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (DEBUG) Log.d(TAG, "onConnectivityChanged(): " 3569c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan + mNetworkType + (mConnected? " CONNECTED" : " DISCONNECTED") 3579c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan + " --> " + type + (connected? " CONNECTED" : " DISCONNECTED")); 3589c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 3599c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan boolean sameType = type.equals(mNetworkType); 3609c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (!sameType && !connected) return; 3619c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 3629c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan boolean wasWifi = "WIFI".equalsIgnoreCase(mNetworkType); 3639c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan boolean isWifi = "WIFI".equalsIgnoreCase(type); 3649c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan boolean wifiOff = (isWifi && !connected) || (wasWifi && !sameType); 3659c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan boolean wifiOn = isWifi && connected; 3669c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (wifiOff) { 3679c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan releaseWifiLock(); 3689c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else if (wifiOn) { 3699c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (anyOpened()) grabWifiLock(); 3709c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 3719c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 3729c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan try { 3739c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan boolean wasConnected = mConnected; 3749c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mNetworkType = type; 3759c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mConnected = connected; 3769c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 3779c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (wasConnected) { 3789c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mLocalIp = null; 3799c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan for (SipSessionGroupExt group : mSipGroups.values()) { 3809c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan group.onConnectivityChanged(false); 3819c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 3829c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 3839c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 3849c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (connected) { 3859c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mLocalIp = determineLocalIp(); 3869c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan for (SipSessionGroupExt group : mSipGroups.values()) { 3879c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan group.onConnectivityChanged(true); 3889c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 3899c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 3909c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 3919c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } catch (SipException e) { 3929c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Log.e(TAG, "onConnectivityChanged()", e); 3939c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 3949c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 3959c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 3969c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private synchronized void addPendingSession(ISipSession session) { 3979c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan try { 3989c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mPendingSessions.put(session.getCallId(), session); 3999c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } catch (RemoteException e) { 4009c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // should not happen with a local call 4019c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Log.e(TAG, "addPendingSession()", e); 4029c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 4039c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 4049c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 4059c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private class SipSessionGroupExt extends SipSessionAdapter { 4069c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private SipSessionGroup mSipGroup; 4079c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private String mIncomingCallBroadcastAction; 4089c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private boolean mOpened; 4099c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 4109c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private AutoRegistrationProcess mAutoRegistration = 4119c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan new AutoRegistrationProcess(); 4129c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 4139c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public SipSessionGroupExt(SipProfile localProfile, 4149c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan String incomingCallBroadcastAction, 4159c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan ISipSessionListener listener) throws SipException { 4169c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan String password = localProfile.getPassword(); 4179c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan SipProfile p = duplicate(localProfile); 4189c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mSipGroup = createSipSessionGroup(mLocalIp, p, password); 4199c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mIncomingCallBroadcastAction = incomingCallBroadcastAction; 4209c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mAutoRegistration.setListener(listener); 4219c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 4229c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 4239c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public SipProfile getLocalProfile() { 4249c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return mSipGroup.getLocalProfile(); 4259c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 4269c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 4279c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // network connectivity is tricky because network can be disconnected 4289c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // at any instant so need to deal with exceptions carefully even when 4299c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // you think you are connected 4309c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private SipSessionGroup createSipSessionGroup(String localIp, 4319c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan SipProfile localProfile, String password) throws SipException { 4329c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan try { 4339c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return new SipSessionGroup(localIp, localProfile, password); 4349c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } catch (IOException e) { 4359c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // network disconnected 4369c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Log.w(TAG, "createSipSessionGroup(): network disconnected?"); 4379c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (localIp != null) { 4389c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return createSipSessionGroup(null, localProfile, password); 4399c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else { 4409c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // recursive 4419c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Log.wtf(TAG, "impossible!"); 4429c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan throw new RuntimeException("createSipSessionGroup"); 4439c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 4449c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 4459c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 4469c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 4479c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private SipProfile duplicate(SipProfile p) { 4489c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan try { 4499c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return new SipProfile.Builder(p).setPassword("*").build(); 4509c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } catch (Exception e) { 4519c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Log.wtf(TAG, "duplicate()", e); 4529c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan throw new RuntimeException("duplicate profile", e); 4539c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 4549c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 4559c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 4569c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public void setListener(ISipSessionListener listener) { 4579c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mAutoRegistration.setListener(listener); 4589c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 4599c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 4609c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public void setIncomingCallBroadcastAction(String action) { 4619c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mIncomingCallBroadcastAction = action; 4629c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 4639c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 4649c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public void openToReceiveCalls() throws SipException { 4659c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mOpened = true; 4669c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (mConnected) { 4679c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mSipGroup.openToReceiveCalls(this); 4689c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mAutoRegistration.start(mSipGroup); 4699c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 4709c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (DEBUG) Log.d(TAG, " openToReceiveCalls: " + getUri() + ": " 4719c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan + mIncomingCallBroadcastAction); 4729c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 4739c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 4749c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public void onConnectivityChanged(boolean connected) 4759c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan throws SipException { 4769c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mSipGroup.onConnectivityChanged(); 4779c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (connected) { 4789c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan resetGroup(mLocalIp); 4799c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (mOpened) openToReceiveCalls(); 4809c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else { 4819c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // close mSipGroup but remember mOpened 4829c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (DEBUG) Log.d(TAG, " close auto reg temporarily: " 4839c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan + getUri() + ": " + mIncomingCallBroadcastAction); 4849c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mSipGroup.close(); 4859c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mAutoRegistration.stop(); 4869c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 4879c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 4889c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 4899c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private void resetGroup(String localIp) throws SipException { 4909c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan try { 4919c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mSipGroup.reset(localIp); 4929c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } catch (IOException e) { 4939c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // network disconnected 4949c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Log.w(TAG, "resetGroup(): network disconnected?"); 4959c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (localIp != null) { 4969c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan resetGroup(null); // reset w/o local IP 4979c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else { 4989c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // recursive 4999c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Log.wtf(TAG, "impossible!"); 5009c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan throw new RuntimeException("resetGroup"); 5019c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 5029c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 5039c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 5049c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 5059c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public void close() { 5069c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mOpened = false; 5079c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mSipGroup.close(); 5089c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mAutoRegistration.stop(); 5099c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (DEBUG) Log.d(TAG, " close: " + getUri() + ": " 5109c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan + mIncomingCallBroadcastAction); 5119c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 5129c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 5139c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public ISipSession createSession(ISipSessionListener listener) { 5149c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return mSipGroup.createSession(listener); 5159c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 5169c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 5179c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan @Override 5189c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public void onRinging(ISipSession session, SipProfile caller, 5199c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan String sessionDescription) { 5209c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan synchronized (SipService.this) { 5219c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan try { 5229c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (!isRegistered()) { 5239c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan session.endCall(); 5249c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return; 5259c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 5269c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 5279c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // send out incoming call broadcast 5289c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan addPendingSession(session); 5299c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Intent intent = SipManager.createIncomingCallBroadcast( 5309c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan session.getCallId(), sessionDescription) 5319c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan .setAction(mIncomingCallBroadcastAction); 5329c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (DEBUG) Log.d(TAG, " ringing~~ " + getUri() + ": " 5339c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan + caller.getUri() + ": " + session.getCallId() 5349c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan + " " + mIncomingCallBroadcastAction); 5359c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mContext.sendBroadcast(intent); 5369c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } catch (RemoteException e) { 5379c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // should never happen with a local call 5389c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Log.e(TAG, "processCall()", e); 5399c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 5409c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 5419c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 5429c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 5439c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan @Override 5449c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public void onError(ISipSession session, int errorCode, 5459c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan String message) { 5469c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (DEBUG) Log.d(TAG, "sip session error: " 5479c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan + SipErrorCode.toString(errorCode) + ": " + message); 5489c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 5499c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 5509c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public boolean isOpened() { 5519c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return mOpened; 5529c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 5539c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 5549c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public boolean isRegistered() { 5559c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return mAutoRegistration.isRegistered(); 5569c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 5579c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 5589c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private String getUri() { 5599c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return mSipGroup.getLocalProfileUri(); 5609c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 5619c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 5629c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 563d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan // KeepAliveProcess is controlled by AutoRegistrationProcess. 564d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan // All methods will be invoked in sync with SipService.this except realRun() 5659c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private class KeepAliveProcess implements Runnable { 5669c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private static final String TAG = "\\KEEPALIVE/"; 5679c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private static final int INTERVAL = 10; 5689c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private SipSessionGroup.SipSessionImpl mSession; 569d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan private boolean mRunning = false; 5709c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 5719c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public KeepAliveProcess(SipSessionGroup.SipSessionImpl session) { 5729c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mSession = session; 5739c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 5749c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 5759c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public void start() { 576d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan if (mRunning) return; 577d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan mRunning = true; 5789c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mTimer.set(INTERVAL * 1000, this); 5799c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 5809c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 581d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan // timeout handler 5829c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public void run() { 583d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan if (!mRunning) return; 584d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan final SipSessionGroup.SipSessionImpl session = mSession; 585d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan 5869c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // delegate to mExecutor 5879c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan getExecutor().addTask(new Runnable() { 5889c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public void run() { 589d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan realRun(session); 5909c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 5919c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan }); 5929c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 5939c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 594d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan // real timeout handler 595d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan private void realRun(SipSessionGroup.SipSessionImpl session) { 5969c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan synchronized (SipService.this) { 597d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan if (notCurrentSession(session)) return; 598d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan 599d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan session = session.duplicate(); 6009c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (DEBUG) Log.d(TAG, "~~~ keepalive"); 6019c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mTimer.cancel(this); 6029c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan session.sendKeepAlive(); 6039c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (session.isReRegisterRequired()) { 6049c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mSession.register(EXPIRY_TIME); 6059c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else { 6069c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mTimer.set(INTERVAL * 1000, this); 6079c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 6089c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 6099c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 6109c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 6119c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public void stop() { 612d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan mRunning = false; 613d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan mSession = null; 6149c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mTimer.cancel(this); 6159c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 616d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan 617d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan private boolean notCurrentSession(ISipSession session) { 618d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan return (session != mSession) || !mRunning; 619d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan } 6209c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 6219c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 6229c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private class AutoRegistrationProcess extends SipSessionAdapter 6239c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan implements Runnable { 6249c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private SipSessionGroup.SipSessionImpl mSession; 6259c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private SipSessionListenerProxy mProxy = new SipSessionListenerProxy(); 6269c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private KeepAliveProcess mKeepAliveProcess; 6279c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private int mBackoff = 1; 6289c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private boolean mRegistered; 6299c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private long mExpiryTime; 6309c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private int mErrorCode; 6319c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private String mErrorMessage; 632d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan private boolean mRunning = false; 6339c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 6349c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private String getAction() { 6359c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return toString(); 6369c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 6379c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 6389c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public void start(SipSessionGroup group) { 639d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan if (!mRunning) { 640d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan mRunning = true; 6419c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mBackoff = 1; 6429c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mSession = (SipSessionGroup.SipSessionImpl) 6439c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan group.createSession(this); 6449c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // return right away if no active network connection. 6459c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (mSession == null) return; 6469c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 6479c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // start unregistration to clear up old registration at server 6489c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // TODO: when rfc5626 is deployed, use reg-id and sip.instance 6499c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // in registration to avoid adding duplicate entries to server 6509c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mSession.unregister(); 6519c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (DEBUG) Log.d(TAG, "start AutoRegistrationProcess for " 6529c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan + mSession.getLocalProfile().getUriString()); 6539c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 6549c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 6559c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 6569c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public void stop() { 657d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan if (!mRunning) return; 658d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan mRunning = false; 659d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan mSession.setListener(null); 6609c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (mConnected && mRegistered) mSession.unregister(); 661d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan 6629c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mTimer.cancel(this); 6639c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (mKeepAliveProcess != null) { 6649c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mKeepAliveProcess.stop(); 6659c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mKeepAliveProcess = null; 6669c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 6679c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 668d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan mRegistered = false; 669d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan setListener(mProxy.getListener()); 6709c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 6719c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 6729c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public void setListener(ISipSessionListener listener) { 6739c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan synchronized (SipService.this) { 6749c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mProxy.setListener(listener); 6759c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 6769c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan try { 6779c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan int state = (mSession == null) 6789c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan ? SipSession.State.READY_TO_CALL 6799c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan : mSession.getState(); 6809c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if ((state == SipSession.State.REGISTERING) 6819c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan || (state == SipSession.State.DEREGISTERING)) { 6829c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mProxy.onRegistering(mSession); 6839c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else if (mRegistered) { 6849c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan int duration = (int) 6859c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan (mExpiryTime - SystemClock.elapsedRealtime()); 6869c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mProxy.onRegistrationDone(mSession, duration); 6879c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else if (mErrorCode != SipErrorCode.NO_ERROR) { 6889c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (mErrorCode == SipErrorCode.TIME_OUT) { 6899c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mProxy.onRegistrationTimeout(mSession); 6909c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else { 6919c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mProxy.onRegistrationFailed(mSession, mErrorCode, 6929c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mErrorMessage); 6939c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 694d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan } else if (!mConnected) { 695d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan mProxy.onRegistrationFailed(mSession, 696d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan SipErrorCode.DATA_CONNECTION_LOST, 697d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan "no data connection"); 698d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan } else if (!mRunning) { 699d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan mProxy.onRegistrationFailed(mSession, 700d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan SipErrorCode.CLIENT_ERROR, 701d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan "registration not running"); 702d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan } else { 703d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan mProxy.onRegistrationFailed(mSession, 704d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan SipErrorCode.IN_PROGRESS, 705d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan String.valueOf(state)); 7069c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 7079c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } catch (Throwable t) { 7089c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Log.w(TAG, "setListener(): " + t); 7099c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 7109c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 7119c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 7129c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 7139c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public boolean isRegistered() { 7149c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return mRegistered; 7159c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 7169c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 717d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan // timeout handler 7189c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public void run() { 719d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan synchronized (SipService.this) { 720d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan if (!mRunning) return; 721d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan final SipSessionGroup.SipSessionImpl session = mSession; 722d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan 723d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan // delegate to mExecutor 724d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan getExecutor().addTask(new Runnable() { 725d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan public void run() { 726d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan realRun(session); 727d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan } 728d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan }); 729d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan } 7309c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 7319c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 732d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan // real timeout handler 733d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan private void realRun(SipSessionGroup.SipSessionImpl session) { 7349c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan synchronized (SipService.this) { 735d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan if (notCurrentSession(session)) return; 736d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan mErrorCode = SipErrorCode.NO_ERROR; 737d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan mErrorMessage = null; 738d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan if (DEBUG) Log.d(TAG, "~~~ registering"); 739d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan if (mConnected) session.register(EXPIRY_TIME); 7409c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 7419c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 7429c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 7439c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private boolean isBehindNAT(String address) { 7449c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan try { 7459c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan byte[] d = InetAddress.getByName(address).getAddress(); 7469c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if ((d[0] == 10) || 7479c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan (((0x000000FF & ((int)d[0])) == 172) && 7489c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan ((0x000000F0 & ((int)d[1])) == 16)) || 7499c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan (((0x000000FF & ((int)d[0])) == 192) && 7509c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan ((0x000000FF & ((int)d[1])) == 168))) { 7519c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return true; 7529c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 7539c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } catch (UnknownHostException e) { 7549c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Log.e(TAG, "isBehindAT()" + address, e); 7559c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 7569c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return false; 7579c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 7589c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 7599c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private void restart(int duration) { 7609c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (DEBUG) Log.d(TAG, "Refresh registration " + duration + "s later."); 7619c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mTimer.cancel(this); 7629c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mTimer.set(duration * 1000, this); 7639c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 7649c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 7659c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private int backoffDuration() { 7669c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan int duration = SHORT_EXPIRY_TIME * mBackoff; 7679c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (duration > 3600) { 7689c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan duration = 3600; 7699c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else { 7709c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mBackoff *= 2; 7719c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 7729c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return duration; 7739c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 7749c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 7759c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan @Override 7769c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public void onRegistering(ISipSession session) { 7779c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (DEBUG) Log.d(TAG, "onRegistering(): " + session); 7789c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan synchronized (SipService.this) { 779d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan if (notCurrentSession(session)) return; 780d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan 7819c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mRegistered = false; 7829c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mProxy.onRegistering(session); 7839c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 7849c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 7859c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 786d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan private boolean notCurrentSession(ISipSession session) { 787d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan if (session != mSession) { 788d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan ((SipSessionGroup.SipSessionImpl) session).setListener(null); 789d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan return true; 790d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan } 791d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan return !mRunning; 792d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan } 793d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan 7949c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan @Override 7959c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public void onRegistrationDone(ISipSession session, int duration) { 7969c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (DEBUG) Log.d(TAG, "onRegistrationDone(): " + session); 7979c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan synchronized (SipService.this) { 798d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan if (notCurrentSession(session)) return; 7999c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 8009c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mProxy.onRegistrationDone(session, duration); 8019c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 8029c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (duration > 0) { 8039c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mSession.clearReRegisterRequired(); 8049c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mExpiryTime = SystemClock.elapsedRealtime() 8059c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan + (duration * 1000); 8069c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 8079c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (!mRegistered) { 8089c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mRegistered = true; 8099c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // allow some overlap to avoid call drop during renew 8109c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan duration -= MIN_EXPIRY_TIME; 8119c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (duration < MIN_EXPIRY_TIME) { 8129c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan duration = MIN_EXPIRY_TIME; 8139c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 8149c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan restart(duration); 8159c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 8169c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (isBehindNAT(mLocalIp) || 8179c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mSession.getLocalProfile().getSendKeepAlive()) { 8189c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (mKeepAliveProcess == null) { 8199c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mKeepAliveProcess = 8209c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan new KeepAliveProcess(mSession); 8219c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 8229c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mKeepAliveProcess.start(); 8239c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 8249c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 8259c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else { 8269c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mRegistered = false; 8279c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mExpiryTime = -1L; 8289c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (DEBUG) Log.d(TAG, "Refresh registration immediately"); 8299c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan run(); 8309c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 8319c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 8329c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 8339c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 8349c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan @Override 8359c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public void onRegistrationFailed(ISipSession session, int errorCode, 8369c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan String message) { 8379c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (DEBUG) Log.d(TAG, "onRegistrationFailed(): " + session + ": " 8389c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan + SipErrorCode.toString(errorCode) + ": " + message); 8399c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan synchronized (SipService.this) { 840d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan if (notCurrentSession(session)) return; 8419c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 8429c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (errorCode == SipErrorCode.INVALID_CREDENTIALS) { 8439c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (DEBUG) Log.d(TAG, " pause auto-registration"); 844d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan stop(); 845d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan } else { 8469c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan onError(); 8479c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 848d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan 849d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan mErrorCode = errorCode; 850d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan mErrorMessage = message; 851d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan mProxy.onRegistrationFailed(session, errorCode, message); 8529c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 8539c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 8549c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 8559c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan @Override 8569c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public void onRegistrationTimeout(ISipSession session) { 8579c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (DEBUG) Log.d(TAG, "onRegistrationTimeout(): " + session); 8589c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan synchronized (SipService.this) { 859d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan if (notCurrentSession(session)) return; 860d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan 8619c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mErrorCode = SipErrorCode.TIME_OUT; 8629c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mProxy.onRegistrationTimeout(session); 863d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan onError(); 8649c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 8659c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 8669c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 8679c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private void onError() { 8689c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mRegistered = false; 8699c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan restart(backoffDuration()); 8709c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (mKeepAliveProcess != null) { 8719c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mKeepAliveProcess.stop(); 8729c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mKeepAliveProcess = null; 8739c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 8749c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 8759c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 8769c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 8779c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private class ConnectivityReceiver extends BroadcastReceiver { 8789c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private Timer mTimer = new Timer(); 8799c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private MyTimerTask mTask; 8809c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 8819c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan @Override 8829c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public void onReceive(Context context, Intent intent) { 8839c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan String action = intent.getAction(); 8849c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) { 8859c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Bundle b = intent.getExtras(); 8869c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (b != null) { 8879c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan NetworkInfo netInfo = (NetworkInfo) 8889c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan b.get(ConnectivityManager.EXTRA_NETWORK_INFO); 8899c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan String type = netInfo.getTypeName(); 8909c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan NetworkInfo.State state = netInfo.getState(); 8919c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 8929c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (mWifiOnly && (netInfo.getType() != 8939c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan ConnectivityManager.TYPE_WIFI)) { 8949c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (DEBUG) { 8959c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Log.d(TAG, "Wifi only, other connectivity ignored: " 8969c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan + type); 8979c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 8989c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return; 8999c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 9009c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 9019c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan NetworkInfo activeNetInfo = getActiveNetworkInfo(); 9029c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (DEBUG) { 9039c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (activeNetInfo != null) { 9049c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Log.d(TAG, "active network: " 9059c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan + activeNetInfo.getTypeName() 9069c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan + ((activeNetInfo.getState() == NetworkInfo.State.CONNECTED) 9079c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan ? " CONNECTED" : " DISCONNECTED")); 9089c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else { 9099c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Log.d(TAG, "active network: null"); 9109c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 9119c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 9129c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if ((state == NetworkInfo.State.CONNECTED) 9139c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan && (activeNetInfo != null) 9149c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan && (activeNetInfo.getType() != netInfo.getType())) { 9159c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (DEBUG) Log.d(TAG, "ignore connect event: " + type 9169c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan + ", active: " + activeNetInfo.getTypeName()); 9179c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return; 9189c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 9199c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 9209c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (state == NetworkInfo.State.CONNECTED) { 9219c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (DEBUG) Log.d(TAG, "Connectivity alert: CONNECTED " + type); 9229c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan onChanged(type, true); 9239c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else if (state == NetworkInfo.State.DISCONNECTED) { 9249c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (DEBUG) Log.d(TAG, "Connectivity alert: DISCONNECTED " + type); 9259c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan onChanged(type, false); 9269c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else { 9279c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (DEBUG) Log.d(TAG, "Connectivity alert not processed: " 9289c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan + state + " " + type); 9299c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 9309c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 9319c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 9329c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 9339c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 9349c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private NetworkInfo getActiveNetworkInfo() { 9359c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan ConnectivityManager cm = (ConnectivityManager) 9369c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mContext.getSystemService(Context.CONNECTIVITY_SERVICE); 9379c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return cm.getActiveNetworkInfo(); 9389c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 9399c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 9409c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private void onChanged(String type, boolean connected) { 9419c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan synchronized (SipService.this) { 9429c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // When turning on WIFI, it needs some time for network 9439c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // connectivity to get stabile so we defer good news (because 9449c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // we want to skip the interim ones) but deliver bad news 9459c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // immediately 9469c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (connected) { 9479c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (mTask != null) mTask.cancel(); 9489c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mTask = new MyTimerTask(type, connected); 9499c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mTimer.schedule(mTask, 2 * 1000L); 9509c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // TODO: hold wakup lock so that we can finish change before 9519c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // the device goes to sleep 9529c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else { 9539c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if ((mTask != null) && mTask.mNetworkType.equals(type)) { 9549c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mTask.cancel(); 9559c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 9569c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan onConnectivityChanged(type, false); 9579c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 9589c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 9599c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 9609c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 9619c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private class MyTimerTask extends TimerTask { 9629c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private boolean mConnected; 9639c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private String mNetworkType; 9649c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 9659c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public MyTimerTask(String type, boolean connected) { 9669c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mNetworkType = type; 9679c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mConnected = connected; 9689c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 9699c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 970d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan // timeout handler 9719c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan @Override 9729c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public void run() { 9739c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // delegate to mExecutor 9749c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan getExecutor().addTask(new Runnable() { 9759c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public void run() { 9769c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan realRun(); 9779c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 9789c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan }); 9799c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 9809c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 9819c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private void realRun() { 9829c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan synchronized (SipService.this) { 9839c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (mTask != this) { 9849c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Log.w(TAG, " unexpected task: " + mNetworkType 9859c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan + (mConnected ? " CONNECTED" : "DISCONNECTED")); 9869c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return; 9879c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 9889c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mTask = null; 9899c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (DEBUG) Log.d(TAG, " deliver change for " + mNetworkType 9909c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan + (mConnected ? " CONNECTED" : "DISCONNECTED")); 9919c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan onConnectivityChanged(mNetworkType, mConnected); 9929c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 9939c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 9949c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 9959c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 9969c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 9979c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // TODO: clean up pending SipSession(s) periodically 9989c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 9999c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 10009c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan /** 10019c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan * Timer that can schedule events to occur even when the device is in sleep. 10029c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan * Only used internally in this package. 10039c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan */ 10049c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan class WakeupTimer extends BroadcastReceiver { 10059c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private static final String TAG = "_SIP.WkTimer_"; 10069c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private static final String TRIGGER_TIME = "TriggerTime"; 10079c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 10089c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private Context mContext; 10099c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private AlarmManager mAlarmManager; 10109c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 10119c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // runnable --> time to execute in SystemClock 10129c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private TreeSet<MyEvent> mEventQueue = 10139c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan new TreeSet<MyEvent>(new MyEventComparator()); 10149c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 10159c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private PendingIntent mPendingIntent; 10169c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 10179c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public WakeupTimer(Context context) { 10189c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mContext = context; 10199c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mAlarmManager = (AlarmManager) 10209c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan context.getSystemService(Context.ALARM_SERVICE); 10219c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 10229c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan IntentFilter filter = new IntentFilter(getAction()); 10239c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan context.registerReceiver(this, filter); 10249c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 10259c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 10269c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan /** 10279c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan * Stops the timer. No event can be scheduled after this method is called. 10289c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan */ 10299c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public synchronized void stop() { 10309c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mContext.unregisterReceiver(this); 10319c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (mPendingIntent != null) { 10329c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mAlarmManager.cancel(mPendingIntent); 10339c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mPendingIntent = null; 10349c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 10359c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mEventQueue.clear(); 10369c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mEventQueue = null; 10379c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 10389c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 10399c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private synchronized boolean stopped() { 10409c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (mEventQueue == null) { 10419c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Log.w(TAG, "Timer stopped"); 10429c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return true; 10439c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else { 10449c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return false; 10459c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 10469c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 10479c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 10489c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private void cancelAlarm() { 10499c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mAlarmManager.cancel(mPendingIntent); 10509c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mPendingIntent = null; 10519c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 10529c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 10539c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private void recalculatePeriods() { 10549c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (mEventQueue.isEmpty()) return; 10559c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 10569c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan MyEvent firstEvent = mEventQueue.first(); 10579c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan int minPeriod = firstEvent.mMaxPeriod; 10589c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan long minTriggerTime = firstEvent.mTriggerTime; 10599c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan for (MyEvent e : mEventQueue) { 10609c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan e.mPeriod = e.mMaxPeriod / minPeriod * minPeriod; 10619c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan int interval = (int) (e.mLastTriggerTime + e.mMaxPeriod 10629c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan - minTriggerTime); 10639c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan interval = interval / minPeriod * minPeriod; 10649c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan e.mTriggerTime = minTriggerTime + interval; 10659c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 10669c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan TreeSet<MyEvent> newQueue = new TreeSet<MyEvent>( 10679c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mEventQueue.comparator()); 10689c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan newQueue.addAll((Collection<MyEvent>) mEventQueue); 10699c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mEventQueue.clear(); 10709c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mEventQueue = newQueue; 10719c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (DEBUG_TIMER) { 10729c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Log.d(TAG, "queue re-calculated"); 10739c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan printQueue(); 10749c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 10759c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 10769c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 10779c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // Determines the period and the trigger time of the new event and insert it 10789c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // to the queue. 10799c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private void insertEvent(MyEvent event) { 10809c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan long now = SystemClock.elapsedRealtime(); 10819c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (mEventQueue.isEmpty()) { 10829c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan event.mTriggerTime = now + event.mPeriod; 10839c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mEventQueue.add(event); 10849c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return; 10859c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 10869c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan MyEvent firstEvent = mEventQueue.first(); 10879c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan int minPeriod = firstEvent.mPeriod; 10889c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (minPeriod <= event.mMaxPeriod) { 10899c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan event.mPeriod = event.mMaxPeriod / minPeriod * minPeriod; 10909c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan int interval = event.mMaxPeriod; 10919c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan interval -= (int) (firstEvent.mTriggerTime - now); 10929c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan interval = interval / minPeriod * minPeriod; 10939c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan event.mTriggerTime = firstEvent.mTriggerTime + interval; 10949c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mEventQueue.add(event); 10959c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else { 10969c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan long triggerTime = now + event.mPeriod; 10979c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (firstEvent.mTriggerTime < triggerTime) { 10989c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan event.mTriggerTime = firstEvent.mTriggerTime; 10999c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan event.mLastTriggerTime -= event.mPeriod; 11009c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else { 11019c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan event.mTriggerTime = triggerTime; 11029c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 11039c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mEventQueue.add(event); 11049c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan recalculatePeriods(); 11059c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 11069c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 11079c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 11089c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan /** 11099c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan * Sets a periodic timer. 11109c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan * 11119c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan * @param period the timer period; in milli-second 11129c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan * @param callback is called back when the timer goes off; the same callback 11139c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan * can be specified in multiple timer events 11149c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan */ 11159c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public synchronized void set(int period, Runnable callback) { 11169c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (stopped()) return; 11179c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 11189c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan long now = SystemClock.elapsedRealtime(); 11199c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan MyEvent event = new MyEvent(period, callback, now); 11209c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan insertEvent(event); 11219c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 11229c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (mEventQueue.first() == event) { 11239c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (mEventQueue.size() > 1) cancelAlarm(); 11249c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan scheduleNext(); 11259c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 11269c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 11279c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan long triggerTime = event.mTriggerTime; 11289c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (DEBUG_TIMER) { 11299c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Log.d(TAG, " add event " + event + " scheduled at " 11309c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan + showTime(triggerTime) + " at " + showTime(now) 11319c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan + ", #events=" + mEventQueue.size()); 11329c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan printQueue(); 11339c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 11349c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 11359c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 11369c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan /** 11379c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan * Cancels all the timer events with the specified callback. 11389c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan * 11399c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan * @param callback the callback 11409c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan */ 11419c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public synchronized void cancel(Runnable callback) { 11429c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (stopped() || mEventQueue.isEmpty()) return; 11439c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (DEBUG_TIMER) Log.d(TAG, "cancel:" + callback); 11449c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 11459c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan MyEvent firstEvent = mEventQueue.first(); 11469c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan for (Iterator<MyEvent> iter = mEventQueue.iterator(); 11479c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan iter.hasNext();) { 11489c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan MyEvent event = iter.next(); 11499c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (event.mCallback == callback) { 11509c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan iter.remove(); 11519c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (DEBUG_TIMER) Log.d(TAG, " cancel found:" + event); 11529c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 11539c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 11549c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (mEventQueue.isEmpty()) { 11559c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan cancelAlarm(); 11569c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else if (mEventQueue.first() != firstEvent) { 11579c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan cancelAlarm(); 11589c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan firstEvent = mEventQueue.first(); 11599c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan firstEvent.mPeriod = firstEvent.mMaxPeriod; 11609c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan firstEvent.mTriggerTime = firstEvent.mLastTriggerTime 11619c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan + firstEvent.mPeriod; 11629c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan recalculatePeriods(); 11639c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan scheduleNext(); 11649c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 11659c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (DEBUG_TIMER) { 11669c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Log.d(TAG, "after cancel:"); 11679c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan printQueue(); 11689c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 11699c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 11709c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 11719c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private void scheduleNext() { 11729c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (stopped() || mEventQueue.isEmpty()) return; 11739c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 11749c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (mPendingIntent != null) { 11759c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan throw new RuntimeException("pendingIntent is not null!"); 11769c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 11779c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 11789c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan MyEvent event = mEventQueue.first(); 11799c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Intent intent = new Intent(getAction()); 11809c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan intent.putExtra(TRIGGER_TIME, event.mTriggerTime); 11819c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan PendingIntent pendingIntent = mPendingIntent = 11829c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan PendingIntent.getBroadcast(mContext, 0, intent, 11839c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan PendingIntent.FLAG_UPDATE_CURRENT); 11849c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, 11859c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan event.mTriggerTime, pendingIntent); 11869c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 11879c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 11889c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan @Override 11899c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public synchronized void onReceive(Context context, Intent intent) { 11909c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan String action = intent.getAction(); 11919c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (getAction().equals(action) 11929c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan && intent.getExtras().containsKey(TRIGGER_TIME)) { 11939c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mPendingIntent = null; 11949c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan long triggerTime = intent.getLongExtra(TRIGGER_TIME, -1L); 11959c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan execute(triggerTime); 11969c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else { 11979c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Log.d(TAG, "unrecognized intent: " + intent); 11989c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 11999c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 12009c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 12019c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private void printQueue() { 12029c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan int count = 0; 12039c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan for (MyEvent event : mEventQueue) { 12049c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Log.d(TAG, " " + event + ": scheduled at " 12059c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan + showTime(event.mTriggerTime) + ": last at " 12069c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan + showTime(event.mLastTriggerTime)); 12079c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (++count >= 5) break; 12089c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 12099c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (mEventQueue.size() > count) { 12109c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Log.d(TAG, " ....."); 12119c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else if (count == 0) { 12129c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Log.d(TAG, " <empty>"); 12139c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 12149c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 12159c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 12169c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private void execute(long triggerTime) { 12179c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (DEBUG_TIMER) Log.d(TAG, "time's up, triggerTime = " 12189c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan + showTime(triggerTime) + ": " + mEventQueue.size()); 12199c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (stopped() || mEventQueue.isEmpty()) return; 12209c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 12219c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan for (MyEvent event : mEventQueue) { 12229c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (event.mTriggerTime != triggerTime) break; 12239c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (DEBUG_TIMER) Log.d(TAG, "execute " + event); 12249c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 12259c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan event.mLastTriggerTime = event.mTriggerTime; 12269c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan event.mTriggerTime += event.mPeriod; 12279c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 12289c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // run the callback in a new thread to prevent deadlock 12299c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan new Thread(event.mCallback, "SipServiceTimerCallbackThread") 12309c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan .start(); 12319c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 12329c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (DEBUG_TIMER) { 12339c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Log.d(TAG, "after timeout execution"); 12349c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan printQueue(); 12359c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 12369c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan scheduleNext(); 12379c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 12389c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 12399c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private String getAction() { 12409c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return toString(); 12419c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 12429c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 12439c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private String showTime(long time) { 12449c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan int ms = (int) (time % 1000); 12459c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan int s = (int) (time / 1000); 12469c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan int m = s / 60; 12479c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan s %= 60; 12489c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return String.format("%d.%d.%d", m, s, ms); 12499c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 12509c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 12519c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 12529c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private static class MyEvent { 12539c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan int mPeriod; 12549c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan int mMaxPeriod; 12559c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan long mTriggerTime; 12569c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan long mLastTriggerTime; 12579c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Runnable mCallback; 12589c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 12599c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan MyEvent(int period, Runnable callback, long now) { 12609c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mPeriod = mMaxPeriod = period; 12619c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mCallback = callback; 12629c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mLastTriggerTime = now; 12639c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 12649c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 12659c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan @Override 12669c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public String toString() { 12679c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan String s = super.toString(); 12689c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan s = s.substring(s.indexOf("@")); 12699c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return s + ":" + (mPeriod / 1000) + ":" + (mMaxPeriod / 1000) + ":" 12709c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan + toString(mCallback); 12719c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 12729c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 12739c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private String toString(Object o) { 12749c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan String s = o.toString(); 12759c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan int index = s.indexOf("$"); 12769c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (index > 0) s = s.substring(index + 1); 12779c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return s; 12789c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 12799c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 12809c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 12819c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private static class MyEventComparator implements Comparator<MyEvent> { 12829c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public int compare(MyEvent e1, MyEvent e2) { 12839c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (e1 == e2) return 0; 12849c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan int diff = e1.mMaxPeriod - e2.mMaxPeriod; 12859c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (diff == 0) diff = -1; 12869c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return diff; 12879c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 12889c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 12899c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public boolean equals(Object that) { 12909c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return (this == that); 12919c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 12929c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 12939c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 12949c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // Single-threaded executor 12959c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private static class MyExecutor extends Handler { 12969c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan MyExecutor() { 12979c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan super(createLooper()); 12989c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 12999c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 13009c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private static Looper createLooper() { 13019c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan HandlerThread thread = new HandlerThread("SipService"); 13029c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan thread.start(); 13039c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return thread.getLooper(); 13049c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 13059c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 13069c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan void addTask(Runnable task) { 13079c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Message.obtain(this, 0/* don't care */, task).sendToTarget(); 13089c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 13099c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 13109c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan @Override 13119c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public void handleMessage(Message msg) { 13129c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (msg.obj instanceof Runnable) { 13139c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan ((Runnable) msg.obj).run(); 13149c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else { 13159c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Log.w(TAG, "can't handle msg: " + msg); 13169c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 13179c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 13189c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 13199c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan} 1320