SipService.java revision 7d803d942453ed2139bb590aba4c4fe025529a8f
19c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan/*
29c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan * Copyright (C) 2010, The Android Open Source Project
39c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan *
49c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan * Licensed under the Apache License, Version 2.0 (the "License");
59c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan * you may not use this file except in compliance with the License.
69c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan * You may obtain a copy of the License at
79c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan *
89c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan *     http://www.apache.org/licenses/LICENSE-2.0
99c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan *
109c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan * Unless required by applicable law or agreed to in writing, software
119c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan * distributed under the License is distributed on an "AS IS" BASIS,
129c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan * See the License for the specific language governing permissions and
149c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan * limitations under the License.
159c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan */
169c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
179c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanpackage com.android.server.sip;
189c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
199c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.app.AlarmManager;
209c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.app.PendingIntent;
219c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.content.BroadcastReceiver;
229c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.content.Context;
239c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.content.Intent;
249c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.content.IntentFilter;
259c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.net.ConnectivityManager;
269c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.net.NetworkInfo;
279c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.net.sip.ISipService;
289c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.net.sip.ISipSession;
299c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.net.sip.ISipSessionListener;
309c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.net.sip.SipErrorCode;
319c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.net.sip.SipManager;
329c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.net.sip.SipProfile;
339c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.net.sip.SipSession;
349c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.net.sip.SipSessionAdapter;
359c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.net.wifi.WifiManager;
369c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.os.Binder;
379c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.os.Bundle;
389c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.os.Handler;
399c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.os.HandlerThread;
409c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.os.Looper;
419c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.os.Message;
42257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyanimport android.os.PowerManager;
43a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyanimport android.os.Process;
449c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.os.RemoteException;
459c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.os.ServiceManager;
469c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.os.SystemClock;
479c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.text.TextUtils;
489c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.util.Log;
499c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
509c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport java.io.IOException;
519c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport java.net.DatagramSocket;
529c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport java.net.InetAddress;
539c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport java.net.UnknownHostException;
54a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyanimport java.util.ArrayList;
559c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport java.util.Collection;
569c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport java.util.Comparator;
579c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport java.util.HashMap;
589c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport java.util.Iterator;
599c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport java.util.Map;
609c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport java.util.Timer;
619c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport java.util.TimerTask;
629c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport java.util.TreeSet;
634cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyanimport java.util.concurrent.Executor;
649c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport javax.sip.SipException;
659c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
669c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan/**
679c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan * @hide
689c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan */
699c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanpublic final class SipService extends ISipService.Stub {
70acedadc1967457ac2f8981c67f884fd8c0ee853cHung-ying Tyan    static final String TAG = "SipService";
7185caf063c027ba0d1defeaff8850e12b6428c4f7Chia-chi Yeh    static final boolean DEBUG = false;
729c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    private static final int EXPIRY_TIME = 3600;
739c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    private static final int SHORT_EXPIRY_TIME = 10;
749c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    private static final int MIN_EXPIRY_TIME = 60;
758a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan    private static final int DEFAULT_KEEPALIVE_INTERVAL = 10; // in seconds
76cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan    private static final int DEFAULT_MAX_KEEPALIVE_INTERVAL = 120; // in seconds
779c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
789c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    private Context mContext;
799c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    private String mLocalIp;
807d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh    private int mNetworkType = -1;
814cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan    private SipWakeupTimer mTimer;
829c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    private WifiManager.WifiLock mWifiLock;
8379d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh    private boolean mSipOnWifiOnly;
84987b505b1c190ff0e5a05d2cc20c9b08d2b99b18Hung-ying Tyan
85469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang    private IntervalMeasurementProcess mIntervalMeasurementProcess;
869c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
874cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan    private MyExecutor mExecutor = new MyExecutor();
889c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
899c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    // SipProfile URI --> group
909c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    private Map<String, SipSessionGroupExt> mSipGroups =
919c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            new HashMap<String, SipSessionGroupExt>();
929c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
939c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    // session ID --> session
949c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    private Map<String, ISipSession> mPendingSessions =
959c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            new HashMap<String, ISipSession>();
969c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
979c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    private ConnectivityReceiver mConnectivityReceiver;
98acedadc1967457ac2f8981c67f884fd8c0ee853cHung-ying Tyan    private SipWakeLock mMyWakeLock;
99469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang    private int mKeepAliveInterval;
100cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan    private int mLastGoodKeepAliveInterval = DEFAULT_KEEPALIVE_INTERVAL;
1019c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
1029c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    /**
1039c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan     * Starts the SIP service. Do nothing if the SIP API is not supported on the
1049c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan     * device.
1059c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan     */
1069c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    public static void start(Context context) {
1079c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        if (SipManager.isApiSupported(context)) {
1089c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            ServiceManager.addService("sip", new SipService(context));
10922523a59d879cf47f1e9c202d001d569fad4f69eHung-ying Tyan            context.sendBroadcast(new Intent(SipManager.ACTION_SIP_SERVICE_UP));
110dc7545495e1ef8bad32cd78775f4dc072015eea0Hung-ying Tyan            if (DEBUG) Log.d(TAG, "SIP service started");
1119c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
1129c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    }
1139c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
1149c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    private SipService(Context context) {
1159c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        if (DEBUG) Log.d(TAG, " service started!");
1169c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        mContext = context;
1179c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        mConnectivityReceiver = new ConnectivityReceiver();
11879d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh
11979d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh        mWifiLock = ((WifiManager)
12079d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh                context.getSystemService(Context.WIFI_SERVICE))
12179d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh                .createWifiLock(WifiManager.WIFI_MODE_FULL, TAG);
12279d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh        mWifiLock.setReferenceCounted(false);
12379d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh        mSipOnWifiOnly = SipManager.isSipWifiOnly(context);
12479d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh
125acedadc1967457ac2f8981c67f884fd8c0ee853cHung-ying Tyan        mMyWakeLock = new SipWakeLock((PowerManager)
126257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan                context.getSystemService(Context.POWER_SERVICE));
1279c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
1284cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan        mTimer = new SipWakeupTimer(context, mExecutor);
129dc7545495e1ef8bad32cd78775f4dc072015eea0Hung-ying Tyan    }
130dc7545495e1ef8bad32cd78775f4dc072015eea0Hung-ying Tyan
1319c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    public synchronized SipProfile[] getListOfProfiles() {
1328127b35b75c13f853dc8eb2fed8bba4bf99e3eedHung-ying Tyan        mContext.enforceCallingOrSelfPermission(
1338127b35b75c13f853dc8eb2fed8bba4bf99e3eedHung-ying Tyan                android.Manifest.permission.USE_SIP, null);
134a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan        boolean isCallerRadio = isCallerRadio();
135a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan        ArrayList<SipProfile> profiles = new ArrayList<SipProfile>();
1369c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        for (SipSessionGroupExt group : mSipGroups.values()) {
137a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan            if (isCallerRadio || isCallerCreator(group)) {
138a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan                profiles.add(group.getLocalProfile());
139a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan            }
1409c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
141a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan        return profiles.toArray(new SipProfile[profiles.size()]);
1429c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    }
1439c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
144dc7545495e1ef8bad32cd78775f4dc072015eea0Hung-ying Tyan    public synchronized void open(SipProfile localProfile) {
1458127b35b75c13f853dc8eb2fed8bba4bf99e3eedHung-ying Tyan        mContext.enforceCallingOrSelfPermission(
1468127b35b75c13f853dc8eb2fed8bba4bf99e3eedHung-ying Tyan                android.Manifest.permission.USE_SIP, null);
1479c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        localProfile.setCallingUid(Binder.getCallingUid());
1489c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        try {
1499c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            createGroup(localProfile);
1509c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        } catch (SipException e) {
1519c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            Log.e(TAG, "openToMakeCalls()", e);
1529c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            // TODO: how to send the exception back
1539c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
1549c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    }
1559c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
1569c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    public synchronized void open3(SipProfile localProfile,
157845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan            PendingIntent incomingCallPendingIntent,
158845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan            ISipSessionListener listener) {
1598127b35b75c13f853dc8eb2fed8bba4bf99e3eedHung-ying Tyan        mContext.enforceCallingOrSelfPermission(
1608127b35b75c13f853dc8eb2fed8bba4bf99e3eedHung-ying Tyan                android.Manifest.permission.USE_SIP, null);
1619c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        localProfile.setCallingUid(Binder.getCallingUid());
162845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan        if (incomingCallPendingIntent == null) {
163845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan            Log.w(TAG, "incomingCallPendingIntent cannot be null; "
164845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan                    + "the profile is not opened");
165a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan            return;
1669c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
1679c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        if (DEBUG) Log.d(TAG, "open3: " + localProfile.getUriString() + ": "
168845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan                + incomingCallPendingIntent + ": " + listener);
1699c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        try {
1709c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            SipSessionGroupExt group = createGroup(localProfile,
171845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan                    incomingCallPendingIntent, listener);
1729c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            if (localProfile.getAutoRegistration()) {
1739c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                group.openToReceiveCalls();
1747d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh                updateWakeLocks();
1759c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            }
1769c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        } catch (SipException e) {
1779c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            Log.e(TAG, "openToReceiveCalls()", e);
1789c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            // TODO: how to send the exception back
1799c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
1809c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    }
1819c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
182a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan    private boolean isCallerCreator(SipSessionGroupExt group) {
183a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan        SipProfile profile = group.getLocalProfile();
184a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan        return (profile.getCallingUid() == Binder.getCallingUid());
185a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan    }
186a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan
187a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan    private boolean isCallerCreatorOrRadio(SipSessionGroupExt group) {
188a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan        return (isCallerRadio() || isCallerCreator(group));
189a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan    }
190a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan
191a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan    private boolean isCallerRadio() {
192a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan        return (Binder.getCallingUid() == Process.PHONE_UID);
193a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan    }
194a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan
1959c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    public synchronized void close(String localProfileUri) {
1968127b35b75c13f853dc8eb2fed8bba4bf99e3eedHung-ying Tyan        mContext.enforceCallingOrSelfPermission(
1978127b35b75c13f853dc8eb2fed8bba4bf99e3eedHung-ying Tyan                android.Manifest.permission.USE_SIP, null);
198a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan        SipSessionGroupExt group = mSipGroups.get(localProfileUri);
199a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan        if (group == null) return;
200a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan        if (!isCallerCreatorOrRadio(group)) {
2016d9d99615a30de0675271553552c3c7b49311354Joe Onorato            Log.w(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();
208257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan
2097d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh        updateWakeLocks();
2109c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    }
2119c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
2129c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    public synchronized boolean isOpened(String localProfileUri) {
2138127b35b75c13f853dc8eb2fed8bba4bf99e3eedHung-ying Tyan        mContext.enforceCallingOrSelfPermission(
2148127b35b75c13f853dc8eb2fed8bba4bf99e3eedHung-ying Tyan                android.Manifest.permission.USE_SIP, null);
2159c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        SipSessionGroupExt group = mSipGroups.get(localProfileUri);
216a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan        if (group == null) return false;
217a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan        if (isCallerCreatorOrRadio(group)) {
218617479363dcafe01bfa1fa025e1d9d122864a0ceHung-ying Tyan            return true;
219a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan        } else {
2206d9d99615a30de0675271553552c3c7b49311354Joe Onorato            Log.w(TAG, "only creator or radio can query on the profile");
221a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan            return false;
222a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan        }
2239c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    }
2249c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
2259c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    public synchronized boolean isRegistered(String localProfileUri) {
2268127b35b75c13f853dc8eb2fed8bba4bf99e3eedHung-ying Tyan        mContext.enforceCallingOrSelfPermission(
2278127b35b75c13f853dc8eb2fed8bba4bf99e3eedHung-ying Tyan                android.Manifest.permission.USE_SIP, null);
2289c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        SipSessionGroupExt group = mSipGroups.get(localProfileUri);
229a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan        if (group == null) return false;
230a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan        if (isCallerCreatorOrRadio(group)) {
231a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan            return group.isRegistered();
232a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan        } else {
2336d9d99615a30de0675271553552c3c7b49311354Joe Onorato            Log.w(TAG, "only creator or radio can query on the profile");
234a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan            return false;
235a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan        }
2369c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    }
2379c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
2389c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    public synchronized void setRegistrationListener(String localProfileUri,
2399c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            ISipSessionListener listener) {
2408127b35b75c13f853dc8eb2fed8bba4bf99e3eedHung-ying Tyan        mContext.enforceCallingOrSelfPermission(
2418127b35b75c13f853dc8eb2fed8bba4bf99e3eedHung-ying Tyan                android.Manifest.permission.USE_SIP, null);
2429c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        SipSessionGroupExt group = mSipGroups.get(localProfileUri);
243a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan        if (group == null) return;
244a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan        if (isCallerCreator(group)) {
245a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan            group.setListener(listener);
246a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan        } else {
2476d9d99615a30de0675271553552c3c7b49311354Joe Onorato            Log.w(TAG, "only creator can set listener on the profile");
248a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan        }
2499c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    }
2509c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
2519c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    public synchronized ISipSession createSession(SipProfile localProfile,
2529c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            ISipSessionListener listener) {
2538127b35b75c13f853dc8eb2fed8bba4bf99e3eedHung-ying Tyan        mContext.enforceCallingOrSelfPermission(
2548127b35b75c13f853dc8eb2fed8bba4bf99e3eedHung-ying Tyan                android.Manifest.permission.USE_SIP, null);
2559c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        localProfile.setCallingUid(Binder.getCallingUid());
2567d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh        if (mNetworkType == -1) return null;
2579c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        try {
2589c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            SipSessionGroupExt group = createGroup(localProfile);
2599c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            return group.createSession(listener);
2609c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        } catch (SipException e) {
2616d9d99615a30de0675271553552c3c7b49311354Joe Onorato            if (DEBUG) Log.d(TAG, "createSession()", e);
2629c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            return null;
2639c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
2649c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    }
2659c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
2669c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    public synchronized ISipSession getPendingSession(String callId) {
2678127b35b75c13f853dc8eb2fed8bba4bf99e3eedHung-ying Tyan        mContext.enforceCallingOrSelfPermission(
2688127b35b75c13f853dc8eb2fed8bba4bf99e3eedHung-ying Tyan                android.Manifest.permission.USE_SIP, null);
2699c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        if (callId == null) return null;
2709c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        return mPendingSessions.get(callId);
2719c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    }
2729c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
2739c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    private String determineLocalIp() {
2749c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        try {
2759c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            DatagramSocket s = new DatagramSocket();
2769c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            s.connect(InetAddress.getByName("192.168.1.1"), 80);
2779c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            return s.getLocalAddress().getHostAddress();
2789c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        } catch (IOException e) {
2796d9d99615a30de0675271553552c3c7b49311354Joe Onorato            if (DEBUG) Log.d(TAG, "determineLocalIp()", e);
2809c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            // dont do anything; there should be a connectivity change going
2819c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            return null;
2829c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
2839c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    }
2849c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
2859c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    private SipSessionGroupExt createGroup(SipProfile localProfile)
2869c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            throws SipException {
2879c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        String key = localProfile.getUriString();
2889c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        SipSessionGroupExt group = mSipGroups.get(key);
2899c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        if (group == null) {
2909c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            group = new SipSessionGroupExt(localProfile, null, null);
2919c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            mSipGroups.put(key, group);
2929c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            notifyProfileAdded(localProfile);
293a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan        } else if (!isCallerCreator(group)) {
294a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan            throw new SipException("only creator can access the profile");
2959c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
2969c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        return group;
2979c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    }
2989c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
2999c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    private SipSessionGroupExt createGroup(SipProfile localProfile,
300845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan            PendingIntent incomingCallPendingIntent,
301845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan            ISipSessionListener listener) throws SipException {
3029c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        String key = localProfile.getUriString();
3039c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        SipSessionGroupExt group = mSipGroups.get(key);
3049c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        if (group != null) {
305a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan            if (!isCallerCreator(group)) {
306a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan                throw new SipException("only creator can access the profile");
307a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan            }
308845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan            group.setIncomingCallPendingIntent(incomingCallPendingIntent);
3099c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            group.setListener(listener);
3109c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        } else {
3119c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            group = new SipSessionGroupExt(localProfile,
312845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan                    incomingCallPendingIntent, listener);
3139c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            mSipGroups.put(key, group);
3149c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            notifyProfileAdded(localProfile);
3159c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
3169c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        return group;
3179c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    }
3189c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
3199c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    private void notifyProfileAdded(SipProfile localProfile) {
3209c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        if (DEBUG) Log.d(TAG, "notify: profile added: " + localProfile);
3219c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        Intent intent = new Intent(SipManager.ACTION_SIP_ADD_PHONE);
3229c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        intent.putExtra(SipManager.EXTRA_LOCAL_URI, localProfile.getUriString());
3239c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        mContext.sendBroadcast(intent);
3247d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh        if (mSipGroups.size() == 1) {
3257d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh            registerReceivers();
3267d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh        }
3279c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    }
3289c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
3299c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    private void notifyProfileRemoved(SipProfile localProfile) {
3309c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        if (DEBUG) Log.d(TAG, "notify: profile removed: " + localProfile);
3319c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        Intent intent = new Intent(SipManager.ACTION_SIP_REMOVE_PHONE);
3329c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        intent.putExtra(SipManager.EXTRA_LOCAL_URI, localProfile.getUriString());
3339c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        mContext.sendBroadcast(intent);
3347d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh        if (mSipGroups.size() == 0) {
3357d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh            unregisterReceivers();
3369c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
3379c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    }
3389c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
339469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang    private void stopPortMappingMeasurement() {
340469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang        if (mIntervalMeasurementProcess != null) {
341469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang            mIntervalMeasurementProcess.stop();
342469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang            mIntervalMeasurementProcess = null;
343469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang        }
344469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang    }
345469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang
3468a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan    private void startPortMappingLifetimeMeasurement(
3478a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan            SipProfile localProfile) {
348cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan        startPortMappingLifetimeMeasurement(localProfile,
349cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan                DEFAULT_MAX_KEEPALIVE_INTERVAL);
35044ccfb03bb349a90546ddb3dc0063cbf4aaddaf1Hung-ying Tyan    }
35144ccfb03bb349a90546ddb3dc0063cbf4aaddaf1Hung-ying Tyan
35244ccfb03bb349a90546ddb3dc0063cbf4aaddaf1Hung-ying Tyan    private void startPortMappingLifetimeMeasurement(
35344ccfb03bb349a90546ddb3dc0063cbf4aaddaf1Hung-ying Tyan            SipProfile localProfile, int maxInterval) {
3548a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan        if ((mIntervalMeasurementProcess == null)
3558a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                && (mKeepAliveInterval == -1)
3568a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                && isBehindNAT(mLocalIp)) {
3578a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan            Log.d(TAG, "start NAT port mapping timeout measurement on "
3588a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                    + localProfile.getUriString());
3598a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan
360cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan            int minInterval = mLastGoodKeepAliveInterval;
361cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan            if (minInterval >= maxInterval) {
362cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan                // If mLastGoodKeepAliveInterval also does not work, reset it
363cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan                // to the default min
364cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan                minInterval = mLastGoodKeepAliveInterval
365cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan                        = DEFAULT_KEEPALIVE_INTERVAL;
366cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan                Log.d(TAG, "  reset min interval to " + minInterval);
367cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan            }
368cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan            mIntervalMeasurementProcess = new IntervalMeasurementProcess(
369cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan                    localProfile, minInterval, maxInterval);
3708a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan            mIntervalMeasurementProcess.start();
3718a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan        }
372469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang    }
373469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang
37444ccfb03bb349a90546ddb3dc0063cbf4aaddaf1Hung-ying Tyan    private void restartPortMappingLifetimeMeasurement(
37544ccfb03bb349a90546ddb3dc0063cbf4aaddaf1Hung-ying Tyan            SipProfile localProfile, int maxInterval) {
37644ccfb03bb349a90546ddb3dc0063cbf4aaddaf1Hung-ying Tyan        stopPortMappingMeasurement();
37744ccfb03bb349a90546ddb3dc0063cbf4aaddaf1Hung-ying Tyan        mKeepAliveInterval = -1;
37844ccfb03bb349a90546ddb3dc0063cbf4aaddaf1Hung-ying Tyan        startPortMappingLifetimeMeasurement(localProfile, maxInterval);
37944ccfb03bb349a90546ddb3dc0063cbf4aaddaf1Hung-ying Tyan    }
38044ccfb03bb349a90546ddb3dc0063cbf4aaddaf1Hung-ying Tyan
3819c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    private synchronized void addPendingSession(ISipSession session) {
3829c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        try {
3833f4d44657ccad3ed02ed0e1354387b14b07dc011Hung-ying Tyan            cleanUpPendingSessions();
3849c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            mPendingSessions.put(session.getCallId(), session);
3853f4d44657ccad3ed02ed0e1354387b14b07dc011Hung-ying Tyan            if (DEBUG) Log.d(TAG, "#pending sess=" + mPendingSessions.size());
3869c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        } catch (RemoteException e) {
3879c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            // should not happen with a local call
3889c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            Log.e(TAG, "addPendingSession()", e);
3899c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
3909c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    }
3919c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
3923f4d44657ccad3ed02ed0e1354387b14b07dc011Hung-ying Tyan    private void cleanUpPendingSessions() throws RemoteException {
3933f4d44657ccad3ed02ed0e1354387b14b07dc011Hung-ying Tyan        Map.Entry<String, ISipSession>[] entries =
3943f4d44657ccad3ed02ed0e1354387b14b07dc011Hung-ying Tyan                mPendingSessions.entrySet().toArray(
3953f4d44657ccad3ed02ed0e1354387b14b07dc011Hung-ying Tyan                new Map.Entry[mPendingSessions.size()]);
3963f4d44657ccad3ed02ed0e1354387b14b07dc011Hung-ying Tyan        for (Map.Entry<String, ISipSession> entry : entries) {
3973f4d44657ccad3ed02ed0e1354387b14b07dc011Hung-ying Tyan            if (entry.getValue().getState() != SipSession.State.INCOMING_CALL) {
3983f4d44657ccad3ed02ed0e1354387b14b07dc011Hung-ying Tyan                mPendingSessions.remove(entry.getKey());
3993f4d44657ccad3ed02ed0e1354387b14b07dc011Hung-ying Tyan            }
4003f4d44657ccad3ed02ed0e1354387b14b07dc011Hung-ying Tyan        }
4013f4d44657ccad3ed02ed0e1354387b14b07dc011Hung-ying Tyan    }
4023f4d44657ccad3ed02ed0e1354387b14b07dc011Hung-ying Tyan
403ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan    private synchronized boolean callingSelf(SipSessionGroupExt ringingGroup,
404ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan            SipSessionGroup.SipSessionImpl ringingSession) {
405ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan        String callId = ringingSession.getCallId();
406ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan        for (SipSessionGroupExt group : mSipGroups.values()) {
407ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan            if ((group != ringingGroup) && group.containsSession(callId)) {
408ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan                if (DEBUG) Log.d(TAG, "call self: "
409ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan                        + ringingSession.getLocalProfile().getUriString()
410ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan                        + " -> " + group.getLocalProfile().getUriString());
411ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan                return true;
412ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan            }
413ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan        }
414ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan        return false;
415ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan    }
416ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan
4178a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan    private synchronized void onKeepAliveIntervalChanged() {
4188a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan        for (SipSessionGroupExt group : mSipGroups.values()) {
4198a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan            group.onKeepAliveIntervalChanged();
4208a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan        }
4218a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan    }
4228a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan
4238a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan    private int getKeepAliveInterval() {
4248a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan        return (mKeepAliveInterval < 0)
425cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan                ? mLastGoodKeepAliveInterval
4268a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                : mKeepAliveInterval;
4278a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan    }
4288a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan
4298a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan    private boolean isBehindNAT(String address) {
4308a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan        try {
4318a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan            byte[] d = InetAddress.getByName(address).getAddress();
4328a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan            if ((d[0] == 10) ||
4338a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                    (((0x000000FF & ((int)d[0])) == 172) &&
4348a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                    ((0x000000F0 & ((int)d[1])) == 16)) ||
4358a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                    (((0x000000FF & ((int)d[0])) == 192) &&
4368a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                    ((0x000000FF & ((int)d[1])) == 168))) {
4378a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                return true;
4388a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan            }
4398a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan        } catch (UnknownHostException e) {
4408a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan            Log.e(TAG, "isBehindAT()" + address, e);
4418a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan        }
4428a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan        return false;
4438a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan    }
444ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan
4459c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    private class SipSessionGroupExt extends SipSessionAdapter {
4469c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        private SipSessionGroup mSipGroup;
447845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan        private PendingIntent mIncomingCallPendingIntent;
448617479363dcafe01bfa1fa025e1d9d122864a0ceHung-ying Tyan        private boolean mOpenedToReceiveCalls;
4499c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
4509c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        private AutoRegistrationProcess mAutoRegistration =
4519c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                new AutoRegistrationProcess();
4529c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
4539c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        public SipSessionGroupExt(SipProfile localProfile,
454845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan                PendingIntent incomingCallPendingIntent,
4559c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                ISipSessionListener listener) throws SipException {
4569c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            String password = localProfile.getPassword();
4579c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            SipProfile p = duplicate(localProfile);
4589c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            mSipGroup = createSipSessionGroup(mLocalIp, p, password);
459845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan            mIncomingCallPendingIntent = incomingCallPendingIntent;
4609c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            mAutoRegistration.setListener(listener);
4619c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
4629c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
4639c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        public SipProfile getLocalProfile() {
4649c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            return mSipGroup.getLocalProfile();
4659c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
4669c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
467ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan        public boolean containsSession(String callId) {
468ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan            return mSipGroup.containsSession(callId);
469ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan        }
470ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan
4718a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan        public void onKeepAliveIntervalChanged() {
4728a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan            mAutoRegistration.onKeepAliveIntervalChanged();
4738a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan        }
4748a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan
4758a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan        // TODO: remove this method once SipWakeupTimer can better handle variety
4768a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan        // of timeout values
4778a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan        void setWakeupTimer(SipWakeupTimer timer) {
4788a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan            mSipGroup.setWakeupTimer(timer);
4798a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan        }
4808a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan
4819c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        // network connectivity is tricky because network can be disconnected
4829c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        // at any instant so need to deal with exceptions carefully even when
4839c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        // you think you are connected
4849c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        private SipSessionGroup createSipSessionGroup(String localIp,
4859c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                SipProfile localProfile, String password) throws SipException {
4869c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            try {
487acedadc1967457ac2f8981c67f884fd8c0ee853cHung-ying Tyan                return new SipSessionGroup(localIp, localProfile, password,
4888a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                        mTimer, mMyWakeLock);
4899c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            } catch (IOException e) {
4909c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                // network disconnected
4919c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                Log.w(TAG, "createSipSessionGroup(): network disconnected?");
4929c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                if (localIp != null) {
4939c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                    return createSipSessionGroup(null, localProfile, password);
4949c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                } else {
4959c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                    // recursive
4966d9d99615a30de0675271553552c3c7b49311354Joe Onorato                    Log.wtf(TAG, "impossible! recursive!");
4979c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                    throw new RuntimeException("createSipSessionGroup");
4989c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                }
4999c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            }
5009c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
5019c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
5029c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        private SipProfile duplicate(SipProfile p) {
5039c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            try {
5049c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                return new SipProfile.Builder(p).setPassword("*").build();
5059c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            } catch (Exception e) {
5069c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                Log.wtf(TAG, "duplicate()", e);
5079c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                throw new RuntimeException("duplicate profile", e);
5089c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            }
5099c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
5109c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
5119c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        public void setListener(ISipSessionListener listener) {
5129c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            mAutoRegistration.setListener(listener);
5139c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
5149c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
515845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan        public void setIncomingCallPendingIntent(PendingIntent pIntent) {
516845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan            mIncomingCallPendingIntent = pIntent;
5179c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
5189c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
5199c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        public void openToReceiveCalls() throws SipException {
520617479363dcafe01bfa1fa025e1d9d122864a0ceHung-ying Tyan            mOpenedToReceiveCalls = true;
5217d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh            if (mNetworkType != -1) {
5229c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                mSipGroup.openToReceiveCalls(this);
5239c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                mAutoRegistration.start(mSipGroup);
5249c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            }
5259c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            if (DEBUG) Log.d(TAG, "  openToReceiveCalls: " + getUri() + ": "
526845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan                    + mIncomingCallPendingIntent);
5279c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
5289c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
5299c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        public void onConnectivityChanged(boolean connected)
5309c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                throws SipException {
5319c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            mSipGroup.onConnectivityChanged();
5329c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            if (connected) {
5339c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                resetGroup(mLocalIp);
534617479363dcafe01bfa1fa025e1d9d122864a0ceHung-ying Tyan                if (mOpenedToReceiveCalls) openToReceiveCalls();
5359c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            } else {
536617479363dcafe01bfa1fa025e1d9d122864a0ceHung-ying Tyan                // close mSipGroup but remember mOpenedToReceiveCalls
5379c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                if (DEBUG) Log.d(TAG, "  close auto reg temporarily: "
538845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan                        + getUri() + ": " + mIncomingCallPendingIntent);
5399c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                mSipGroup.close();
5409c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                mAutoRegistration.stop();
5419c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            }
5429c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
5439c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
5449c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        private void resetGroup(String localIp) throws SipException {
5459c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            try {
5469c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                mSipGroup.reset(localIp);
5479c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            } catch (IOException e) {
5489c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                // network disconnected
5499c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                Log.w(TAG, "resetGroup(): network disconnected?");
5509c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                if (localIp != null) {
5519c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                    resetGroup(null); // reset w/o local IP
5529c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                } else {
5539c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                    // recursive
5549c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                    Log.wtf(TAG, "impossible!");
5559c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                    throw new RuntimeException("resetGroup");
5569c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                }
5579c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            }
5589c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
5599c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
5609c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        public void close() {
561617479363dcafe01bfa1fa025e1d9d122864a0ceHung-ying Tyan            mOpenedToReceiveCalls = false;
5629c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            mSipGroup.close();
5639c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            mAutoRegistration.stop();
5649c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            if (DEBUG) Log.d(TAG, "   close: " + getUri() + ": "
565845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan                    + mIncomingCallPendingIntent);
5669c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
5679c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
5689c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        public ISipSession createSession(ISipSessionListener listener) {
5699c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            return mSipGroup.createSession(listener);
5709c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
5719c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
5729c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        @Override
573845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan        public void onRinging(ISipSession s, SipProfile caller,
5749c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                String sessionDescription) {
57585caf063c027ba0d1defeaff8850e12b6428c4f7Chia-chi Yeh            if (DEBUG) Log.d(TAG, "<<<<< onRinging()");
576845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan            SipSessionGroup.SipSessionImpl session =
577845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan                    (SipSessionGroup.SipSessionImpl) s;
5789c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            synchronized (SipService.this) {
5799c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                try {
580ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan                    if (!isRegistered() || callingSelf(this, session)) {
5819c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                        session.endCall();
5829c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                        return;
5839c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                    }
5849c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
5859c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                    // send out incoming call broadcast
5869c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                    addPendingSession(session);
5879c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                    Intent intent = SipManager.createIncomingCallBroadcast(
588845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan                            session.getCallId(), sessionDescription);
5899c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                    if (DEBUG) Log.d(TAG, " ringing~~ " + getUri() + ": "
5909c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                            + caller.getUri() + ": " + session.getCallId()
591845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan                            + " " + mIncomingCallPendingIntent);
592845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan                    mIncomingCallPendingIntent.send(mContext,
593845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan                            SipManager.INCOMING_CALL_RESULT_CODE, intent);
594845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan                } catch (PendingIntent.CanceledException e) {
595845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan                    Log.w(TAG, "pendingIntent is canceled, drop incoming call");
596845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan                    session.endCall();
5979c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                }
5989c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            }
5999c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
6009c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
6019c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        @Override
6029c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        public void onError(ISipSession session, int errorCode,
6039c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                String message) {
6049c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            if (DEBUG) Log.d(TAG, "sip session error: "
6059c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                    + SipErrorCode.toString(errorCode) + ": " + message);
6069c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
6079c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
608617479363dcafe01bfa1fa025e1d9d122864a0ceHung-ying Tyan        public boolean isOpenedToReceiveCalls() {
609617479363dcafe01bfa1fa025e1d9d122864a0ceHung-ying Tyan            return mOpenedToReceiveCalls;
6109c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
6119c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
6129c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        public boolean isRegistered() {
6139c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            return mAutoRegistration.isRegistered();
6149c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
6159c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
6169c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        private String getUri() {
6179c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            return mSipGroup.getLocalProfileUri();
6189c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
6199c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    }
6209c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
6217d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan    private class IntervalMeasurementProcess implements Runnable,
6228a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan            SipSessionGroup.KeepAliveProcessCallback {
6238a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan        private static final String TAG = "SipKeepAliveInterval";
6247d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan        private static final int MIN_INTERVAL = 5; // in seconds
6258a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan        private static final int PASS_THRESHOLD = 10;
62644ccfb03bb349a90546ddb3dc0063cbf4aaddaf1Hung-ying Tyan        private static final int MAX_RETRY_COUNT = 5;
6277d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan        private static final int NAT_MEASUREMENT_RETRY_INTERVAL = 120; // in seconds
62837f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh        private SipProfile mLocalProfile;
629469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang        private SipSessionGroupExt mGroup;
630469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang        private SipSessionGroup.SipSessionImpl mSession;
631cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan        private int mMinInterval;
63244ccfb03bb349a90546ddb3dc0063cbf4aaddaf1Hung-ying Tyan        private int mMaxInterval;
63344ccfb03bb349a90546ddb3dc0063cbf4aaddaf1Hung-ying Tyan        private int mInterval;
63437f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh        private int mPassCount;
63544ccfb03bb349a90546ddb3dc0063cbf4aaddaf1Hung-ying Tyan
636cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan        public IntervalMeasurementProcess(SipProfile localProfile,
637cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan                int minInterval, int maxInterval) {
638cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan            mMaxInterval = maxInterval;
639cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan            mMinInterval = minInterval;
64037f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh            mLocalProfile = localProfile;
641469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang        }
642469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang
643469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang        public void start() {
6448a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan            synchronized (SipService.this) {
64537f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh                if (mSession != null) {
64637f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh                    return;
6477d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan                }
64837f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh
64937f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh                mInterval = (mMaxInterval + mMinInterval) / 2;
65037f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh                mPassCount = 0;
65137f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh
65237f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh                // Don't start measurement if the interval is too small
65337f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh                if (mInterval < DEFAULT_KEEPALIVE_INTERVAL || checkTermination()) {
65437f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh                    Log.w(TAG, "measurement aborted; interval=[" +
65537f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh                            mMinInterval + "," + mMaxInterval + "]");
65637f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh                    return;
65737f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh                }
65837f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh
6598a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                try {
66037f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh                    Log.d(TAG, "start measurement w interval=" + mInterval);
66137f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh
66237f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh                    mGroup = new SipSessionGroupExt(mLocalProfile, null, null);
66337f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh                    // TODO: remove this line once SipWakeupTimer can better handle
66437f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh                    // variety of timeout values
66537f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh                    mGroup.setWakeupTimer(new SipWakeupTimer(mContext, mExecutor));
66637f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh
66737f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh                    mSession = (SipSessionGroup.SipSessionImpl)
66837f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh                            mGroup.createSession(null);
6698a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                    mSession.startKeepAliveProcess(mInterval, this);
67037f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh                } catch (Throwable t) {
67137f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh                    onError(SipErrorCode.CLIENT_ERROR, t.toString());
6728a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                }
6738a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan            }
674469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang        }
675469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang
676469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang        public void stop() {
6778a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan            synchronized (SipService.this) {
6787d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan                if (mSession != null) {
6797d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan                    mSession.stopKeepAliveProcess();
6807d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan                    mSession = null;
6817d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan                }
68237f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh                if (mGroup != null) {
68337f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh                    mGroup.close();
68437f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh                    mGroup = null;
68537f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh                }
6867d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan                mTimer.cancel(this);
687469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang            }
688469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang        }
689469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang
6908a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan        private void restart() {
691469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang            synchronized (SipService.this) {
6927d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan                // Return immediately if the measurement process is stopped
6937d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan                if (mSession == null) return;
6947d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan
6957d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan                Log.d(TAG, "restart measurement w interval=" + mInterval);
696469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang                try {
6978a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                    mSession.stopKeepAliveProcess();
6987d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan                    mPassCount = 0;
6998a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                    mSession.startKeepAliveProcess(mInterval, this);
7008a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                } catch (SipException e) {
7018a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                    Log.e(TAG, "restart()", e);
702469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang                }
703469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang            }
704469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang        }
705469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang
706cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan        private boolean checkTermination() {
707cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan            return ((mMaxInterval - mMinInterval) < MIN_INTERVAL);
708cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan        }
709cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan
7108a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan        // SipSessionGroup.KeepAliveProcessCallback
7118a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan        @Override
7128a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan        public void onResponse(boolean portChanged) {
7139c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            synchronized (SipService.this) {
7148a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                if (!portChanged) {
71544ccfb03bb349a90546ddb3dc0063cbf4aaddaf1Hung-ying Tyan                    if (++mPassCount != PASS_THRESHOLD) return;
7168a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                    // update the interval, since the current interval is good to
7178a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                    // keep the port mapping.
718cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan                    if (mKeepAliveInterval > 0) {
719cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan                        mLastGoodKeepAliveInterval = mKeepAliveInterval;
720cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan                    }
7218a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                    mKeepAliveInterval = mMinInterval = mInterval;
7228a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                    if (DEBUG) {
7238a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                        Log.d(TAG, "measured good keepalive interval: "
7248a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                                + mKeepAliveInterval);
725257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan                    }
7268a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                    onKeepAliveIntervalChanged();
7278a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                } else {
7288a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                    // Since the rport is changed, shorten the interval.
7298a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                    mMaxInterval = mInterval;
7308a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                }
731cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan                if (checkTermination()) {
7328a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                    // update mKeepAliveInterval and stop measurement.
7338a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                    stop();
734cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan                    // If all the measurements failed, we still set it to
735cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan                    // mMinInterval; If mMinInterval still doesn't work, a new
736cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan                    // measurement with min interval=DEFAULT_KEEPALIVE_INTERVAL
737cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan                    // will be conducted.
7388a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                    mKeepAliveInterval = mMinInterval;
7398a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                    if (DEBUG) {
7408a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                        Log.d(TAG, "measured keepalive interval: "
7418a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                                + mKeepAliveInterval);
742469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang                    }
7438a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                } else {
7448a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                    // calculate the new interval and continue.
7458a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                    mInterval = (mMaxInterval + mMinInterval) / 2;
7468a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                    if (DEBUG) {
7478a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                        Log.d(TAG, "current interval: " + mKeepAliveInterval
7488a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                                + ", test new interval: " + mInterval);
7498a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                    }
7508a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                    restart();
7519c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                }
7529c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            }
7539c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
7549c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
7558a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan        // SipSessionGroup.KeepAliveProcessCallback
7568a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan        @Override
7578a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan        public void onError(int errorCode, String description) {
7587d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan            Log.w(TAG, "interval measurement error: " + description);
7597d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan            restartLater();
7607d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan        }
7617d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan
7627d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan        // timeout handler
7637d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan        @Override
7647d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan        public void run() {
7657d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan            mTimer.cancel(this);
7667d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan            restart();
7677d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan        }
7687d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan
7697d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan        private void restartLater() {
7708a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan            synchronized (SipService.this) {
7717d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan                int interval = NAT_MEASUREMENT_RETRY_INTERVAL;
7727d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan                mTimer.cancel(this);
7737d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan                mTimer.set(interval * 1000, this);
7748a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan            }
7759c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
7769c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    }
7779c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
7789c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    private class AutoRegistrationProcess extends SipSessionAdapter
7798a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan            implements Runnable, SipSessionGroup.KeepAliveProcessCallback {
7807d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan        private static final int MIN_KEEPALIVE_SUCCESS_COUNT = 10;
78185caf063c027ba0d1defeaff8850e12b6428c4f7Chia-chi Yeh        private String TAG = "SipAutoReg";
7827d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan
7839c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        private SipSessionGroup.SipSessionImpl mSession;
7848a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan        private SipSessionGroup.SipSessionImpl mKeepAliveSession;
7859c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        private SipSessionListenerProxy mProxy = new SipSessionListenerProxy();
7869c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        private int mBackoff = 1;
7879c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        private boolean mRegistered;
7889c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        private long mExpiryTime;
7899c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        private int mErrorCode;
7909c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        private String mErrorMessage;
791d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan        private boolean mRunning = false;
7929c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
7937d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan        private int mKeepAliveSuccessCount = 0;
7947d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan
7959c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        private String getAction() {
7969c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            return toString();
7979c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
7989c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
7999c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        public void start(SipSessionGroup group) {
800d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan            if (!mRunning) {
801d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan                mRunning = true;
8029c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                mBackoff = 1;
8039c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                mSession = (SipSessionGroup.SipSessionImpl)
8049c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                        group.createSession(this);
8059c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                // return right away if no active network connection.
8069c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                if (mSession == null) return;
8079c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
8089c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                // start unregistration to clear up old registration at server
8099c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                // TODO: when rfc5626 is deployed, use reg-id and sip.instance
8109c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                // in registration to avoid adding duplicate entries to server
811257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan                mMyWakeLock.acquire(mSession);
8129c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                mSession.unregister();
81385caf063c027ba0d1defeaff8850e12b6428c4f7Chia-chi Yeh                TAG = "SipAutoReg:" + mSession.getLocalProfile().getUriString();
8149c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            }
8159c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
8169c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
8177d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan        private void startKeepAliveProcess(int interval) {
81885caf063c027ba0d1defeaff8850e12b6428c4f7Chia-chi Yeh            if (DEBUG) Log.d(TAG, "start keepalive w interval=" + interval);
8197d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan            if (mKeepAliveSession == null) {
8207d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan                mKeepAliveSession = mSession.duplicate();
8217d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan            } else {
8227d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan                mKeepAliveSession.stopKeepAliveProcess();
8237d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan            }
8247d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan            try {
8257d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan                mKeepAliveSession.startKeepAliveProcess(interval, this);
8267d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan            } catch (SipException e) {
8277d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan                Log.e(TAG, "failed to start keepalive w interval=" + interval,
8287d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan                        e);
8297d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan            }
8307d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan        }
8317d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan
8327d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan        private void stopKeepAliveProcess() {
8337d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan            if (mKeepAliveSession != null) {
8347d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan                mKeepAliveSession.stopKeepAliveProcess();
8357d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan                mKeepAliveSession = null;
8367d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan            }
8377d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan            mKeepAliveSuccessCount = 0;
8387d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan        }
8397d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan
8408a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan        // SipSessionGroup.KeepAliveProcessCallback
8418a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan        @Override
8428a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan        public void onResponse(boolean portChanged) {
8438a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan            synchronized (SipService.this) {
84444ccfb03bb349a90546ddb3dc0063cbf4aaddaf1Hung-ying Tyan                if (portChanged) {
8457d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan                    int interval = getKeepAliveInterval();
8467d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan                    if (mKeepAliveSuccessCount < MIN_KEEPALIVE_SUCCESS_COUNT) {
8477d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan                        Log.i(TAG, "keepalive doesn't work with interval "
8487d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan                                + interval + ", past success count="
8497d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan                                + mKeepAliveSuccessCount);
8507d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan                        if (interval > DEFAULT_KEEPALIVE_INTERVAL) {
8517d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan                            restartPortMappingLifetimeMeasurement(
8527d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan                                    mSession.getLocalProfile(), interval);
8537d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan                            mKeepAliveSuccessCount = 0;
8547d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan                        }
8557d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan                    } else {
85685caf063c027ba0d1defeaff8850e12b6428c4f7Chia-chi Yeh                        if (DEBUG) {
85785caf063c027ba0d1defeaff8850e12b6428c4f7Chia-chi Yeh                            Log.i(TAG, "keep keepalive going with interval "
85885caf063c027ba0d1defeaff8850e12b6428c4f7Chia-chi Yeh                                    + interval + ", past success count="
85985caf063c027ba0d1defeaff8850e12b6428c4f7Chia-chi Yeh                                    + mKeepAliveSuccessCount);
86085caf063c027ba0d1defeaff8850e12b6428c4f7Chia-chi Yeh                        }
8617d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan                        mKeepAliveSuccessCount /= 2;
8627d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan                    }
86344ccfb03bb349a90546ddb3dc0063cbf4aaddaf1Hung-ying Tyan                } else {
86444ccfb03bb349a90546ddb3dc0063cbf4aaddaf1Hung-ying Tyan                    // Start keep-alive interval measurement on the first
86544ccfb03bb349a90546ddb3dc0063cbf4aaddaf1Hung-ying Tyan                    // successfully kept-alive SipSessionGroup
86644ccfb03bb349a90546ddb3dc0063cbf4aaddaf1Hung-ying Tyan                    startPortMappingLifetimeMeasurement(
86744ccfb03bb349a90546ddb3dc0063cbf4aaddaf1Hung-ying Tyan                            mSession.getLocalProfile());
8687d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan                    mKeepAliveSuccessCount++;
86944ccfb03bb349a90546ddb3dc0063cbf4aaddaf1Hung-ying Tyan                }
8708a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan
8718a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                if (!mRunning || !portChanged) return;
8729dbe2c72276b9968593054dcfd39fd5135a574aaHung-ying Tyan
8739dbe2c72276b9968593054dcfd39fd5135a574aaHung-ying Tyan                // The keep alive process is stopped when port is changed;
8749dbe2c72276b9968593054dcfd39fd5135a574aaHung-ying Tyan                // Nullify the session so that the process can be restarted
8759dbe2c72276b9968593054dcfd39fd5135a574aaHung-ying Tyan                // again when the re-registration is done
8769dbe2c72276b9968593054dcfd39fd5135a574aaHung-ying Tyan                mKeepAliveSession = null;
8779dbe2c72276b9968593054dcfd39fd5135a574aaHung-ying Tyan
8788a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                // Acquire wake lock for the registration process. The
8798a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                // lock will be released when registration is complete.
8808a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                mMyWakeLock.acquire(mSession);
8818a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                mSession.register(EXPIRY_TIME);
8828a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan            }
8838a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan        }
8848a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan
8858a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan        // SipSessionGroup.KeepAliveProcessCallback
8868a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan        @Override
8878a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan        public void onError(int errorCode, String description) {
88885caf063c027ba0d1defeaff8850e12b6428c4f7Chia-chi Yeh            if (DEBUG) {
88985caf063c027ba0d1defeaff8850e12b6428c4f7Chia-chi Yeh                Log.e(TAG, "keepalive error: " + description);
89085caf063c027ba0d1defeaff8850e12b6428c4f7Chia-chi Yeh            }
89144ccfb03bb349a90546ddb3dc0063cbf4aaddaf1Hung-ying Tyan            onResponse(true); // re-register immediately
8928a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan        }
8938a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan
8949c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        public void stop() {
895d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan            if (!mRunning) return;
896d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan            mRunning = false;
897257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan            mMyWakeLock.release(mSession);
898257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan            if (mSession != null) {
899257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan                mSession.setListener(null);
9007d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh                if (mNetworkType != -1 && mRegistered) mSession.unregister();
901257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan            }
902d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan
9039c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            mTimer.cancel(this);
9047d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan            stopKeepAliveProcess();
9059c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
906d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan            mRegistered = false;
907d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan            setListener(mProxy.getListener());
9089c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
9099c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
9108a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan        public void onKeepAliveIntervalChanged() {
9118a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan            if (mKeepAliveSession != null) {
9128a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                int newInterval = getKeepAliveInterval();
91385caf063c027ba0d1defeaff8850e12b6428c4f7Chia-chi Yeh                if (DEBUG) {
9148a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                    Log.v(TAG, "restart keepalive w interval=" + newInterval);
9158a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                }
9167d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan                mKeepAliveSuccessCount = 0;
9177d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan                startKeepAliveProcess(newInterval);
9188a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan            }
9198a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan        }
9208a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan
9219c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        public void setListener(ISipSessionListener listener) {
9229c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            synchronized (SipService.this) {
9239c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                mProxy.setListener(listener);
9249c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
9259c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                try {
9269c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                    int state = (mSession == null)
9279c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                            ? SipSession.State.READY_TO_CALL
9289c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                            : mSession.getState();
9299c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                    if ((state == SipSession.State.REGISTERING)
9309c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                            || (state == SipSession.State.DEREGISTERING)) {
9319c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                        mProxy.onRegistering(mSession);
9329c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                    } else if (mRegistered) {
9339c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                        int duration = (int)
9349c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                                (mExpiryTime - SystemClock.elapsedRealtime());
9359c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                        mProxy.onRegistrationDone(mSession, duration);
9369c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                    } else if (mErrorCode != SipErrorCode.NO_ERROR) {
9379c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                        if (mErrorCode == SipErrorCode.TIME_OUT) {
9389c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                            mProxy.onRegistrationTimeout(mSession);
9399c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                        } else {
9409c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                            mProxy.onRegistrationFailed(mSession, mErrorCode,
9419c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                                    mErrorMessage);
9429c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                        }
9437d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh                    } else if (mNetworkType == -1) {
944d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan                        mProxy.onRegistrationFailed(mSession,
945d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan                                SipErrorCode.DATA_CONNECTION_LOST,
946d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan                                "no data connection");
947d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan                    } else if (!mRunning) {
948d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan                        mProxy.onRegistrationFailed(mSession,
949d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan                                SipErrorCode.CLIENT_ERROR,
950d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan                                "registration not running");
951d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan                    } else {
952d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan                        mProxy.onRegistrationFailed(mSession,
953d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan                                SipErrorCode.IN_PROGRESS,
954d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan                                String.valueOf(state));
9559c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                    }
9569c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                } catch (Throwable t) {
9579c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                    Log.w(TAG, "setListener(): " + t);
9589c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                }
9599c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            }
9609c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
9619c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
9629c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        public boolean isRegistered() {
9639c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            return mRegistered;
9649c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
9659c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
966257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan        // timeout handler: re-register
9678a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan        @Override
9689c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        public void run() {
969d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan            synchronized (SipService.this) {
970d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan                if (!mRunning) return;
971d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan
972d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan                mErrorCode = SipErrorCode.NO_ERROR;
973d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan                mErrorMessage = null;
9748a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                if (DEBUG) Log.d(TAG, "registering");
9757d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh                if (mNetworkType != -1) {
976257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan                    mMyWakeLock.acquire(mSession);
977257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan                    mSession.register(EXPIRY_TIME);
978257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan                }
9799c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            }
9809c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
9819c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
9829c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        private void restart(int duration) {
98385caf063c027ba0d1defeaff8850e12b6428c4f7Chia-chi Yeh            Log.d(TAG, "Refresh registration " + duration + "s later.");
9849c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            mTimer.cancel(this);
9859c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            mTimer.set(duration * 1000, this);
9869c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
9879c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
9889c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        private int backoffDuration() {
9899c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            int duration = SHORT_EXPIRY_TIME * mBackoff;
9909c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            if (duration > 3600) {
9919c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                duration = 3600;
9929c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            } else {
9939c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                mBackoff *= 2;
9949c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            }
9959c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            return duration;
9969c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
9979c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
9989c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        @Override
9999c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        public void onRegistering(ISipSession session) {
10009c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            if (DEBUG) Log.d(TAG, "onRegistering(): " + session);
10019c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            synchronized (SipService.this) {
1002d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan                if (notCurrentSession(session)) return;
1003d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan
10049c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                mRegistered = false;
10059c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                mProxy.onRegistering(session);
10069c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            }
10079c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
10089c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
1009d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan        private boolean notCurrentSession(ISipSession session) {
1010d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan            if (session != mSession) {
1011d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan                ((SipSessionGroup.SipSessionImpl) session).setListener(null);
1012257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan                mMyWakeLock.release(session);
1013d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan                return true;
1014d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan            }
1015d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan            return !mRunning;
1016d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan        }
1017d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan
10189c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        @Override
10199c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        public void onRegistrationDone(ISipSession session, int duration) {
10209c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            if (DEBUG) Log.d(TAG, "onRegistrationDone(): " + session);
10219c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            synchronized (SipService.this) {
1022d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan                if (notCurrentSession(session)) return;
10239c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
10249c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                mProxy.onRegistrationDone(session, duration);
10259c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
10269c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                if (duration > 0) {
10279c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                    mExpiryTime = SystemClock.elapsedRealtime()
10289c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                            + (duration * 1000);
10299c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
10309c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                    if (!mRegistered) {
10319c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                        mRegistered = true;
10329c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                        // allow some overlap to avoid call drop during renew
10339c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                        duration -= MIN_EXPIRY_TIME;
10349c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                        if (duration < MIN_EXPIRY_TIME) {
10359c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                            duration = MIN_EXPIRY_TIME;
10369c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                        }
10379c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                        restart(duration);
10389c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
10398a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                        SipProfile localProfile = mSession.getLocalProfile();
10408a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                        if ((mKeepAliveSession == null) && (isBehindNAT(mLocalIp)
10418a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                                || localProfile.getSendKeepAlive())) {
10427d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan                            startKeepAliveProcess(getKeepAliveInterval());
10439c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                        }
10449c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                    }
1045257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan                    mMyWakeLock.release(session);
10469c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                } else {
10479c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                    mRegistered = false;
10489c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                    mExpiryTime = -1L;
10499c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                    if (DEBUG) Log.d(TAG, "Refresh registration immediately");
10509c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                    run();
10519c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                }
10529c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            }
10539c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
10549c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
10559c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        @Override
10569c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        public void onRegistrationFailed(ISipSession session, int errorCode,
10579c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                String message) {
10589c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            if (DEBUG) Log.d(TAG, "onRegistrationFailed(): " + session + ": "
10599c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                    + SipErrorCode.toString(errorCode) + ": " + message);
10609c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            synchronized (SipService.this) {
1061d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan                if (notCurrentSession(session)) return;
10629c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
1063fcc474636f42243cfce960158373b9c49636a556Hung-ying Tyan                switch (errorCode) {
1064fcc474636f42243cfce960158373b9c49636a556Hung-ying Tyan                    case SipErrorCode.INVALID_CREDENTIALS:
1065fcc474636f42243cfce960158373b9c49636a556Hung-ying Tyan                    case SipErrorCode.SERVER_UNREACHABLE:
1066fcc474636f42243cfce960158373b9c49636a556Hung-ying Tyan                        if (DEBUG) Log.d(TAG, "   pause auto-registration");
1067fcc474636f42243cfce960158373b9c49636a556Hung-ying Tyan                        stop();
10680b88a073712b1510db7c636f89c4e19f0131449aHung-ying Tyan                        break;
1069fcc474636f42243cfce960158373b9c49636a556Hung-ying Tyan                    default:
1070fcc474636f42243cfce960158373b9c49636a556Hung-ying Tyan                        restartLater();
10719c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                }
1072d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan
1073d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan                mErrorCode = errorCode;
1074d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan                mErrorMessage = message;
1075d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan                mProxy.onRegistrationFailed(session, errorCode, message);
1076257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan                mMyWakeLock.release(session);
10779c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            }
10789c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
10799c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
10809c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        @Override
10819c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        public void onRegistrationTimeout(ISipSession session) {
10829c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            if (DEBUG) Log.d(TAG, "onRegistrationTimeout(): " + session);
10839c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            synchronized (SipService.this) {
1084d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan                if (notCurrentSession(session)) return;
1085d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan
10869c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                mErrorCode = SipErrorCode.TIME_OUT;
10879c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                mProxy.onRegistrationTimeout(session);
1088fcc474636f42243cfce960158373b9c49636a556Hung-ying Tyan                restartLater();
1089257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan                mMyWakeLock.release(session);
10909c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            }
10919c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
10929c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
1093fcc474636f42243cfce960158373b9c49636a556Hung-ying Tyan        private void restartLater() {
10949c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            mRegistered = false;
10959c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            restart(backoffDuration());
10969c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
10979c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    }
10989c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
10999c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    private class ConnectivityReceiver extends BroadcastReceiver {
11009c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        @Override
110179d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh        public void onReceive(Context context, Intent intent) {
110279d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh            Bundle bundle = intent.getExtras();
110379d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh            if (bundle != null) {
110479d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh                final NetworkInfo info = (NetworkInfo)
110579d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh                        bundle.get(ConnectivityManager.EXTRA_NETWORK_INFO);
11069c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
110779d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh                // Run the handler in MyExecutor to be protected by wake lock
110879d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh                mExecutor.execute(new Runnable() {
110979d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh                    public void run() {
111079d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh                        onConnectivityChanged(info);
11119c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                    }
111279d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh                });
11139c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            }
11149c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
111579d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh    }
111679d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh
111779d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh    private void registerReceivers() {
111879d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh        mContext.registerReceiver(mConnectivityReceiver,
111979d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh                new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));
112079d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh        if (DEBUG) Log.d(TAG, " +++ register receivers");
112179d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh    }
11229c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
112379d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh    private void unregisterReceivers() {
112479d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh        mContext.unregisterReceiver(mConnectivityReceiver);
112579d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh        if (DEBUG) Log.d(TAG, " --- unregister receivers");
112679d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh
112779d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh        // Reset variables maintained by ConnectivityReceiver.
112879d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh        mWifiLock.release();
11297d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh        mNetworkType = -1;
11307d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh    }
11317d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh
11327d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh    private void updateWakeLocks() {
11337d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh        for (SipSessionGroupExt group : mSipGroups.values()) {
11347d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh            if (group.isOpenedToReceiveCalls()) {
11357d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh                // Also grab the WifiLock when we are disconnected, so the
11367d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh                // system will keep trying to reconnect. It will be released
11377d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh                // when the system eventually connects to something else.
11387d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh                if (mNetworkType == ConnectivityManager.TYPE_WIFI || mNetworkType == -1) {
11397d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh                    mWifiLock.acquire();
11407d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh                } else {
11417d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh                    mWifiLock.release();
11427d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh                }
11437d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh                return;
11447d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh            }
11457d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh        }
11467d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh        mWifiLock.release();
11477d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh        mMyWakeLock.reset(); // in case there's a leak
114879d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh    }
114979d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh
115079d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh    private synchronized void onConnectivityChanged(NetworkInfo info) {
115179d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh        // We only care about the default network, and getActiveNetworkInfo()
115279d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh        // is the only way to distinguish them. However, as broadcasts are
115379d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh        // delivered asynchronously, we might miss DISCONNECTED events from
115479d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh        // getActiveNetworkInfo(), which is critical to our SIP stack. To
115579d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh        // solve this, if it is a DISCONNECTED event to our current network,
115679d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh        // respect it. Otherwise get a new one from getActiveNetworkInfo().
11577d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh        if (info == null || info.isConnected() || info.getType() != mNetworkType) {
11589c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            ConnectivityManager cm = (ConnectivityManager)
11599c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                    mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
116079d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh            info = cm.getActiveNetworkInfo();
11619c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
11629c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
116379d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh        // Some devices limit SIP on Wi-Fi. In this case, if we are not on
116479d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh        // Wi-Fi, treat it as a DISCONNECTED event.
11657d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh        int networkType = (info != null && info.isConnected()) ? info.getType() : -1;
11667d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh        if (mSipOnWifiOnly && networkType != ConnectivityManager.TYPE_WIFI) {
11677d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh            networkType = -1;
11687d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh        }
11699c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
117079d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh        // Ignore the event if the current active network is not changed.
11717d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh        if (mNetworkType == networkType) {
117279d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh            return;
117379d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh        }
117479d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh        if (DEBUG) {
117579d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh            Log.d(TAG, "onConnectivityChanged(): " + mNetworkType +
117679d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh                    " -> " + networkType);
117779d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh        }
11789c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
117979d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh        try {
11807d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh            if (mNetworkType != -1) {
118179d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh                mLocalIp = null;
118279d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh                stopPortMappingMeasurement();
118379d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh                for (SipSessionGroupExt group : mSipGroups.values()) {
118479d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh                    group.onConnectivityChanged(false);
118579d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh                }
11869c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            }
118779d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh            mNetworkType = networkType;
11889c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
11897d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh            if (mNetworkType != -1) {
119079d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh                mLocalIp = determineLocalIp();
119179d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh                mKeepAliveInterval = -1;
119279d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh                mLastGoodKeepAliveInterval = DEFAULT_KEEPALIVE_INTERVAL;
119379d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh                for (SipSessionGroupExt group : mSipGroups.values()) {
119479d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh                    group.onConnectivityChanged(true);
11959c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                }
11969c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            }
11977d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh            updateWakeLocks();
119879d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh        } catch (SipException e) {
119979d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh            Log.e(TAG, "onConnectivityChanged()", e);
12009c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
12019c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    }
12029c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
1203257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan    private static Looper createLooper() {
1204257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan        HandlerThread thread = new HandlerThread("SipService.Executor");
1205257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan        thread.start();
1206257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan        return thread.getLooper();
1207257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan    }
1208257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan
1209257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan    // Executes immediate tasks in a single thread.
1210257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan    // Hold/release wake lock for running tasks
12114cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan    private class MyExecutor extends Handler implements Executor {
12129c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        MyExecutor() {
12139c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            super(createLooper());
12149c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
12159c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
12164cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan        @Override
12174cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan        public void execute(Runnable task) {
1218257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan            mMyWakeLock.acquire(task);
12199c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            Message.obtain(this, 0/* don't care */, task).sendToTarget();
12209c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
12219c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
12229c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        @Override
12239c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        public void handleMessage(Message msg) {
12249c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            if (msg.obj instanceof Runnable) {
1225257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan                executeInternal((Runnable) msg.obj);
12269c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            } else {
12279c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                Log.w(TAG, "can't handle msg: " + msg);
12289c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            }
12299c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
1230257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan
1231257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan        private void executeInternal(Runnable task) {
1232257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan            try {
1233257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan                task.run();
1234257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan            } catch (Throwable t) {
1235257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan                Log.e(TAG, "run task: " + task, t);
1236257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan            } finally {
1237257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan                mMyWakeLock.release(task);
1238257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan            }
1239257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan        }
1240257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan    }
12419c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan}
1242