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.PendingIntent;
209c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.content.BroadcastReceiver;
219c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.content.Context;
229c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.content.Intent;
239c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.content.IntentFilter;
249c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.net.ConnectivityManager;
259c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.net.NetworkInfo;
269c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.net.sip.ISipService;
279c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.net.sip.ISipSession;
289c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.net.sip.ISipSessionListener;
299c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.net.sip.SipErrorCode;
309c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.net.sip.SipManager;
319c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.net.sip.SipProfile;
329c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.net.sip.SipSession;
339c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.net.sip.SipSessionAdapter;
349c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.net.wifi.WifiManager;
359c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.os.Binder;
369c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.os.Bundle;
379c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.os.Handler;
389c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.os.HandlerThread;
399c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.os.Looper;
409c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.os.Message;
41257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyanimport android.os.PowerManager;
42a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyanimport android.os.Process;
439c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.os.RemoteException;
449c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.os.ServiceManager;
459c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.os.SystemClock;
469329db04f13480ccdff013dcc00cdb96f12a921cWink Savilleimport android.telephony.Rlog;
479c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
489c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport java.io.IOException;
499c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport java.net.DatagramSocket;
509c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport java.net.InetAddress;
519c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport java.net.UnknownHostException;
52a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyanimport java.util.ArrayList;
539c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport java.util.HashMap;
549c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport java.util.Map;
554cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyanimport java.util.concurrent.Executor;
569c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport javax.sip.SipException;
579c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
589c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan/**
599c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan * @hide
609c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan */
619c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanpublic final class SipService extends ISipService.Stub {
62acedadc1967457ac2f8981c67f884fd8c0ee853cHung-ying Tyan    static final String TAG = "SipService";
639329db04f13480ccdff013dcc00cdb96f12a921cWink Saville    static final boolean DBG = true;
649c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    private static final int EXPIRY_TIME = 3600;
659c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    private static final int SHORT_EXPIRY_TIME = 10;
669c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    private static final int MIN_EXPIRY_TIME = 60;
678a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan    private static final int DEFAULT_KEEPALIVE_INTERVAL = 10; // in seconds
68cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan    private static final int DEFAULT_MAX_KEEPALIVE_INTERVAL = 120; // in seconds
699c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
709c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    private Context mContext;
719c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    private String mLocalIp;
727d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh    private int mNetworkType = -1;
734cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan    private SipWakeupTimer mTimer;
749c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    private WifiManager.WifiLock mWifiLock;
7579d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh    private boolean mSipOnWifiOnly;
76987b505b1c190ff0e5a05d2cc20c9b08d2b99b18Hung-ying Tyan
779329db04f13480ccdff013dcc00cdb96f12a921cWink Saville    private SipKeepAliveProcessCallback mSipKeepAliveProcessCallback;
789c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
794cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan    private MyExecutor mExecutor = new MyExecutor();
809c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
819c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    // SipProfile URI --> group
829c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    private Map<String, SipSessionGroupExt> mSipGroups =
839c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            new HashMap<String, SipSessionGroupExt>();
849c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
859c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    // session ID --> session
869c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    private Map<String, ISipSession> mPendingSessions =
879c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            new HashMap<String, ISipSession>();
889c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
899c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    private ConnectivityReceiver mConnectivityReceiver;
90acedadc1967457ac2f8981c67f884fd8c0ee853cHung-ying Tyan    private SipWakeLock mMyWakeLock;
91469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang    private int mKeepAliveInterval;
92cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan    private int mLastGoodKeepAliveInterval = DEFAULT_KEEPALIVE_INTERVAL;
939c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
949c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    /**
959c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan     * Starts the SIP service. Do nothing if the SIP API is not supported on the
969c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan     * device.
979c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan     */
989c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    public static void start(Context context) {
999c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        if (SipManager.isApiSupported(context)) {
1009c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            ServiceManager.addService("sip", new SipService(context));
10122523a59d879cf47f1e9c202d001d569fad4f69eHung-ying Tyan            context.sendBroadcast(new Intent(SipManager.ACTION_SIP_SERVICE_UP));
1029329db04f13480ccdff013dcc00cdb96f12a921cWink Saville            if (DBG) slog("start:");
1039c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
1049c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    }
1059c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
1069c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    private SipService(Context context) {
1079329db04f13480ccdff013dcc00cdb96f12a921cWink Saville        if (DBG) log("SipService: started!");
1089c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        mContext = context;
1099c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        mConnectivityReceiver = new ConnectivityReceiver();
11079d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh
11179d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh        mWifiLock = ((WifiManager)
11279d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh                context.getSystemService(Context.WIFI_SERVICE))
11379d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh                .createWifiLock(WifiManager.WIFI_MODE_FULL, TAG);
11479d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh        mWifiLock.setReferenceCounted(false);
11579d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh        mSipOnWifiOnly = SipManager.isSipWifiOnly(context);
11679d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh
117acedadc1967457ac2f8981c67f884fd8c0ee853cHung-ying Tyan        mMyWakeLock = new SipWakeLock((PowerManager)
118257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan                context.getSystemService(Context.POWER_SERVICE));
1199c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
1204cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan        mTimer = new SipWakeupTimer(context, mExecutor);
121dc7545495e1ef8bad32cd78775f4dc072015eea0Hung-ying Tyan    }
122dc7545495e1ef8bad32cd78775f4dc072015eea0Hung-ying Tyan
1239329db04f13480ccdff013dcc00cdb96f12a921cWink Saville    @Override
1249c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    public synchronized SipProfile[] getListOfProfiles() {
1258127b35b75c13f853dc8eb2fed8bba4bf99e3eedHung-ying Tyan        mContext.enforceCallingOrSelfPermission(
1268127b35b75c13f853dc8eb2fed8bba4bf99e3eedHung-ying Tyan                android.Manifest.permission.USE_SIP, null);
127a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan        boolean isCallerRadio = isCallerRadio();
128a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan        ArrayList<SipProfile> profiles = new ArrayList<SipProfile>();
1299c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        for (SipSessionGroupExt group : mSipGroups.values()) {
130a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan            if (isCallerRadio || isCallerCreator(group)) {
131a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan                profiles.add(group.getLocalProfile());
132a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan            }
1339c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
134a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan        return profiles.toArray(new SipProfile[profiles.size()]);
1359c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    }
1369c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
1379329db04f13480ccdff013dcc00cdb96f12a921cWink Saville    @Override
138dc7545495e1ef8bad32cd78775f4dc072015eea0Hung-ying Tyan    public synchronized void open(SipProfile localProfile) {
1398127b35b75c13f853dc8eb2fed8bba4bf99e3eedHung-ying Tyan        mContext.enforceCallingOrSelfPermission(
1408127b35b75c13f853dc8eb2fed8bba4bf99e3eedHung-ying Tyan                android.Manifest.permission.USE_SIP, null);
1419c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        localProfile.setCallingUid(Binder.getCallingUid());
1429c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        try {
1439c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            createGroup(localProfile);
1449c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        } catch (SipException e) {
1459329db04f13480ccdff013dcc00cdb96f12a921cWink Saville            loge("openToMakeCalls()", e);
1469c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            // TODO: how to send the exception back
1479c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
1489c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    }
1499c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
1509329db04f13480ccdff013dcc00cdb96f12a921cWink Saville    @Override
1519c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    public synchronized void open3(SipProfile localProfile,
152845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan            PendingIntent incomingCallPendingIntent,
153845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan            ISipSessionListener listener) {
1548127b35b75c13f853dc8eb2fed8bba4bf99e3eedHung-ying Tyan        mContext.enforceCallingOrSelfPermission(
1558127b35b75c13f853dc8eb2fed8bba4bf99e3eedHung-ying Tyan                android.Manifest.permission.USE_SIP, null);
1569c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        localProfile.setCallingUid(Binder.getCallingUid());
157845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan        if (incomingCallPendingIntent == null) {
1589329db04f13480ccdff013dcc00cdb96f12a921cWink Saville            if (DBG) log("open3: incomingCallPendingIntent cannot be null; "
159845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan                    + "the profile is not opened");
160a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan            return;
1619c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
1629329db04f13480ccdff013dcc00cdb96f12a921cWink Saville        if (DBG) log("open3: " + localProfile.getUriString() + ": "
163845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan                + incomingCallPendingIntent + ": " + listener);
1649c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        try {
1659c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            SipSessionGroupExt group = createGroup(localProfile,
166845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan                    incomingCallPendingIntent, listener);
1679c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            if (localProfile.getAutoRegistration()) {
1689c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                group.openToReceiveCalls();
1697d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh                updateWakeLocks();
1709c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            }
1719c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        } catch (SipException e) {
1729329db04f13480ccdff013dcc00cdb96f12a921cWink Saville            loge("open3:", e);
1739c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            // TODO: how to send the exception back
1749c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
1759c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    }
1769c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
177a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan    private boolean isCallerCreator(SipSessionGroupExt group) {
178a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan        SipProfile profile = group.getLocalProfile();
179a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan        return (profile.getCallingUid() == Binder.getCallingUid());
180a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan    }
181a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan
182a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan    private boolean isCallerCreatorOrRadio(SipSessionGroupExt group) {
183a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan        return (isCallerRadio() || isCallerCreator(group));
184a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan    }
185a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan
186a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan    private boolean isCallerRadio() {
187a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan        return (Binder.getCallingUid() == Process.PHONE_UID);
188a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan    }
189a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan
1909329db04f13480ccdff013dcc00cdb96f12a921cWink Saville    @Override
1919c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    public synchronized void close(String localProfileUri) {
1928127b35b75c13f853dc8eb2fed8bba4bf99e3eedHung-ying Tyan        mContext.enforceCallingOrSelfPermission(
1938127b35b75c13f853dc8eb2fed8bba4bf99e3eedHung-ying Tyan                android.Manifest.permission.USE_SIP, null);
194a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan        SipSessionGroupExt group = mSipGroups.get(localProfileUri);
195a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan        if (group == null) return;
196a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan        if (!isCallerCreatorOrRadio(group)) {
1979329db04f13480ccdff013dcc00cdb96f12a921cWink Saville            if (DBG) log("only creator or radio can close this profile");
198a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan            return;
1999c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
200a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan
201a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan        group = mSipGroups.remove(localProfileUri);
202a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan        notifyProfileRemoved(group.getLocalProfile());
203a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan        group.close();
204257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan
2057d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh        updateWakeLocks();
2069c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    }
2079c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
2089329db04f13480ccdff013dcc00cdb96f12a921cWink Saville    @Override
2099c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    public synchronized boolean isOpened(String localProfileUri) {
2108127b35b75c13f853dc8eb2fed8bba4bf99e3eedHung-ying Tyan        mContext.enforceCallingOrSelfPermission(
2118127b35b75c13f853dc8eb2fed8bba4bf99e3eedHung-ying Tyan                android.Manifest.permission.USE_SIP, null);
2129c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        SipSessionGroupExt group = mSipGroups.get(localProfileUri);
213a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan        if (group == null) return false;
214a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan        if (isCallerCreatorOrRadio(group)) {
215617479363dcafe01bfa1fa025e1d9d122864a0ceHung-ying Tyan            return true;
216a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan        } else {
2179329db04f13480ccdff013dcc00cdb96f12a921cWink Saville            if (DBG) log("only creator or radio can query on the profile");
218a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan            return false;
219a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan        }
2209c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    }
2219c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
2229329db04f13480ccdff013dcc00cdb96f12a921cWink Saville    @Override
2239c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    public synchronized boolean isRegistered(String localProfileUri) {
2248127b35b75c13f853dc8eb2fed8bba4bf99e3eedHung-ying Tyan        mContext.enforceCallingOrSelfPermission(
2258127b35b75c13f853dc8eb2fed8bba4bf99e3eedHung-ying Tyan                android.Manifest.permission.USE_SIP, null);
2269c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        SipSessionGroupExt group = mSipGroups.get(localProfileUri);
227a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan        if (group == null) return false;
228a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan        if (isCallerCreatorOrRadio(group)) {
229a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan            return group.isRegistered();
230a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan        } else {
2319329db04f13480ccdff013dcc00cdb96f12a921cWink Saville            if (DBG) log("only creator or radio can query on the profile");
232a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan            return false;
233a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan        }
2349c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    }
2359c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
2369329db04f13480ccdff013dcc00cdb96f12a921cWink Saville    @Override
2379c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    public synchronized void setRegistrationListener(String localProfileUri,
2389c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            ISipSessionListener listener) {
2398127b35b75c13f853dc8eb2fed8bba4bf99e3eedHung-ying Tyan        mContext.enforceCallingOrSelfPermission(
2408127b35b75c13f853dc8eb2fed8bba4bf99e3eedHung-ying Tyan                android.Manifest.permission.USE_SIP, null);
2419c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        SipSessionGroupExt group = mSipGroups.get(localProfileUri);
242a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan        if (group == null) return;
243a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan        if (isCallerCreator(group)) {
244a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan            group.setListener(listener);
245a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan        } else {
2469329db04f13480ccdff013dcc00cdb96f12a921cWink Saville            if (DBG) log("only creator can set listener on the profile");
247a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan        }
2489c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    }
2499c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
2509329db04f13480ccdff013dcc00cdb96f12a921cWink Saville    @Override
2519c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    public synchronized ISipSession createSession(SipProfile localProfile,
2529c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            ISipSessionListener listener) {
2539329db04f13480ccdff013dcc00cdb96f12a921cWink Saville        if (DBG) log("createSession: profile" + localProfile);
2548127b35b75c13f853dc8eb2fed8bba4bf99e3eedHung-ying Tyan        mContext.enforceCallingOrSelfPermission(
2558127b35b75c13f853dc8eb2fed8bba4bf99e3eedHung-ying Tyan                android.Manifest.permission.USE_SIP, null);
2569c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        localProfile.setCallingUid(Binder.getCallingUid());
2579329db04f13480ccdff013dcc00cdb96f12a921cWink Saville        if (mNetworkType == -1) {
2589329db04f13480ccdff013dcc00cdb96f12a921cWink Saville            if (DBG) log("createSession: mNetworkType==-1 ret=null");
2599329db04f13480ccdff013dcc00cdb96f12a921cWink Saville            return null;
2609329db04f13480ccdff013dcc00cdb96f12a921cWink Saville        }
2619c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        try {
2629c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            SipSessionGroupExt group = createGroup(localProfile);
2639c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            return group.createSession(listener);
2649c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        } catch (SipException e) {
2659329db04f13480ccdff013dcc00cdb96f12a921cWink Saville            if (DBG) loge("createSession;", e);
2669c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            return null;
2679c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
2689c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    }
2699c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
2709329db04f13480ccdff013dcc00cdb96f12a921cWink Saville    @Override
2719c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    public synchronized ISipSession getPendingSession(String callId) {
2728127b35b75c13f853dc8eb2fed8bba4bf99e3eedHung-ying Tyan        mContext.enforceCallingOrSelfPermission(
2738127b35b75c13f853dc8eb2fed8bba4bf99e3eedHung-ying Tyan                android.Manifest.permission.USE_SIP, null);
2749c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        if (callId == null) return null;
2759c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        return mPendingSessions.get(callId);
2769c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    }
2779c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
2789c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    private String determineLocalIp() {
2799c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        try {
2809c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            DatagramSocket s = new DatagramSocket();
2819c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            s.connect(InetAddress.getByName("192.168.1.1"), 80);
2829c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            return s.getLocalAddress().getHostAddress();
2839c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        } catch (IOException e) {
2849329db04f13480ccdff013dcc00cdb96f12a921cWink Saville            if (DBG) loge("determineLocalIp()", e);
2859c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            // dont do anything; there should be a connectivity change going
2869c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            return null;
2879c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
2889c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    }
2899c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
2909c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    private SipSessionGroupExt createGroup(SipProfile localProfile)
2919c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            throws SipException {
2929c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        String key = localProfile.getUriString();
2939c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        SipSessionGroupExt group = mSipGroups.get(key);
2949c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        if (group == null) {
2959c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            group = new SipSessionGroupExt(localProfile, null, null);
2969c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            mSipGroups.put(key, group);
2979c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            notifyProfileAdded(localProfile);
298a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan        } else if (!isCallerCreator(group)) {
299a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan            throw new SipException("only creator can access the profile");
3009c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
3019c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        return group;
3029c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    }
3039c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
3049c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    private SipSessionGroupExt createGroup(SipProfile localProfile,
305845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan            PendingIntent incomingCallPendingIntent,
306845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan            ISipSessionListener listener) throws SipException {
3079c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        String key = localProfile.getUriString();
3089c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        SipSessionGroupExt group = mSipGroups.get(key);
3099c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        if (group != null) {
310a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan            if (!isCallerCreator(group)) {
311a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan                throw new SipException("only creator can access the profile");
312a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan            }
313845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan            group.setIncomingCallPendingIntent(incomingCallPendingIntent);
3149c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            group.setListener(listener);
3159c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        } else {
3169c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            group = new SipSessionGroupExt(localProfile,
317845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan                    incomingCallPendingIntent, listener);
3189c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            mSipGroups.put(key, group);
3199c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            notifyProfileAdded(localProfile);
3209c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
3219c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        return group;
3229c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    }
3239c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
3249c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    private void notifyProfileAdded(SipProfile localProfile) {
3259329db04f13480ccdff013dcc00cdb96f12a921cWink Saville        if (DBG) log("notify: profile added: " + localProfile);
3269c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        Intent intent = new Intent(SipManager.ACTION_SIP_ADD_PHONE);
3279c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        intent.putExtra(SipManager.EXTRA_LOCAL_URI, localProfile.getUriString());
3289c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        mContext.sendBroadcast(intent);
3297d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh        if (mSipGroups.size() == 1) {
3307d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh            registerReceivers();
3317d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh        }
3329c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    }
3339c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
3349c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    private void notifyProfileRemoved(SipProfile localProfile) {
3359329db04f13480ccdff013dcc00cdb96f12a921cWink Saville        if (DBG) log("notify: profile removed: " + localProfile);
3369c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        Intent intent = new Intent(SipManager.ACTION_SIP_REMOVE_PHONE);
3379c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        intent.putExtra(SipManager.EXTRA_LOCAL_URI, localProfile.getUriString());
3389c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        mContext.sendBroadcast(intent);
3397d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh        if (mSipGroups.size() == 0) {
3407d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh            unregisterReceivers();
3419c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
3429c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    }
3439c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
344469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang    private void stopPortMappingMeasurement() {
3459329db04f13480ccdff013dcc00cdb96f12a921cWink Saville        if (mSipKeepAliveProcessCallback != null) {
3469329db04f13480ccdff013dcc00cdb96f12a921cWink Saville            mSipKeepAliveProcessCallback.stop();
3479329db04f13480ccdff013dcc00cdb96f12a921cWink Saville            mSipKeepAliveProcessCallback = null;
348469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang        }
349469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang    }
350469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang
3518a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan    private void startPortMappingLifetimeMeasurement(
3528a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan            SipProfile localProfile) {
353cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan        startPortMappingLifetimeMeasurement(localProfile,
354cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan                DEFAULT_MAX_KEEPALIVE_INTERVAL);
35544ccfb03bb349a90546ddb3dc0063cbf4aaddaf1Hung-ying Tyan    }
35644ccfb03bb349a90546ddb3dc0063cbf4aaddaf1Hung-ying Tyan
35744ccfb03bb349a90546ddb3dc0063cbf4aaddaf1Hung-ying Tyan    private void startPortMappingLifetimeMeasurement(
35844ccfb03bb349a90546ddb3dc0063cbf4aaddaf1Hung-ying Tyan            SipProfile localProfile, int maxInterval) {
3599329db04f13480ccdff013dcc00cdb96f12a921cWink Saville        if ((mSipKeepAliveProcessCallback == null)
3608a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                && (mKeepAliveInterval == -1)
3618a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                && isBehindNAT(mLocalIp)) {
3629329db04f13480ccdff013dcc00cdb96f12a921cWink Saville            if (DBG) log("startPortMappingLifetimeMeasurement: profile="
3638a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                    + localProfile.getUriString());
3648a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan
365cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan            int minInterval = mLastGoodKeepAliveInterval;
366cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan            if (minInterval >= maxInterval) {
367cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan                // If mLastGoodKeepAliveInterval also does not work, reset it
368cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan                // to the default min
369cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan                minInterval = mLastGoodKeepAliveInterval
370cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan                        = DEFAULT_KEEPALIVE_INTERVAL;
3719329db04f13480ccdff013dcc00cdb96f12a921cWink Saville                log("  reset min interval to " + minInterval);
372cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan            }
3739329db04f13480ccdff013dcc00cdb96f12a921cWink Saville            mSipKeepAliveProcessCallback = new SipKeepAliveProcessCallback(
374cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan                    localProfile, minInterval, maxInterval);
3759329db04f13480ccdff013dcc00cdb96f12a921cWink Saville            mSipKeepAliveProcessCallback.start();
3768a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan        }
377469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang    }
378469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang
37944ccfb03bb349a90546ddb3dc0063cbf4aaddaf1Hung-ying Tyan    private void restartPortMappingLifetimeMeasurement(
38044ccfb03bb349a90546ddb3dc0063cbf4aaddaf1Hung-ying Tyan            SipProfile localProfile, int maxInterval) {
38144ccfb03bb349a90546ddb3dc0063cbf4aaddaf1Hung-ying Tyan        stopPortMappingMeasurement();
38244ccfb03bb349a90546ddb3dc0063cbf4aaddaf1Hung-ying Tyan        mKeepAliveInterval = -1;
38344ccfb03bb349a90546ddb3dc0063cbf4aaddaf1Hung-ying Tyan        startPortMappingLifetimeMeasurement(localProfile, maxInterval);
38444ccfb03bb349a90546ddb3dc0063cbf4aaddaf1Hung-ying Tyan    }
38544ccfb03bb349a90546ddb3dc0063cbf4aaddaf1Hung-ying Tyan
3869c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    private synchronized void addPendingSession(ISipSession session) {
3879c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        try {
3883f4d44657ccad3ed02ed0e1354387b14b07dc011Hung-ying Tyan            cleanUpPendingSessions();
3899c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            mPendingSessions.put(session.getCallId(), session);
3909329db04f13480ccdff013dcc00cdb96f12a921cWink Saville            if (DBG) log("#pending sess=" + mPendingSessions.size());
3919c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        } catch (RemoteException e) {
3929c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            // should not happen with a local call
3939329db04f13480ccdff013dcc00cdb96f12a921cWink Saville            loge("addPendingSession()", e);
3949c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
3959c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    }
3969c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
3973f4d44657ccad3ed02ed0e1354387b14b07dc011Hung-ying Tyan    private void cleanUpPendingSessions() throws RemoteException {
3983f4d44657ccad3ed02ed0e1354387b14b07dc011Hung-ying Tyan        Map.Entry<String, ISipSession>[] entries =
3993f4d44657ccad3ed02ed0e1354387b14b07dc011Hung-ying Tyan                mPendingSessions.entrySet().toArray(
4003f4d44657ccad3ed02ed0e1354387b14b07dc011Hung-ying Tyan                new Map.Entry[mPendingSessions.size()]);
4013f4d44657ccad3ed02ed0e1354387b14b07dc011Hung-ying Tyan        for (Map.Entry<String, ISipSession> entry : entries) {
4023f4d44657ccad3ed02ed0e1354387b14b07dc011Hung-ying Tyan            if (entry.getValue().getState() != SipSession.State.INCOMING_CALL) {
4033f4d44657ccad3ed02ed0e1354387b14b07dc011Hung-ying Tyan                mPendingSessions.remove(entry.getKey());
4043f4d44657ccad3ed02ed0e1354387b14b07dc011Hung-ying Tyan            }
4053f4d44657ccad3ed02ed0e1354387b14b07dc011Hung-ying Tyan        }
4063f4d44657ccad3ed02ed0e1354387b14b07dc011Hung-ying Tyan    }
4073f4d44657ccad3ed02ed0e1354387b14b07dc011Hung-ying Tyan
408ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan    private synchronized boolean callingSelf(SipSessionGroupExt ringingGroup,
409ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan            SipSessionGroup.SipSessionImpl ringingSession) {
410ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan        String callId = ringingSession.getCallId();
411ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan        for (SipSessionGroupExt group : mSipGroups.values()) {
412ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan            if ((group != ringingGroup) && group.containsSession(callId)) {
4139329db04f13480ccdff013dcc00cdb96f12a921cWink Saville                if (DBG) log("call self: "
414ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan                        + ringingSession.getLocalProfile().getUriString()
415ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan                        + " -> " + group.getLocalProfile().getUriString());
416ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan                return true;
417ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan            }
418ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan        }
419ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan        return false;
420ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan    }
421ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan
4228a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan    private synchronized void onKeepAliveIntervalChanged() {
4238a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan        for (SipSessionGroupExt group : mSipGroups.values()) {
4248a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan            group.onKeepAliveIntervalChanged();
4258a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan        }
4268a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan    }
4278a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan
4288a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan    private int getKeepAliveInterval() {
4298a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan        return (mKeepAliveInterval < 0)
430cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan                ? mLastGoodKeepAliveInterval
4318a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                : mKeepAliveInterval;
4328a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan    }
4338a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan
4348a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan    private boolean isBehindNAT(String address) {
4358a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan        try {
4369329db04f13480ccdff013dcc00cdb96f12a921cWink Saville            // TODO: How is isBehindNAT used and why these constanst address:
4379329db04f13480ccdff013dcc00cdb96f12a921cWink Saville            //       10.x.x.x | 192.168.x.x | 172.16.x.x .. 172.19.x.x
4388a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan            byte[] d = InetAddress.getByName(address).getAddress();
4398a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan            if ((d[0] == 10) ||
4409329db04f13480ccdff013dcc00cdb96f12a921cWink Saville                    (((0x000000FF & d[0]) == 172) &&
4419329db04f13480ccdff013dcc00cdb96f12a921cWink Saville                    ((0x000000F0 & d[1]) == 16)) ||
4429329db04f13480ccdff013dcc00cdb96f12a921cWink Saville                    (((0x000000FF & d[0]) == 192) &&
4439329db04f13480ccdff013dcc00cdb96f12a921cWink Saville                    ((0x000000FF & d[1]) == 168))) {
4448a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                return true;
4458a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan            }
4468a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan        } catch (UnknownHostException e) {
4479329db04f13480ccdff013dcc00cdb96f12a921cWink Saville            loge("isBehindAT()" + address, e);
4488a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan        }
4498a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan        return false;
4508a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan    }
451ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan
4529c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    private class SipSessionGroupExt extends SipSessionAdapter {
4539329db04f13480ccdff013dcc00cdb96f12a921cWink Saville        private static final String SSGE_TAG = "SipSessionGroupExt";
4549329db04f13480ccdff013dcc00cdb96f12a921cWink Saville        private static final boolean SSGE_DBG = true;
4559c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        private SipSessionGroup mSipGroup;
456845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan        private PendingIntent mIncomingCallPendingIntent;
457617479363dcafe01bfa1fa025e1d9d122864a0ceHung-ying Tyan        private boolean mOpenedToReceiveCalls;
4589c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
4599329db04f13480ccdff013dcc00cdb96f12a921cWink Saville        private SipAutoReg mAutoRegistration =
4609329db04f13480ccdff013dcc00cdb96f12a921cWink Saville                new SipAutoReg();
4619c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
4629c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        public SipSessionGroupExt(SipProfile localProfile,
463845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan                PendingIntent incomingCallPendingIntent,
4649c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                ISipSessionListener listener) throws SipException {
4659329db04f13480ccdff013dcc00cdb96f12a921cWink Saville            if (SSGE_DBG) log("SipSessionGroupExt: profile=" + localProfile);
4661b5111f16c1401437d577dfd547af10aa691d44fChia-chi Yeh            mSipGroup = new SipSessionGroup(duplicate(localProfile),
4671b5111f16c1401437d577dfd547af10aa691d44fChia-chi Yeh                    localProfile.getPassword(), mTimer, mMyWakeLock);
468845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan            mIncomingCallPendingIntent = incomingCallPendingIntent;
4699c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            mAutoRegistration.setListener(listener);
4709c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
4719c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
4729c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        public SipProfile getLocalProfile() {
4739c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            return mSipGroup.getLocalProfile();
4749c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
4759c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
476ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan        public boolean containsSession(String callId) {
477ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan            return mSipGroup.containsSession(callId);
478ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan        }
479ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan
4808a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan        public void onKeepAliveIntervalChanged() {
4818a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan            mAutoRegistration.onKeepAliveIntervalChanged();
4828a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan        }
4838a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan
4848a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan        // TODO: remove this method once SipWakeupTimer can better handle variety
4858a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan        // of timeout values
4868a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan        void setWakeupTimer(SipWakeupTimer timer) {
4878a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan            mSipGroup.setWakeupTimer(timer);
4888a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan        }
4898a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan
4909c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        private SipProfile duplicate(SipProfile p) {
4919c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            try {
4929c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                return new SipProfile.Builder(p).setPassword("*").build();
4939c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            } catch (Exception e) {
4949329db04f13480ccdff013dcc00cdb96f12a921cWink Saville                loge("duplicate()", e);
4959c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                throw new RuntimeException("duplicate profile", e);
4969c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            }
4979c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
4989c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
4999c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        public void setListener(ISipSessionListener listener) {
5009c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            mAutoRegistration.setListener(listener);
5019c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
5029c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
503845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan        public void setIncomingCallPendingIntent(PendingIntent pIntent) {
504845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan            mIncomingCallPendingIntent = pIntent;
5059c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
5069c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
5079c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        public void openToReceiveCalls() throws SipException {
508617479363dcafe01bfa1fa025e1d9d122864a0ceHung-ying Tyan            mOpenedToReceiveCalls = true;
5097d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh            if (mNetworkType != -1) {
5109c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                mSipGroup.openToReceiveCalls(this);
5119c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                mAutoRegistration.start(mSipGroup);
5129c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            }
5139329db04f13480ccdff013dcc00cdb96f12a921cWink Saville            if (SSGE_DBG) log("openToReceiveCalls: " + getUri() + ": "
514845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan                    + mIncomingCallPendingIntent);
5159c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
5169c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
5179c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        public void onConnectivityChanged(boolean connected)
5189c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                throws SipException {
5199329db04f13480ccdff013dcc00cdb96f12a921cWink Saville            if (SSGE_DBG) {
5209329db04f13480ccdff013dcc00cdb96f12a921cWink Saville                log("onConnectivityChanged: connected=" + connected + " uri="
5219329db04f13480ccdff013dcc00cdb96f12a921cWink Saville                    + getUri() + ": " + mIncomingCallPendingIntent);
5229329db04f13480ccdff013dcc00cdb96f12a921cWink Saville            }
5239c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            mSipGroup.onConnectivityChanged();
5249c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            if (connected) {
5251b5111f16c1401437d577dfd547af10aa691d44fChia-chi Yeh                mSipGroup.reset();
526617479363dcafe01bfa1fa025e1d9d122864a0ceHung-ying Tyan                if (mOpenedToReceiveCalls) openToReceiveCalls();
5279c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            } else {
5289c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                mSipGroup.close();
5299c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                mAutoRegistration.stop();
5309c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            }
5319c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
5329c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
5339c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        public void close() {
534617479363dcafe01bfa1fa025e1d9d122864a0ceHung-ying Tyan            mOpenedToReceiveCalls = false;
5359c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            mSipGroup.close();
5369c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            mAutoRegistration.stop();
5379329db04f13480ccdff013dcc00cdb96f12a921cWink Saville            if (SSGE_DBG) log("close: " + getUri() + ": " + mIncomingCallPendingIntent);
5389c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
5399c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
5409c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        public ISipSession createSession(ISipSessionListener listener) {
5419329db04f13480ccdff013dcc00cdb96f12a921cWink Saville            if (SSGE_DBG) log("createSession");
5429c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            return mSipGroup.createSession(listener);
5439c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
5449c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
5459c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        @Override
546845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan        public void onRinging(ISipSession s, SipProfile caller,
5479c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                String sessionDescription) {
548845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan            SipSessionGroup.SipSessionImpl session =
549845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan                    (SipSessionGroup.SipSessionImpl) s;
5509c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            synchronized (SipService.this) {
5519c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                try {
552ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan                    if (!isRegistered() || callingSelf(this, session)) {
5539329db04f13480ccdff013dcc00cdb96f12a921cWink Saville                        if (SSGE_DBG) log("onRinging: end notReg or self");
5549c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                        session.endCall();
5559c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                        return;
5569c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                    }
5579c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
5589c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                    // send out incoming call broadcast
5599c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                    addPendingSession(session);
5609c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                    Intent intent = SipManager.createIncomingCallBroadcast(
561845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan                            session.getCallId(), sessionDescription);
5629329db04f13480ccdff013dcc00cdb96f12a921cWink Saville                    if (SSGE_DBG) log("onRinging: uri=" + getUri() + ": "
5639c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                            + caller.getUri() + ": " + session.getCallId()
564845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan                            + " " + mIncomingCallPendingIntent);
565845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan                    mIncomingCallPendingIntent.send(mContext,
566845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan                            SipManager.INCOMING_CALL_RESULT_CODE, intent);
567845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan                } catch (PendingIntent.CanceledException e) {
5689329db04f13480ccdff013dcc00cdb96f12a921cWink Saville                    loge("onRinging: pendingIntent is canceled, drop incoming call", e);
569845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan                    session.endCall();
5709c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                }
5719c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            }
5729c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
5739c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
5749c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        @Override
5759c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        public void onError(ISipSession session, int errorCode,
5769c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                String message) {
5779329db04f13480ccdff013dcc00cdb96f12a921cWink Saville            if (SSGE_DBG) log("onError: errorCode=" + errorCode + " desc="
5789c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                    + SipErrorCode.toString(errorCode) + ": " + message);
5799c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
5809c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
581617479363dcafe01bfa1fa025e1d9d122864a0ceHung-ying Tyan        public boolean isOpenedToReceiveCalls() {
582617479363dcafe01bfa1fa025e1d9d122864a0ceHung-ying Tyan            return mOpenedToReceiveCalls;
5839c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
5849c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
5859c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        public boolean isRegistered() {
5869c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            return mAutoRegistration.isRegistered();
5879c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
5889c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
5899c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        private String getUri() {
5909c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            return mSipGroup.getLocalProfileUri();
5919c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
5929329db04f13480ccdff013dcc00cdb96f12a921cWink Saville
5939329db04f13480ccdff013dcc00cdb96f12a921cWink Saville        private void log(String s) {
5949329db04f13480ccdff013dcc00cdb96f12a921cWink Saville            Rlog.d(SSGE_TAG, s);
5959329db04f13480ccdff013dcc00cdb96f12a921cWink Saville        }
5969329db04f13480ccdff013dcc00cdb96f12a921cWink Saville
5979329db04f13480ccdff013dcc00cdb96f12a921cWink Saville        private void loge(String s, Throwable t) {
5989329db04f13480ccdff013dcc00cdb96f12a921cWink Saville            Rlog.e(SSGE_TAG, s, t);
5999329db04f13480ccdff013dcc00cdb96f12a921cWink Saville        }
6009329db04f13480ccdff013dcc00cdb96f12a921cWink Saville
6019c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    }
6029c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
6039329db04f13480ccdff013dcc00cdb96f12a921cWink Saville    private class SipKeepAliveProcessCallback implements Runnable,
6048a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan            SipSessionGroup.KeepAliveProcessCallback {
6059329db04f13480ccdff013dcc00cdb96f12a921cWink Saville        private static final String SKAI_TAG = "SipKeepAliveProcessCallback";
6069329db04f13480ccdff013dcc00cdb96f12a921cWink Saville        private static final boolean SKAI_DBG = true;
6077d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan        private static final int MIN_INTERVAL = 5; // in seconds
6088a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan        private static final int PASS_THRESHOLD = 10;
6097d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan        private static final int NAT_MEASUREMENT_RETRY_INTERVAL = 120; // in seconds
61037f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh        private SipProfile mLocalProfile;
611469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang        private SipSessionGroupExt mGroup;
612469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang        private SipSessionGroup.SipSessionImpl mSession;
613cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan        private int mMinInterval;
61444ccfb03bb349a90546ddb3dc0063cbf4aaddaf1Hung-ying Tyan        private int mMaxInterval;
61544ccfb03bb349a90546ddb3dc0063cbf4aaddaf1Hung-ying Tyan        private int mInterval;
61637f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh        private int mPassCount;
61744ccfb03bb349a90546ddb3dc0063cbf4aaddaf1Hung-ying Tyan
6189329db04f13480ccdff013dcc00cdb96f12a921cWink Saville        public SipKeepAliveProcessCallback(SipProfile localProfile,
619cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan                int minInterval, int maxInterval) {
620cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan            mMaxInterval = maxInterval;
621cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan            mMinInterval = minInterval;
62237f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh            mLocalProfile = localProfile;
623469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang        }
624469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang
625469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang        public void start() {
6268a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan            synchronized (SipService.this) {
62737f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh                if (mSession != null) {
62837f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh                    return;
6297d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan                }
63037f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh
63137f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh                mInterval = (mMaxInterval + mMinInterval) / 2;
63237f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh                mPassCount = 0;
63337f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh
63437f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh                // Don't start measurement if the interval is too small
63537f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh                if (mInterval < DEFAULT_KEEPALIVE_INTERVAL || checkTermination()) {
6369329db04f13480ccdff013dcc00cdb96f12a921cWink Saville                    if (SKAI_DBG) log("start: measurement aborted; interval=[" +
63737f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh                            mMinInterval + "," + mMaxInterval + "]");
63837f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh                    return;
63937f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh                }
64037f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh
6418a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                try {
6429329db04f13480ccdff013dcc00cdb96f12a921cWink Saville                    if (SKAI_DBG) log("start: interval=" + mInterval);
64337f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh
64437f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh                    mGroup = new SipSessionGroupExt(mLocalProfile, null, null);
64537f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh                    // TODO: remove this line once SipWakeupTimer can better handle
64637f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh                    // variety of timeout values
64737f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh                    mGroup.setWakeupTimer(new SipWakeupTimer(mContext, mExecutor));
64837f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh
64937f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh                    mSession = (SipSessionGroup.SipSessionImpl)
65037f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh                            mGroup.createSession(null);
6518a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                    mSession.startKeepAliveProcess(mInterval, this);
65237f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh                } catch (Throwable t) {
65337f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh                    onError(SipErrorCode.CLIENT_ERROR, t.toString());
6548a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                }
6558a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan            }
656469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang        }
657469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang
658469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang        public void stop() {
6598a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan            synchronized (SipService.this) {
6607d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan                if (mSession != null) {
6617d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan                    mSession.stopKeepAliveProcess();
6627d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan                    mSession = null;
6637d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan                }
66437f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh                if (mGroup != null) {
66537f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh                    mGroup.close();
66637f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh                    mGroup = null;
66737f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh                }
6687d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan                mTimer.cancel(this);
6699329db04f13480ccdff013dcc00cdb96f12a921cWink Saville                if (SKAI_DBG) log("stop");
670469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang            }
671469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang        }
672469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang
6738a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan        private void restart() {
674469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang            synchronized (SipService.this) {
6757d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan                // Return immediately if the measurement process is stopped
6767d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan                if (mSession == null) return;
6777d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan
6789329db04f13480ccdff013dcc00cdb96f12a921cWink Saville                if (SKAI_DBG) log("restart: interval=" + mInterval);
679469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang                try {
6808a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                    mSession.stopKeepAliveProcess();
6817d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan                    mPassCount = 0;
6828a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                    mSession.startKeepAliveProcess(mInterval, this);
6838a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                } catch (SipException e) {
6849329db04f13480ccdff013dcc00cdb96f12a921cWink Saville                    loge("restart", e);
685469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang                }
686469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang            }
687469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang        }
688469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang
689cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan        private boolean checkTermination() {
690cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan            return ((mMaxInterval - mMinInterval) < MIN_INTERVAL);
691cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan        }
692cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan
6938a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan        // SipSessionGroup.KeepAliveProcessCallback
6948a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan        @Override
6958a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan        public void onResponse(boolean portChanged) {
6969c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            synchronized (SipService.this) {
6978a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                if (!portChanged) {
69844ccfb03bb349a90546ddb3dc0063cbf4aaddaf1Hung-ying Tyan                    if (++mPassCount != PASS_THRESHOLD) return;
6998a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                    // update the interval, since the current interval is good to
7008a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                    // keep the port mapping.
701cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan                    if (mKeepAliveInterval > 0) {
702cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan                        mLastGoodKeepAliveInterval = mKeepAliveInterval;
703cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan                    }
7048a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                    mKeepAliveInterval = mMinInterval = mInterval;
7059329db04f13480ccdff013dcc00cdb96f12a921cWink Saville                    if (SKAI_DBG) {
7069329db04f13480ccdff013dcc00cdb96f12a921cWink Saville                        log("onResponse: portChanged=" + portChanged + " mKeepAliveInterval="
7078a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                                + mKeepAliveInterval);
708257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan                    }
7098a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                    onKeepAliveIntervalChanged();
7108a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                } else {
7118a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                    // Since the rport is changed, shorten the interval.
7128a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                    mMaxInterval = mInterval;
7138a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                }
714cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan                if (checkTermination()) {
7158a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                    // update mKeepAliveInterval and stop measurement.
7168a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                    stop();
717cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan                    // If all the measurements failed, we still set it to
718cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan                    // mMinInterval; If mMinInterval still doesn't work, a new
719cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan                    // measurement with min interval=DEFAULT_KEEPALIVE_INTERVAL
720cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan                    // will be conducted.
7218a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                    mKeepAliveInterval = mMinInterval;
7229329db04f13480ccdff013dcc00cdb96f12a921cWink Saville                    if (SKAI_DBG) {
7239329db04f13480ccdff013dcc00cdb96f12a921cWink Saville                        log("onResponse: checkTermination mKeepAliveInterval="
7248a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                                + mKeepAliveInterval);
725469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang                    }
7268a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                } else {
7278a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                    // calculate the new interval and continue.
7288a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                    mInterval = (mMaxInterval + mMinInterval) / 2;
7299329db04f13480ccdff013dcc00cdb96f12a921cWink Saville                    if (SKAI_DBG) {
7309329db04f13480ccdff013dcc00cdb96f12a921cWink Saville                        log("onResponse: mKeepAliveInterval=" + mKeepAliveInterval
7319329db04f13480ccdff013dcc00cdb96f12a921cWink Saville                                + ", new mInterval=" + mInterval);
7328a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                    }
7338a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                    restart();
7349c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                }
7359c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            }
7369c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
7379c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
7388a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan        // SipSessionGroup.KeepAliveProcessCallback
7398a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan        @Override
7408a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan        public void onError(int errorCode, String description) {
7419329db04f13480ccdff013dcc00cdb96f12a921cWink Saville            if (SKAI_DBG) loge("onError: errorCode=" + errorCode + " desc=" + description);
7427d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan            restartLater();
7437d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan        }
7447d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan
7457d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan        // timeout handler
7467d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan        @Override
7477d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan        public void run() {
7487d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan            mTimer.cancel(this);
7497d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan            restart();
7507d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan        }
7517d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan
7527d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan        private void restartLater() {
7538a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan            synchronized (SipService.this) {
7547d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan                int interval = NAT_MEASUREMENT_RETRY_INTERVAL;
7557d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan                mTimer.cancel(this);
7567d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan                mTimer.set(interval * 1000, this);
7578a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan            }
7589c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
7599329db04f13480ccdff013dcc00cdb96f12a921cWink Saville
7609329db04f13480ccdff013dcc00cdb96f12a921cWink Saville        private void log(String s) {
7619329db04f13480ccdff013dcc00cdb96f12a921cWink Saville            Rlog.d(SKAI_TAG, s);
7629329db04f13480ccdff013dcc00cdb96f12a921cWink Saville        }
7639329db04f13480ccdff013dcc00cdb96f12a921cWink Saville
7649329db04f13480ccdff013dcc00cdb96f12a921cWink Saville        private void loge(String s) {
7659329db04f13480ccdff013dcc00cdb96f12a921cWink Saville            Rlog.d(SKAI_TAG, s);
7669329db04f13480ccdff013dcc00cdb96f12a921cWink Saville        }
7679329db04f13480ccdff013dcc00cdb96f12a921cWink Saville
7689329db04f13480ccdff013dcc00cdb96f12a921cWink Saville        private void loge(String s, Throwable t) {
7699329db04f13480ccdff013dcc00cdb96f12a921cWink Saville            Rlog.d(SKAI_TAG, s, t);
7709329db04f13480ccdff013dcc00cdb96f12a921cWink Saville        }
7719c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    }
7729c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
7739329db04f13480ccdff013dcc00cdb96f12a921cWink Saville    private class SipAutoReg extends SipSessionAdapter
7748a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan            implements Runnable, SipSessionGroup.KeepAliveProcessCallback {
7759329db04f13480ccdff013dcc00cdb96f12a921cWink Saville        private String SAR_TAG;
7769329db04f13480ccdff013dcc00cdb96f12a921cWink Saville        private static final boolean SAR_DBG = true;
7777d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan        private static final int MIN_KEEPALIVE_SUCCESS_COUNT = 10;
7787d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan
7799c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        private SipSessionGroup.SipSessionImpl mSession;
7808a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan        private SipSessionGroup.SipSessionImpl mKeepAliveSession;
7819c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        private SipSessionListenerProxy mProxy = new SipSessionListenerProxy();
7829c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        private int mBackoff = 1;
7839c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        private boolean mRegistered;
7849c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        private long mExpiryTime;
7859c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        private int mErrorCode;
7869c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        private String mErrorMessage;
787d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan        private boolean mRunning = false;
7889c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
7897d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan        private int mKeepAliveSuccessCount = 0;
7907d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan
7919c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        public void start(SipSessionGroup group) {
792d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan            if (!mRunning) {
793d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan                mRunning = true;
7949c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                mBackoff = 1;
7959c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                mSession = (SipSessionGroup.SipSessionImpl)
7969c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                        group.createSession(this);
7979c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                // return right away if no active network connection.
7989c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                if (mSession == null) return;
7999c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
8009c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                // start unregistration to clear up old registration at server
8019c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                // TODO: when rfc5626 is deployed, use reg-id and sip.instance
8029c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                // in registration to avoid adding duplicate entries to server
803257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan                mMyWakeLock.acquire(mSession);
8049c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                mSession.unregister();
8059329db04f13480ccdff013dcc00cdb96f12a921cWink Saville                SAR_TAG = "SipAutoReg:" + mSession.getLocalProfile().getUriString();
8069329db04f13480ccdff013dcc00cdb96f12a921cWink Saville                if (SAR_DBG) log("start: group=" + group);
8079c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            }
8089c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
8099c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
8107d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan        private void startKeepAliveProcess(int interval) {
8119329db04f13480ccdff013dcc00cdb96f12a921cWink Saville            if (SAR_DBG) log("startKeepAliveProcess: interval=" + interval);
8127d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan            if (mKeepAliveSession == null) {
8137d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan                mKeepAliveSession = mSession.duplicate();
8147d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan            } else {
8157d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan                mKeepAliveSession.stopKeepAliveProcess();
8167d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan            }
8177d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan            try {
8187d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan                mKeepAliveSession.startKeepAliveProcess(interval, this);
8197d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan            } catch (SipException e) {
8209329db04f13480ccdff013dcc00cdb96f12a921cWink Saville                loge("startKeepAliveProcess: interval=" + interval, e);
8217d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan            }
8227d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan        }
8237d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan
8247d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan        private void stopKeepAliveProcess() {
8257d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan            if (mKeepAliveSession != null) {
8267d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan                mKeepAliveSession.stopKeepAliveProcess();
8277d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan                mKeepAliveSession = null;
8287d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan            }
8297d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan            mKeepAliveSuccessCount = 0;
8307d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan        }
8317d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan
8328a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan        // SipSessionGroup.KeepAliveProcessCallback
8338a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan        @Override
8348a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan        public void onResponse(boolean portChanged) {
8358a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan            synchronized (SipService.this) {
83644ccfb03bb349a90546ddb3dc0063cbf4aaddaf1Hung-ying Tyan                if (portChanged) {
8377d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan                    int interval = getKeepAliveInterval();
8387d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan                    if (mKeepAliveSuccessCount < MIN_KEEPALIVE_SUCCESS_COUNT) {
8399329db04f13480ccdff013dcc00cdb96f12a921cWink Saville                        if (SAR_DBG) {
8409329db04f13480ccdff013dcc00cdb96f12a921cWink Saville                            log("onResponse: keepalive doesn't work with interval "
8419329db04f13480ccdff013dcc00cdb96f12a921cWink Saville                                    + interval + ", past success count="
8429329db04f13480ccdff013dcc00cdb96f12a921cWink Saville                                    + mKeepAliveSuccessCount);
8439329db04f13480ccdff013dcc00cdb96f12a921cWink Saville                        }
8447d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan                        if (interval > DEFAULT_KEEPALIVE_INTERVAL) {
8457d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan                            restartPortMappingLifetimeMeasurement(
8467d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan                                    mSession.getLocalProfile(), interval);
8477d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan                            mKeepAliveSuccessCount = 0;
8487d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan                        }
8497d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan                    } else {
8509329db04f13480ccdff013dcc00cdb96f12a921cWink Saville                        if (SAR_DBG) {
8519329db04f13480ccdff013dcc00cdb96f12a921cWink Saville                            log("keep keepalive going with interval "
85285caf063c027ba0d1defeaff8850e12b6428c4f7Chia-chi Yeh                                    + interval + ", past success count="
85385caf063c027ba0d1defeaff8850e12b6428c4f7Chia-chi Yeh                                    + mKeepAliveSuccessCount);
85485caf063c027ba0d1defeaff8850e12b6428c4f7Chia-chi Yeh                        }
8557d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan                        mKeepAliveSuccessCount /= 2;
8567d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan                    }
85744ccfb03bb349a90546ddb3dc0063cbf4aaddaf1Hung-ying Tyan                } else {
85844ccfb03bb349a90546ddb3dc0063cbf4aaddaf1Hung-ying Tyan                    // Start keep-alive interval measurement on the first
85944ccfb03bb349a90546ddb3dc0063cbf4aaddaf1Hung-ying Tyan                    // successfully kept-alive SipSessionGroup
86044ccfb03bb349a90546ddb3dc0063cbf4aaddaf1Hung-ying Tyan                    startPortMappingLifetimeMeasurement(
86144ccfb03bb349a90546ddb3dc0063cbf4aaddaf1Hung-ying Tyan                            mSession.getLocalProfile());
8627d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan                    mKeepAliveSuccessCount++;
86344ccfb03bb349a90546ddb3dc0063cbf4aaddaf1Hung-ying Tyan                }
8648a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan
8658a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                if (!mRunning || !portChanged) return;
8669dbe2c72276b9968593054dcfd39fd5135a574aaHung-ying Tyan
8679dbe2c72276b9968593054dcfd39fd5135a574aaHung-ying Tyan                // The keep alive process is stopped when port is changed;
8689dbe2c72276b9968593054dcfd39fd5135a574aaHung-ying Tyan                // Nullify the session so that the process can be restarted
8699dbe2c72276b9968593054dcfd39fd5135a574aaHung-ying Tyan                // again when the re-registration is done
8709dbe2c72276b9968593054dcfd39fd5135a574aaHung-ying Tyan                mKeepAliveSession = null;
8719dbe2c72276b9968593054dcfd39fd5135a574aaHung-ying Tyan
8728a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                // Acquire wake lock for the registration process. The
8738a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                // lock will be released when registration is complete.
8748a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                mMyWakeLock.acquire(mSession);
8758a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                mSession.register(EXPIRY_TIME);
8768a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan            }
8778a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan        }
8788a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan
8798a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan        // SipSessionGroup.KeepAliveProcessCallback
8808a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan        @Override
8818a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan        public void onError(int errorCode, String description) {
8829329db04f13480ccdff013dcc00cdb96f12a921cWink Saville            if (SAR_DBG) {
8839329db04f13480ccdff013dcc00cdb96f12a921cWink Saville                loge("onError: errorCode=" + errorCode + " desc=" + description);
88485caf063c027ba0d1defeaff8850e12b6428c4f7Chia-chi Yeh            }
88544ccfb03bb349a90546ddb3dc0063cbf4aaddaf1Hung-ying Tyan            onResponse(true); // re-register immediately
8868a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan        }
8878a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan
8889c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        public void stop() {
889d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan            if (!mRunning) return;
890d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan            mRunning = false;
891257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan            mMyWakeLock.release(mSession);
892257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan            if (mSession != null) {
893257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan                mSession.setListener(null);
8947d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh                if (mNetworkType != -1 && mRegistered) mSession.unregister();
895257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan            }
896d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan
8979c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            mTimer.cancel(this);
8987d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan            stopKeepAliveProcess();
8999c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
900d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan            mRegistered = false;
901d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan            setListener(mProxy.getListener());
9029c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
9039c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
9048a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan        public void onKeepAliveIntervalChanged() {
9058a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan            if (mKeepAliveSession != null) {
9068a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                int newInterval = getKeepAliveInterval();
9079329db04f13480ccdff013dcc00cdb96f12a921cWink Saville                if (SAR_DBG) {
9089329db04f13480ccdff013dcc00cdb96f12a921cWink Saville                    log("onKeepAliveIntervalChanged: interval=" + newInterval);
9098a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                }
9107d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan                mKeepAliveSuccessCount = 0;
9117d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan                startKeepAliveProcess(newInterval);
9128a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan            }
9138a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan        }
9148a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan
9159c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        public void setListener(ISipSessionListener listener) {
9169c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            synchronized (SipService.this) {
9179c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                mProxy.setListener(listener);
9189c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
9199c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                try {
9209c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                    int state = (mSession == null)
9219c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                            ? SipSession.State.READY_TO_CALL
9229c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                            : mSession.getState();
9239c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                    if ((state == SipSession.State.REGISTERING)
9249c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                            || (state == SipSession.State.DEREGISTERING)) {
9259c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                        mProxy.onRegistering(mSession);
9269c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                    } else if (mRegistered) {
9279c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                        int duration = (int)
9289c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                                (mExpiryTime - SystemClock.elapsedRealtime());
9299c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                        mProxy.onRegistrationDone(mSession, duration);
9309c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                    } else if (mErrorCode != SipErrorCode.NO_ERROR) {
9319c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                        if (mErrorCode == SipErrorCode.TIME_OUT) {
9329c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                            mProxy.onRegistrationTimeout(mSession);
9339c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                        } else {
9349c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                            mProxy.onRegistrationFailed(mSession, mErrorCode,
9359c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                                    mErrorMessage);
9369c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                        }
9377d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh                    } else if (mNetworkType == -1) {
938d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan                        mProxy.onRegistrationFailed(mSession,
939d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan                                SipErrorCode.DATA_CONNECTION_LOST,
940d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan                                "no data connection");
941d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan                    } else if (!mRunning) {
942d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan                        mProxy.onRegistrationFailed(mSession,
943d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan                                SipErrorCode.CLIENT_ERROR,
944d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan                                "registration not running");
945d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan                    } else {
946d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan                        mProxy.onRegistrationFailed(mSession,
947d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan                                SipErrorCode.IN_PROGRESS,
948d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan                                String.valueOf(state));
9499c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                    }
9509c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                } catch (Throwable t) {
9519329db04f13480ccdff013dcc00cdb96f12a921cWink Saville                    loge("setListener: ", t);
9529c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                }
9539c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            }
9549c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
9559c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
9569c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        public boolean isRegistered() {
9579c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            return mRegistered;
9589c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
9599c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
960257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan        // timeout handler: re-register
9618a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan        @Override
9629c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        public void run() {
963d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan            synchronized (SipService.this) {
964d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan                if (!mRunning) return;
965d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan
966d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan                mErrorCode = SipErrorCode.NO_ERROR;
967d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan                mErrorMessage = null;
9689329db04f13480ccdff013dcc00cdb96f12a921cWink Saville                if (SAR_DBG) log("run: registering");
9697d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh                if (mNetworkType != -1) {
970257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan                    mMyWakeLock.acquire(mSession);
971257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan                    mSession.register(EXPIRY_TIME);
972257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan                }
9739c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            }
9749c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
9759c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
9769c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        private void restart(int duration) {
9779329db04f13480ccdff013dcc00cdb96f12a921cWink Saville            if (SAR_DBG) log("restart: duration=" + duration + "s later.");
9789c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            mTimer.cancel(this);
9799c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            mTimer.set(duration * 1000, this);
9809c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
9819c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
9829c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        private int backoffDuration() {
9839c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            int duration = SHORT_EXPIRY_TIME * mBackoff;
9849c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            if (duration > 3600) {
9859c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                duration = 3600;
9869c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            } else {
9879c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                mBackoff *= 2;
9889c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            }
9899c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            return duration;
9909c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
9919c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
9929c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        @Override
9939c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        public void onRegistering(ISipSession session) {
9949329db04f13480ccdff013dcc00cdb96f12a921cWink Saville            if (SAR_DBG) log("onRegistering: " + session);
9959c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            synchronized (SipService.this) {
996d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan                if (notCurrentSession(session)) return;
997d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan
9989c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                mRegistered = false;
9999c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                mProxy.onRegistering(session);
10009c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            }
10019c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
10029c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
1003d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan        private boolean notCurrentSession(ISipSession session) {
1004d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan            if (session != mSession) {
1005d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan                ((SipSessionGroup.SipSessionImpl) session).setListener(null);
1006257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan                mMyWakeLock.release(session);
1007d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan                return true;
1008d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan            }
1009d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan            return !mRunning;
1010d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan        }
1011d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan
10129c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        @Override
10139c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        public void onRegistrationDone(ISipSession session, int duration) {
10149329db04f13480ccdff013dcc00cdb96f12a921cWink Saville            if (SAR_DBG) log("onRegistrationDone: " + session);
10159c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            synchronized (SipService.this) {
1016d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan                if (notCurrentSession(session)) return;
10179c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
10189c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                mProxy.onRegistrationDone(session, duration);
10199c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
10209c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                if (duration > 0) {
10219c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                    mExpiryTime = SystemClock.elapsedRealtime()
10229c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                            + (duration * 1000);
10239c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
10249c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                    if (!mRegistered) {
10259c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                        mRegistered = true;
10269c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                        // allow some overlap to avoid call drop during renew
10279c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                        duration -= MIN_EXPIRY_TIME;
10289c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                        if (duration < MIN_EXPIRY_TIME) {
10299c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                            duration = MIN_EXPIRY_TIME;
10309c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                        }
10319c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                        restart(duration);
10329c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
10338a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                        SipProfile localProfile = mSession.getLocalProfile();
10348a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                        if ((mKeepAliveSession == null) && (isBehindNAT(mLocalIp)
10358a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                                || localProfile.getSendKeepAlive())) {
10367d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan                            startKeepAliveProcess(getKeepAliveInterval());
10379c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                        }
10389c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                    }
1039257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan                    mMyWakeLock.release(session);
10409c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                } else {
10419c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                    mRegistered = false;
10429c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                    mExpiryTime = -1L;
10439329db04f13480ccdff013dcc00cdb96f12a921cWink Saville                    if (SAR_DBG) log("Refresh registration immediately");
10449c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                    run();
10459c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                }
10469c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            }
10479c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
10489c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
10499c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        @Override
10509c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        public void onRegistrationFailed(ISipSession session, int errorCode,
10519c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                String message) {
10529329db04f13480ccdff013dcc00cdb96f12a921cWink Saville            if (SAR_DBG) log("onRegistrationFailed: " + session + ": "
10539c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                    + SipErrorCode.toString(errorCode) + ": " + message);
10549c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            synchronized (SipService.this) {
1055d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan                if (notCurrentSession(session)) return;
10569c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
1057fcc474636f42243cfce960158373b9c49636a556Hung-ying Tyan                switch (errorCode) {
1058fcc474636f42243cfce960158373b9c49636a556Hung-ying Tyan                    case SipErrorCode.INVALID_CREDENTIALS:
1059fcc474636f42243cfce960158373b9c49636a556Hung-ying Tyan                    case SipErrorCode.SERVER_UNREACHABLE:
10609329db04f13480ccdff013dcc00cdb96f12a921cWink Saville                        if (SAR_DBG) log("   pause auto-registration");
1061fcc474636f42243cfce960158373b9c49636a556Hung-ying Tyan                        stop();
10620b88a073712b1510db7c636f89c4e19f0131449aHung-ying Tyan                        break;
1063fcc474636f42243cfce960158373b9c49636a556Hung-ying Tyan                    default:
1064fcc474636f42243cfce960158373b9c49636a556Hung-ying Tyan                        restartLater();
10659c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                }
1066d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan
1067d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan                mErrorCode = errorCode;
1068d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan                mErrorMessage = message;
1069d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan                mProxy.onRegistrationFailed(session, errorCode, message);
1070257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan                mMyWakeLock.release(session);
10719c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            }
10729c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
10739c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
10749c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        @Override
10759c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        public void onRegistrationTimeout(ISipSession session) {
10769329db04f13480ccdff013dcc00cdb96f12a921cWink Saville            if (SAR_DBG) log("onRegistrationTimeout: " + session);
10779c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            synchronized (SipService.this) {
1078d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan                if (notCurrentSession(session)) return;
1079d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan
10809c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                mErrorCode = SipErrorCode.TIME_OUT;
10819c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                mProxy.onRegistrationTimeout(session);
1082fcc474636f42243cfce960158373b9c49636a556Hung-ying Tyan                restartLater();
1083257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan                mMyWakeLock.release(session);
10849c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            }
10859c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
10869c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
1087fcc474636f42243cfce960158373b9c49636a556Hung-ying Tyan        private void restartLater() {
10889329db04f13480ccdff013dcc00cdb96f12a921cWink Saville            if (SAR_DBG) loge("restartLater");
10899c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            mRegistered = false;
10909c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            restart(backoffDuration());
10919c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
10929329db04f13480ccdff013dcc00cdb96f12a921cWink Saville
10939329db04f13480ccdff013dcc00cdb96f12a921cWink Saville        private void log(String s) {
10949329db04f13480ccdff013dcc00cdb96f12a921cWink Saville            Rlog.d(SAR_TAG, s);
10959329db04f13480ccdff013dcc00cdb96f12a921cWink Saville        }
10969329db04f13480ccdff013dcc00cdb96f12a921cWink Saville
10979329db04f13480ccdff013dcc00cdb96f12a921cWink Saville        private void loge(String s) {
10989329db04f13480ccdff013dcc00cdb96f12a921cWink Saville            Rlog.e(SAR_TAG, s);
10999329db04f13480ccdff013dcc00cdb96f12a921cWink Saville        }
11009329db04f13480ccdff013dcc00cdb96f12a921cWink Saville
11019329db04f13480ccdff013dcc00cdb96f12a921cWink Saville        private void loge(String s, Throwable e) {
11029329db04f13480ccdff013dcc00cdb96f12a921cWink Saville            Rlog.e(SAR_TAG, s, e);
11039329db04f13480ccdff013dcc00cdb96f12a921cWink Saville        }
11049c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    }
11059c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
11069c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    private class ConnectivityReceiver extends BroadcastReceiver {
11079c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        @Override
110879d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh        public void onReceive(Context context, Intent intent) {
110979d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh            Bundle bundle = intent.getExtras();
111079d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh            if (bundle != null) {
111179d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh                final NetworkInfo info = (NetworkInfo)
111279d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh                        bundle.get(ConnectivityManager.EXTRA_NETWORK_INFO);
11139c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
111479d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh                // Run the handler in MyExecutor to be protected by wake lock
111579d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh                mExecutor.execute(new Runnable() {
11169329db04f13480ccdff013dcc00cdb96f12a921cWink Saville                    @Override
111779d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh                    public void run() {
111879d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh                        onConnectivityChanged(info);
11199c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                    }
112079d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh                });
11219c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            }
11229c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
112379d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh    }
112479d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh
112579d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh    private void registerReceivers() {
112679d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh        mContext.registerReceiver(mConnectivityReceiver,
112779d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh                new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));
11289329db04f13480ccdff013dcc00cdb96f12a921cWink Saville        if (DBG) log("registerReceivers:");
112979d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh    }
11309c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
113179d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh    private void unregisterReceivers() {
113279d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh        mContext.unregisterReceiver(mConnectivityReceiver);
11339329db04f13480ccdff013dcc00cdb96f12a921cWink Saville        if (DBG) log("unregisterReceivers:");
113479d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh
113579d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh        // Reset variables maintained by ConnectivityReceiver.
113679d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh        mWifiLock.release();
11377d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh        mNetworkType = -1;
11387d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh    }
11397d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh
11407d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh    private void updateWakeLocks() {
11417d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh        for (SipSessionGroupExt group : mSipGroups.values()) {
11427d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh            if (group.isOpenedToReceiveCalls()) {
11437d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh                // Also grab the WifiLock when we are disconnected, so the
11447d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh                // system will keep trying to reconnect. It will be released
11457d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh                // when the system eventually connects to something else.
11467d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh                if (mNetworkType == ConnectivityManager.TYPE_WIFI || mNetworkType == -1) {
11477d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh                    mWifiLock.acquire();
11487d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh                } else {
11497d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh                    mWifiLock.release();
11507d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh                }
11517d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh                return;
11527d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh            }
11537d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh        }
11547d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh        mWifiLock.release();
11557d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh        mMyWakeLock.reset(); // in case there's a leak
115679d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh    }
115779d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh
115879d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh    private synchronized void onConnectivityChanged(NetworkInfo info) {
115979d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh        // We only care about the default network, and getActiveNetworkInfo()
116079d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh        // is the only way to distinguish them. However, as broadcasts are
116179d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh        // delivered asynchronously, we might miss DISCONNECTED events from
116279d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh        // getActiveNetworkInfo(), which is critical to our SIP stack. To
116379d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh        // solve this, if it is a DISCONNECTED event to our current network,
116479d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh        // respect it. Otherwise get a new one from getActiveNetworkInfo().
11657d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh        if (info == null || info.isConnected() || info.getType() != mNetworkType) {
11669c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            ConnectivityManager cm = (ConnectivityManager)
11679c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                    mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
116879d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh            info = cm.getActiveNetworkInfo();
11699c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
11709c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
117179d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh        // Some devices limit SIP on Wi-Fi. In this case, if we are not on
117279d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh        // Wi-Fi, treat it as a DISCONNECTED event.
11737d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh        int networkType = (info != null && info.isConnected()) ? info.getType() : -1;
11747d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh        if (mSipOnWifiOnly && networkType != ConnectivityManager.TYPE_WIFI) {
11757d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh            networkType = -1;
11767d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh        }
11779c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
117879d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh        // Ignore the event if the current active network is not changed.
11797d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh        if (mNetworkType == networkType) {
11809329db04f13480ccdff013dcc00cdb96f12a921cWink Saville            // TODO: Maybe we need to send seq/generation number
118179d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh            return;
118279d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh        }
11839329db04f13480ccdff013dcc00cdb96f12a921cWink Saville        if (DBG) {
11849329db04f13480ccdff013dcc00cdb96f12a921cWink Saville            log("onConnectivityChanged: " + mNetworkType +
118579d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh                    " -> " + networkType);
118679d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh        }
11879c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
118879d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh        try {
11897d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh            if (mNetworkType != -1) {
119079d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh                mLocalIp = null;
119179d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh                stopPortMappingMeasurement();
119279d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh                for (SipSessionGroupExt group : mSipGroups.values()) {
119379d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh                    group.onConnectivityChanged(false);
119479d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh                }
11959c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            }
119679d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh            mNetworkType = networkType;
11979c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
11987d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh            if (mNetworkType != -1) {
119979d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh                mLocalIp = determineLocalIp();
120079d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh                mKeepAliveInterval = -1;
120179d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh                mLastGoodKeepAliveInterval = DEFAULT_KEEPALIVE_INTERVAL;
120279d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh                for (SipSessionGroupExt group : mSipGroups.values()) {
120379d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh                    group.onConnectivityChanged(true);
12049c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                }
12059c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            }
12067d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh            updateWakeLocks();
120779d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh        } catch (SipException e) {
12089329db04f13480ccdff013dcc00cdb96f12a921cWink Saville            loge("onConnectivityChanged()", e);
12099c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
12109c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    }
12119c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
1212257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan    private static Looper createLooper() {
1213257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan        HandlerThread thread = new HandlerThread("SipService.Executor");
1214257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan        thread.start();
1215257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan        return thread.getLooper();
1216257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan    }
1217257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan
1218257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan    // Executes immediate tasks in a single thread.
1219257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan    // Hold/release wake lock for running tasks
12204cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan    private class MyExecutor extends Handler implements Executor {
12219c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        MyExecutor() {
12229c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            super(createLooper());
12239c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
12249c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
12254cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan        @Override
12264cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan        public void execute(Runnable task) {
1227257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan            mMyWakeLock.acquire(task);
12289c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            Message.obtain(this, 0/* don't care */, task).sendToTarget();
12299c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
12309c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
12319c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        @Override
12329c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        public void handleMessage(Message msg) {
12339c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            if (msg.obj instanceof Runnable) {
1234257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan                executeInternal((Runnable) msg.obj);
12359c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            } else {
12369329db04f13480ccdff013dcc00cdb96f12a921cWink Saville                if (DBG) log("handleMessage: not Runnable ignore msg=" + msg);
12379c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            }
12389c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
1239257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan
1240257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan        private void executeInternal(Runnable task) {
1241257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan            try {
1242257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan                task.run();
1243257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan            } catch (Throwable t) {
12449329db04f13480ccdff013dcc00cdb96f12a921cWink Saville                loge("run task: " + task, t);
1245257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan            } finally {
1246257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan                mMyWakeLock.release(task);
1247257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan            }
1248257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan        }
1249257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan    }
12509329db04f13480ccdff013dcc00cdb96f12a921cWink Saville
12519329db04f13480ccdff013dcc00cdb96f12a921cWink Saville    private void log(String s) {
12529329db04f13480ccdff013dcc00cdb96f12a921cWink Saville        Rlog.d(TAG, s);
12539329db04f13480ccdff013dcc00cdb96f12a921cWink Saville    }
12549329db04f13480ccdff013dcc00cdb96f12a921cWink Saville
12559329db04f13480ccdff013dcc00cdb96f12a921cWink Saville    private static void slog(String s) {
12569329db04f13480ccdff013dcc00cdb96f12a921cWink Saville        Rlog.d(TAG, s);
12579329db04f13480ccdff013dcc00cdb96f12a921cWink Saville    }
12589329db04f13480ccdff013dcc00cdb96f12a921cWink Saville
12599329db04f13480ccdff013dcc00cdb96f12a921cWink Saville    private void loge(String s, Throwable e) {
12609329db04f13480ccdff013dcc00cdb96f12a921cWink Saville        Rlog.e(TAG, s, e);
12619329db04f13480ccdff013dcc00cdb96f12a921cWink Saville    }
12629c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan}
1263