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
19d08c8ddcf7bab2beaf212fb7607da15f51ebc09cSvetoslavimport android.app.AppOpsManager;
209c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.app.PendingIntent;
219c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.content.BroadcastReceiver;
229c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.content.Context;
239c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.content.Intent;
249c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.content.IntentFilter;
259c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.net.ConnectivityManager;
269c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.net.NetworkInfo;
279c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.net.sip.ISipService;
289c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.net.sip.ISipSession;
299c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.net.sip.ISipSessionListener;
309c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.net.sip.SipErrorCode;
319c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.net.sip.SipManager;
329c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.net.sip.SipProfile;
339c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.net.sip.SipSession;
349c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.net.sip.SipSessionAdapter;
359c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.net.wifi.WifiManager;
369c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.os.Binder;
379c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.os.Bundle;
389c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.os.Handler;
399c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.os.HandlerThread;
409c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.os.Looper;
419c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.os.Message;
42257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyanimport android.os.PowerManager;
43a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyanimport android.os.Process;
449c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.os.RemoteException;
459c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.os.ServiceManager;
469c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.os.SystemClock;
479329db04f13480ccdff013dcc00cdb96f12a921cWink Savilleimport android.telephony.Rlog;
489c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
499c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport java.io.IOException;
509c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport java.net.DatagramSocket;
519c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport java.net.InetAddress;
529c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport java.net.UnknownHostException;
53a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyanimport java.util.ArrayList;
549c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport java.util.HashMap;
559c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport java.util.Map;
564cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyanimport java.util.concurrent.Executor;
57226ac3ad92a383436a13da89959178d51a0cec1bSantos Cordon
589c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport javax.sip.SipException;
599c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
609c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan/**
619c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan * @hide
629c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan */
639c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanpublic final class SipService extends ISipService.Stub {
64acedadc1967457ac2f8981c67f884fd8c0ee853cHung-ying Tyan    static final String TAG = "SipService";
659329db04f13480ccdff013dcc00cdb96f12a921cWink Saville    static final boolean DBG = true;
669c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    private static final int EXPIRY_TIME = 3600;
679c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    private static final int SHORT_EXPIRY_TIME = 10;
689c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    private static final int MIN_EXPIRY_TIME = 60;
698a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan    private static final int DEFAULT_KEEPALIVE_INTERVAL = 10; // in seconds
70cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan    private static final int DEFAULT_MAX_KEEPALIVE_INTERVAL = 120; // in seconds
719c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
729c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    private Context mContext;
739c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    private String mLocalIp;
747d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh    private int mNetworkType = -1;
754cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan    private SipWakeupTimer mTimer;
769c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    private WifiManager.WifiLock mWifiLock;
7779d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh    private boolean mSipOnWifiOnly;
78987b505b1c190ff0e5a05d2cc20c9b08d2b99b18Hung-ying Tyan
79d08c8ddcf7bab2beaf212fb7607da15f51ebc09cSvetoslav    private final AppOpsManager mAppOps;
80d08c8ddcf7bab2beaf212fb7607da15f51ebc09cSvetoslav
819329db04f13480ccdff013dcc00cdb96f12a921cWink Saville    private SipKeepAliveProcessCallback mSipKeepAliveProcessCallback;
829c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
834cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan    private MyExecutor mExecutor = new MyExecutor();
849c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
859c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    // SipProfile URI --> group
869c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    private Map<String, SipSessionGroupExt> mSipGroups =
879c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            new HashMap<String, SipSessionGroupExt>();
889c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
899c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    // session ID --> session
909c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    private Map<String, ISipSession> mPendingSessions =
919c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            new HashMap<String, ISipSession>();
929c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
939c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    private ConnectivityReceiver mConnectivityReceiver;
94acedadc1967457ac2f8981c67f884fd8c0ee853cHung-ying Tyan    private SipWakeLock mMyWakeLock;
95469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang    private int mKeepAliveInterval;
96cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan    private int mLastGoodKeepAliveInterval = DEFAULT_KEEPALIVE_INTERVAL;
979c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
989c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    /**
999c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan     * Starts the SIP service. Do nothing if the SIP API is not supported on the
1009c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan     * device.
1019c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan     */
1029c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    public static void start(Context context) {
1039c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        if (SipManager.isApiSupported(context)) {
104f08fe9659343327dc29da410b64597b33613c732Brad Ebinger            if (ServiceManager.getService("sip") == null) {
105f08fe9659343327dc29da410b64597b33613c732Brad Ebinger                ServiceManager.addService("sip", new SipService(context));
106f08fe9659343327dc29da410b64597b33613c732Brad Ebinger                context.sendBroadcast(new Intent(SipManager.ACTION_SIP_SERVICE_UP));
107f08fe9659343327dc29da410b64597b33613c732Brad Ebinger                if (DBG) slog("start:");
108f08fe9659343327dc29da410b64597b33613c732Brad Ebinger            }
1099c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
1109c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    }
1119c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
1129c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    private SipService(Context context) {
1139329db04f13480ccdff013dcc00cdb96f12a921cWink Saville        if (DBG) log("SipService: started!");
1149c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        mContext = context;
1159c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        mConnectivityReceiver = new ConnectivityReceiver();
11679d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh
11779d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh        mWifiLock = ((WifiManager)
11879d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh                context.getSystemService(Context.WIFI_SERVICE))
11979d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh                .createWifiLock(WifiManager.WIFI_MODE_FULL, TAG);
12079d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh        mWifiLock.setReferenceCounted(false);
12179d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh        mSipOnWifiOnly = SipManager.isSipWifiOnly(context);
12279d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh
123acedadc1967457ac2f8981c67f884fd8c0ee853cHung-ying Tyan        mMyWakeLock = new SipWakeLock((PowerManager)
124257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan                context.getSystemService(Context.POWER_SERVICE));
1259c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
1264cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan        mTimer = new SipWakeupTimer(context, mExecutor);
127d08c8ddcf7bab2beaf212fb7607da15f51ebc09cSvetoslav        mAppOps = mContext.getSystemService(AppOpsManager.class);
128dc7545495e1ef8bad32cd78775f4dc072015eea0Hung-ying Tyan    }
129dc7545495e1ef8bad32cd78775f4dc072015eea0Hung-ying Tyan
1309329db04f13480ccdff013dcc00cdb96f12a921cWink Saville    @Override
131d08c8ddcf7bab2beaf212fb7607da15f51ebc09cSvetoslav    public synchronized SipProfile[] getListOfProfiles(String opPackageName) {
132d08c8ddcf7bab2beaf212fb7607da15f51ebc09cSvetoslav        if (!canUseSip(opPackageName, "getListOfProfiles")) {
133d08c8ddcf7bab2beaf212fb7607da15f51ebc09cSvetoslav            return new SipProfile[0];
134d08c8ddcf7bab2beaf212fb7607da15f51ebc09cSvetoslav        }
135a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan        boolean isCallerRadio = isCallerRadio();
136a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan        ArrayList<SipProfile> profiles = new ArrayList<SipProfile>();
1379c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        for (SipSessionGroupExt group : mSipGroups.values()) {
138a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan            if (isCallerRadio || isCallerCreator(group)) {
139a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan                profiles.add(group.getLocalProfile());
140a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan            }
1419c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
142a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan        return profiles.toArray(new SipProfile[profiles.size()]);
1439c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    }
1449c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
1459329db04f13480ccdff013dcc00cdb96f12a921cWink Saville    @Override
146d08c8ddcf7bab2beaf212fb7607da15f51ebc09cSvetoslav    public synchronized void open(SipProfile localProfile, String opPackageName) {
147d08c8ddcf7bab2beaf212fb7607da15f51ebc09cSvetoslav        if (!canUseSip(opPackageName, "open")) {
148d08c8ddcf7bab2beaf212fb7607da15f51ebc09cSvetoslav            return;
149d08c8ddcf7bab2beaf212fb7607da15f51ebc09cSvetoslav        }
1509c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        localProfile.setCallingUid(Binder.getCallingUid());
1519c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        try {
1529c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            createGroup(localProfile);
1539c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        } catch (SipException e) {
1549329db04f13480ccdff013dcc00cdb96f12a921cWink Saville            loge("openToMakeCalls()", e);
1559c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            // TODO: how to send the exception back
1569c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
1579c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    }
1589c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
1599329db04f13480ccdff013dcc00cdb96f12a921cWink Saville    @Override
1609c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    public synchronized void open3(SipProfile localProfile,
161845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan            PendingIntent incomingCallPendingIntent,
162d08c8ddcf7bab2beaf212fb7607da15f51ebc09cSvetoslav            ISipSessionListener listener,
163d08c8ddcf7bab2beaf212fb7607da15f51ebc09cSvetoslav            String opPackageName) {
164d08c8ddcf7bab2beaf212fb7607da15f51ebc09cSvetoslav        if (!canUseSip(opPackageName, "open3")) {
165d08c8ddcf7bab2beaf212fb7607da15f51ebc09cSvetoslav            return;
166d08c8ddcf7bab2beaf212fb7607da15f51ebc09cSvetoslav        }
1679c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        localProfile.setCallingUid(Binder.getCallingUid());
168845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan        if (incomingCallPendingIntent == null) {
1699329db04f13480ccdff013dcc00cdb96f12a921cWink Saville            if (DBG) log("open3: incomingCallPendingIntent cannot be null; "
170845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan                    + "the profile is not opened");
171a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan            return;
1729c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
173226ac3ad92a383436a13da89959178d51a0cec1bSantos Cordon        if (DBG) log("open3: " + obfuscateSipUri(localProfile.getUriString()) + ": "
174845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan                + incomingCallPendingIntent + ": " + listener);
1759c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        try {
1769c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            SipSessionGroupExt group = createGroup(localProfile,
177845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan                    incomingCallPendingIntent, listener);
1789c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            if (localProfile.getAutoRegistration()) {
1799c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                group.openToReceiveCalls();
1807d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh                updateWakeLocks();
1819c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            }
1829c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        } catch (SipException e) {
1839329db04f13480ccdff013dcc00cdb96f12a921cWink Saville            loge("open3:", e);
1849c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            // TODO: how to send the exception back
1859c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
1869c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    }
1879c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
188a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan    private boolean isCallerCreator(SipSessionGroupExt group) {
189a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan        SipProfile profile = group.getLocalProfile();
190a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan        return (profile.getCallingUid() == Binder.getCallingUid());
191a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan    }
192a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan
193a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan    private boolean isCallerCreatorOrRadio(SipSessionGroupExt group) {
194a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan        return (isCallerRadio() || isCallerCreator(group));
195a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan    }
196a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan
197a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan    private boolean isCallerRadio() {
198a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan        return (Binder.getCallingUid() == Process.PHONE_UID);
199a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan    }
200a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan
2019329db04f13480ccdff013dcc00cdb96f12a921cWink Saville    @Override
202d08c8ddcf7bab2beaf212fb7607da15f51ebc09cSvetoslav    public synchronized void close(String localProfileUri, String opPackageName) {
203d08c8ddcf7bab2beaf212fb7607da15f51ebc09cSvetoslav        if (!canUseSip(opPackageName, "close")) {
204d08c8ddcf7bab2beaf212fb7607da15f51ebc09cSvetoslav            return;
205d08c8ddcf7bab2beaf212fb7607da15f51ebc09cSvetoslav        }
206a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan        SipSessionGroupExt group = mSipGroups.get(localProfileUri);
207a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan        if (group == null) return;
208a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan        if (!isCallerCreatorOrRadio(group)) {
2099329db04f13480ccdff013dcc00cdb96f12a921cWink Saville            if (DBG) log("only creator or radio can close this profile");
210a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan            return;
2119c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
212a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan
213a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan        group = mSipGroups.remove(localProfileUri);
214a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan        notifyProfileRemoved(group.getLocalProfile());
215a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan        group.close();
216257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan
2177d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh        updateWakeLocks();
2189c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    }
2199c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
2209329db04f13480ccdff013dcc00cdb96f12a921cWink Saville    @Override
221d08c8ddcf7bab2beaf212fb7607da15f51ebc09cSvetoslav    public synchronized boolean isOpened(String localProfileUri, String opPackageName) {
222d08c8ddcf7bab2beaf212fb7607da15f51ebc09cSvetoslav        if (!canUseSip(opPackageName, "isOpened")) {
223d08c8ddcf7bab2beaf212fb7607da15f51ebc09cSvetoslav            return false;
224d08c8ddcf7bab2beaf212fb7607da15f51ebc09cSvetoslav        }
2259c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        SipSessionGroupExt group = mSipGroups.get(localProfileUri);
226a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan        if (group == null) return false;
227a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan        if (isCallerCreatorOrRadio(group)) {
228617479363dcafe01bfa1fa025e1d9d122864a0ceHung-ying Tyan            return true;
229a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan        } else {
2309329db04f13480ccdff013dcc00cdb96f12a921cWink Saville            if (DBG) log("only creator or radio can query on the profile");
231a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan            return false;
232a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan        }
2339c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    }
2349c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
2359329db04f13480ccdff013dcc00cdb96f12a921cWink Saville    @Override
236d08c8ddcf7bab2beaf212fb7607da15f51ebc09cSvetoslav    public synchronized boolean isRegistered(String localProfileUri, String opPackageName) {
237d08c8ddcf7bab2beaf212fb7607da15f51ebc09cSvetoslav        if (!canUseSip(opPackageName, "isRegistered")) {
238d08c8ddcf7bab2beaf212fb7607da15f51ebc09cSvetoslav            return false;
239d08c8ddcf7bab2beaf212fb7607da15f51ebc09cSvetoslav        }
2409c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        SipSessionGroupExt group = mSipGroups.get(localProfileUri);
241a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan        if (group == null) return false;
242a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan        if (isCallerCreatorOrRadio(group)) {
243a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan            return group.isRegistered();
244a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan        } else {
2459329db04f13480ccdff013dcc00cdb96f12a921cWink Saville            if (DBG) log("only creator or radio can query on the profile");
246a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan            return false;
247a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan        }
2489c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    }
2499c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
2509329db04f13480ccdff013dcc00cdb96f12a921cWink Saville    @Override
2519c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    public synchronized void setRegistrationListener(String localProfileUri,
252d08c8ddcf7bab2beaf212fb7607da15f51ebc09cSvetoslav            ISipSessionListener listener, String opPackageName) {
253d08c8ddcf7bab2beaf212fb7607da15f51ebc09cSvetoslav        if (!canUseSip(opPackageName, "setRegistrationListener")) {
254d08c8ddcf7bab2beaf212fb7607da15f51ebc09cSvetoslav            return;
255d08c8ddcf7bab2beaf212fb7607da15f51ebc09cSvetoslav        }
2569c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        SipSessionGroupExt group = mSipGroups.get(localProfileUri);
257a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan        if (group == null) return;
258a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan        if (isCallerCreator(group)) {
259a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan            group.setListener(listener);
260a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan        } else {
2619329db04f13480ccdff013dcc00cdb96f12a921cWink Saville            if (DBG) log("only creator can set listener on the profile");
262a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan        }
2639c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    }
2649c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
2659329db04f13480ccdff013dcc00cdb96f12a921cWink Saville    @Override
2669c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    public synchronized ISipSession createSession(SipProfile localProfile,
267d08c8ddcf7bab2beaf212fb7607da15f51ebc09cSvetoslav            ISipSessionListener listener, String opPackageName) {
2689329db04f13480ccdff013dcc00cdb96f12a921cWink Saville        if (DBG) log("createSession: profile" + localProfile);
269d08c8ddcf7bab2beaf212fb7607da15f51ebc09cSvetoslav        if (!canUseSip(opPackageName, "createSession")) {
270d08c8ddcf7bab2beaf212fb7607da15f51ebc09cSvetoslav            return null;
271d08c8ddcf7bab2beaf212fb7607da15f51ebc09cSvetoslav        }
2729c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        localProfile.setCallingUid(Binder.getCallingUid());
2739329db04f13480ccdff013dcc00cdb96f12a921cWink Saville        if (mNetworkType == -1) {
2749329db04f13480ccdff013dcc00cdb96f12a921cWink Saville            if (DBG) log("createSession: mNetworkType==-1 ret=null");
2759329db04f13480ccdff013dcc00cdb96f12a921cWink Saville            return null;
2769329db04f13480ccdff013dcc00cdb96f12a921cWink Saville        }
2779c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        try {
2789c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            SipSessionGroupExt group = createGroup(localProfile);
2799c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            return group.createSession(listener);
2809c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        } catch (SipException e) {
2819329db04f13480ccdff013dcc00cdb96f12a921cWink Saville            if (DBG) loge("createSession;", e);
2829c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            return null;
2839c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
2849c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    }
2859c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
2869329db04f13480ccdff013dcc00cdb96f12a921cWink Saville    @Override
287d08c8ddcf7bab2beaf212fb7607da15f51ebc09cSvetoslav    public synchronized ISipSession getPendingSession(String callId, String opPackageName) {
288d08c8ddcf7bab2beaf212fb7607da15f51ebc09cSvetoslav        if (!canUseSip(opPackageName, "getPendingSession")) {
289d08c8ddcf7bab2beaf212fb7607da15f51ebc09cSvetoslav            return null;
290d08c8ddcf7bab2beaf212fb7607da15f51ebc09cSvetoslav        }
2919c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        if (callId == null) return null;
2929c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        return mPendingSessions.get(callId);
2939c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    }
2949c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
2959c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    private String determineLocalIp() {
2969c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        try {
2979c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            DatagramSocket s = new DatagramSocket();
2989c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            s.connect(InetAddress.getByName("192.168.1.1"), 80);
2999c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            return s.getLocalAddress().getHostAddress();
3009c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        } catch (IOException e) {
3019329db04f13480ccdff013dcc00cdb96f12a921cWink Saville            if (DBG) loge("determineLocalIp()", e);
3029c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            // dont do anything; there should be a connectivity change going
3039c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            return null;
3049c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
3059c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    }
3069c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
3079c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    private SipSessionGroupExt createGroup(SipProfile localProfile)
3089c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            throws SipException {
3099c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        String key = localProfile.getUriString();
3109c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        SipSessionGroupExt group = mSipGroups.get(key);
3119c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        if (group == null) {
3129c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            group = new SipSessionGroupExt(localProfile, null, null);
3139c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            mSipGroups.put(key, group);
3149c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            notifyProfileAdded(localProfile);
315a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan        } else if (!isCallerCreator(group)) {
316a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan            throw new SipException("only creator can access the profile");
3179c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
3189c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        return group;
3199c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    }
3209c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
3219c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    private SipSessionGroupExt createGroup(SipProfile localProfile,
322845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan            PendingIntent incomingCallPendingIntent,
323845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan            ISipSessionListener listener) throws SipException {
3249c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        String key = localProfile.getUriString();
3259c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        SipSessionGroupExt group = mSipGroups.get(key);
3269c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        if (group != null) {
327a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan            if (!isCallerCreator(group)) {
328a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan                throw new SipException("only creator can access the profile");
329a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan            }
330845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan            group.setIncomingCallPendingIntent(incomingCallPendingIntent);
3319c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            group.setListener(listener);
3329c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        } else {
3339c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            group = new SipSessionGroupExt(localProfile,
334845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan                    incomingCallPendingIntent, listener);
3359c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            mSipGroups.put(key, group);
3369c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            notifyProfileAdded(localProfile);
3379c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
3389c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        return group;
3399c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    }
3409c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
3419c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    private void notifyProfileAdded(SipProfile localProfile) {
3429329db04f13480ccdff013dcc00cdb96f12a921cWink Saville        if (DBG) log("notify: profile added: " + localProfile);
3439c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        Intent intent = new Intent(SipManager.ACTION_SIP_ADD_PHONE);
3449c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        intent.putExtra(SipManager.EXTRA_LOCAL_URI, localProfile.getUriString());
3459c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        mContext.sendBroadcast(intent);
3467d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh        if (mSipGroups.size() == 1) {
3477d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh            registerReceivers();
3487d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh        }
3499c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    }
3509c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
3519c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    private void notifyProfileRemoved(SipProfile localProfile) {
3529329db04f13480ccdff013dcc00cdb96f12a921cWink Saville        if (DBG) log("notify: profile removed: " + localProfile);
3539c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        Intent intent = new Intent(SipManager.ACTION_SIP_REMOVE_PHONE);
3549c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        intent.putExtra(SipManager.EXTRA_LOCAL_URI, localProfile.getUriString());
3559c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        mContext.sendBroadcast(intent);
3567d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh        if (mSipGroups.size() == 0) {
3577d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh            unregisterReceivers();
3589c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
3599c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    }
3609c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
361469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang    private void stopPortMappingMeasurement() {
3629329db04f13480ccdff013dcc00cdb96f12a921cWink Saville        if (mSipKeepAliveProcessCallback != null) {
3639329db04f13480ccdff013dcc00cdb96f12a921cWink Saville            mSipKeepAliveProcessCallback.stop();
3649329db04f13480ccdff013dcc00cdb96f12a921cWink Saville            mSipKeepAliveProcessCallback = null;
365469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang        }
366469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang    }
367469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang
3688a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan    private void startPortMappingLifetimeMeasurement(
3698a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan            SipProfile localProfile) {
370cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan        startPortMappingLifetimeMeasurement(localProfile,
371cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan                DEFAULT_MAX_KEEPALIVE_INTERVAL);
37244ccfb03bb349a90546ddb3dc0063cbf4aaddaf1Hung-ying Tyan    }
37344ccfb03bb349a90546ddb3dc0063cbf4aaddaf1Hung-ying Tyan
37444ccfb03bb349a90546ddb3dc0063cbf4aaddaf1Hung-ying Tyan    private void startPortMappingLifetimeMeasurement(
37544ccfb03bb349a90546ddb3dc0063cbf4aaddaf1Hung-ying Tyan            SipProfile localProfile, int maxInterval) {
3769329db04f13480ccdff013dcc00cdb96f12a921cWink Saville        if ((mSipKeepAliveProcessCallback == null)
3778a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                && (mKeepAliveInterval == -1)
3788a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                && isBehindNAT(mLocalIp)) {
3799329db04f13480ccdff013dcc00cdb96f12a921cWink Saville            if (DBG) log("startPortMappingLifetimeMeasurement: profile="
3808a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                    + localProfile.getUriString());
3818a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan
382cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan            int minInterval = mLastGoodKeepAliveInterval;
383cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan            if (minInterval >= maxInterval) {
384cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan                // If mLastGoodKeepAliveInterval also does not work, reset it
385cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan                // to the default min
386cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan                minInterval = mLastGoodKeepAliveInterval
387cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan                        = DEFAULT_KEEPALIVE_INTERVAL;
3889329db04f13480ccdff013dcc00cdb96f12a921cWink Saville                log("  reset min interval to " + minInterval);
389cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan            }
3909329db04f13480ccdff013dcc00cdb96f12a921cWink Saville            mSipKeepAliveProcessCallback = new SipKeepAliveProcessCallback(
391cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan                    localProfile, minInterval, maxInterval);
3929329db04f13480ccdff013dcc00cdb96f12a921cWink Saville            mSipKeepAliveProcessCallback.start();
3938a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan        }
394469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang    }
395469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang
39644ccfb03bb349a90546ddb3dc0063cbf4aaddaf1Hung-ying Tyan    private void restartPortMappingLifetimeMeasurement(
39744ccfb03bb349a90546ddb3dc0063cbf4aaddaf1Hung-ying Tyan            SipProfile localProfile, int maxInterval) {
39844ccfb03bb349a90546ddb3dc0063cbf4aaddaf1Hung-ying Tyan        stopPortMappingMeasurement();
39944ccfb03bb349a90546ddb3dc0063cbf4aaddaf1Hung-ying Tyan        mKeepAliveInterval = -1;
40044ccfb03bb349a90546ddb3dc0063cbf4aaddaf1Hung-ying Tyan        startPortMappingLifetimeMeasurement(localProfile, maxInterval);
40144ccfb03bb349a90546ddb3dc0063cbf4aaddaf1Hung-ying Tyan    }
40244ccfb03bb349a90546ddb3dc0063cbf4aaddaf1Hung-ying Tyan
4039c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    private synchronized void addPendingSession(ISipSession session) {
4049c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        try {
4053f4d44657ccad3ed02ed0e1354387b14b07dc011Hung-ying Tyan            cleanUpPendingSessions();
4069c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            mPendingSessions.put(session.getCallId(), session);
4079329db04f13480ccdff013dcc00cdb96f12a921cWink Saville            if (DBG) log("#pending sess=" + mPendingSessions.size());
4089c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        } catch (RemoteException e) {
4099c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            // should not happen with a local call
4109329db04f13480ccdff013dcc00cdb96f12a921cWink Saville            loge("addPendingSession()", e);
4119c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
4129c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    }
4139c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
4143f4d44657ccad3ed02ed0e1354387b14b07dc011Hung-ying Tyan    private void cleanUpPendingSessions() throws RemoteException {
4153f4d44657ccad3ed02ed0e1354387b14b07dc011Hung-ying Tyan        Map.Entry<String, ISipSession>[] entries =
4163f4d44657ccad3ed02ed0e1354387b14b07dc011Hung-ying Tyan                mPendingSessions.entrySet().toArray(
4173f4d44657ccad3ed02ed0e1354387b14b07dc011Hung-ying Tyan                new Map.Entry[mPendingSessions.size()]);
4183f4d44657ccad3ed02ed0e1354387b14b07dc011Hung-ying Tyan        for (Map.Entry<String, ISipSession> entry : entries) {
4193f4d44657ccad3ed02ed0e1354387b14b07dc011Hung-ying Tyan            if (entry.getValue().getState() != SipSession.State.INCOMING_CALL) {
4203f4d44657ccad3ed02ed0e1354387b14b07dc011Hung-ying Tyan                mPendingSessions.remove(entry.getKey());
4213f4d44657ccad3ed02ed0e1354387b14b07dc011Hung-ying Tyan            }
4223f4d44657ccad3ed02ed0e1354387b14b07dc011Hung-ying Tyan        }
4233f4d44657ccad3ed02ed0e1354387b14b07dc011Hung-ying Tyan    }
4243f4d44657ccad3ed02ed0e1354387b14b07dc011Hung-ying Tyan
425ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan    private synchronized boolean callingSelf(SipSessionGroupExt ringingGroup,
426ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan            SipSessionGroup.SipSessionImpl ringingSession) {
427ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan        String callId = ringingSession.getCallId();
428ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan        for (SipSessionGroupExt group : mSipGroups.values()) {
429ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan            if ((group != ringingGroup) && group.containsSession(callId)) {
4309329db04f13480ccdff013dcc00cdb96f12a921cWink Saville                if (DBG) log("call self: "
431ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan                        + ringingSession.getLocalProfile().getUriString()
432ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan                        + " -> " + group.getLocalProfile().getUriString());
433ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan                return true;
434ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan            }
435ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan        }
436ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan        return false;
437ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan    }
438ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan
4398a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan    private synchronized void onKeepAliveIntervalChanged() {
4408a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan        for (SipSessionGroupExt group : mSipGroups.values()) {
4418a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan            group.onKeepAliveIntervalChanged();
4428a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan        }
4438a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan    }
4448a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan
4458a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan    private int getKeepAliveInterval() {
4468a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan        return (mKeepAliveInterval < 0)
447cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan                ? mLastGoodKeepAliveInterval
4488a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                : mKeepAliveInterval;
4498a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan    }
4508a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan
4518a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan    private boolean isBehindNAT(String address) {
4528a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan        try {
4539329db04f13480ccdff013dcc00cdb96f12a921cWink Saville            // TODO: How is isBehindNAT used and why these constanst address:
4549329db04f13480ccdff013dcc00cdb96f12a921cWink Saville            //       10.x.x.x | 192.168.x.x | 172.16.x.x .. 172.19.x.x
4558a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan            byte[] d = InetAddress.getByName(address).getAddress();
4568a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan            if ((d[0] == 10) ||
4579329db04f13480ccdff013dcc00cdb96f12a921cWink Saville                    (((0x000000FF & d[0]) == 172) &&
4589329db04f13480ccdff013dcc00cdb96f12a921cWink Saville                    ((0x000000F0 & d[1]) == 16)) ||
4599329db04f13480ccdff013dcc00cdb96f12a921cWink Saville                    (((0x000000FF & d[0]) == 192) &&
4609329db04f13480ccdff013dcc00cdb96f12a921cWink Saville                    ((0x000000FF & d[1]) == 168))) {
4618a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                return true;
4628a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan            }
4638a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan        } catch (UnknownHostException e) {
4649329db04f13480ccdff013dcc00cdb96f12a921cWink Saville            loge("isBehindAT()" + address, e);
4658a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan        }
4668a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan        return false;
4678a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan    }
468ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan
469d08c8ddcf7bab2beaf212fb7607da15f51ebc09cSvetoslav    private boolean canUseSip(String packageName, String message) {
470d08c8ddcf7bab2beaf212fb7607da15f51ebc09cSvetoslav        mContext.enforceCallingOrSelfPermission(
471d08c8ddcf7bab2beaf212fb7607da15f51ebc09cSvetoslav                android.Manifest.permission.USE_SIP, message);
472d08c8ddcf7bab2beaf212fb7607da15f51ebc09cSvetoslav
473d08c8ddcf7bab2beaf212fb7607da15f51ebc09cSvetoslav        return mAppOps.noteOp(AppOpsManager.OP_USE_SIP, Binder.getCallingUid(),
474d08c8ddcf7bab2beaf212fb7607da15f51ebc09cSvetoslav                packageName) == AppOpsManager.MODE_ALLOWED;
475d08c8ddcf7bab2beaf212fb7607da15f51ebc09cSvetoslav    }
476d08c8ddcf7bab2beaf212fb7607da15f51ebc09cSvetoslav
4779c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    private class SipSessionGroupExt extends SipSessionAdapter {
4789329db04f13480ccdff013dcc00cdb96f12a921cWink Saville        private static final String SSGE_TAG = "SipSessionGroupExt";
4799329db04f13480ccdff013dcc00cdb96f12a921cWink Saville        private static final boolean SSGE_DBG = true;
4809c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        private SipSessionGroup mSipGroup;
481845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan        private PendingIntent mIncomingCallPendingIntent;
482617479363dcafe01bfa1fa025e1d9d122864a0ceHung-ying Tyan        private boolean mOpenedToReceiveCalls;
4839c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
4849329db04f13480ccdff013dcc00cdb96f12a921cWink Saville        private SipAutoReg mAutoRegistration =
4859329db04f13480ccdff013dcc00cdb96f12a921cWink Saville                new SipAutoReg();
4869c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
4879c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        public SipSessionGroupExt(SipProfile localProfile,
488845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan                PendingIntent incomingCallPendingIntent,
4899c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                ISipSessionListener listener) throws SipException {
4909329db04f13480ccdff013dcc00cdb96f12a921cWink Saville            if (SSGE_DBG) log("SipSessionGroupExt: profile=" + localProfile);
4911b5111f16c1401437d577dfd547af10aa691d44fChia-chi Yeh            mSipGroup = new SipSessionGroup(duplicate(localProfile),
4921b5111f16c1401437d577dfd547af10aa691d44fChia-chi Yeh                    localProfile.getPassword(), mTimer, mMyWakeLock);
493845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan            mIncomingCallPendingIntent = incomingCallPendingIntent;
4949c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            mAutoRegistration.setListener(listener);
4959c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
4969c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
4979c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        public SipProfile getLocalProfile() {
4989c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            return mSipGroup.getLocalProfile();
4999c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
5009c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
501ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan        public boolean containsSession(String callId) {
502ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan            return mSipGroup.containsSession(callId);
503ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan        }
504ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan
5058a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan        public void onKeepAliveIntervalChanged() {
5068a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan            mAutoRegistration.onKeepAliveIntervalChanged();
5078a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan        }
5088a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan
5098a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan        // TODO: remove this method once SipWakeupTimer can better handle variety
5108a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan        // of timeout values
5118a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan        void setWakeupTimer(SipWakeupTimer timer) {
5128a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan            mSipGroup.setWakeupTimer(timer);
5138a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan        }
5148a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan
5159c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        private SipProfile duplicate(SipProfile p) {
5169c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            try {
5179c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                return new SipProfile.Builder(p).setPassword("*").build();
5189c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            } catch (Exception e) {
5199329db04f13480ccdff013dcc00cdb96f12a921cWink Saville                loge("duplicate()", e);
5209c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                throw new RuntimeException("duplicate profile", e);
5219c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            }
5229c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
5239c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
5249c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        public void setListener(ISipSessionListener listener) {
5259c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            mAutoRegistration.setListener(listener);
5269c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
5279c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
528845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan        public void setIncomingCallPendingIntent(PendingIntent pIntent) {
529845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan            mIncomingCallPendingIntent = pIntent;
5309c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
5319c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
532226ac3ad92a383436a13da89959178d51a0cec1bSantos Cordon        public void openToReceiveCalls() {
533617479363dcafe01bfa1fa025e1d9d122864a0ceHung-ying Tyan            mOpenedToReceiveCalls = true;
5347d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh            if (mNetworkType != -1) {
5359c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                mSipGroup.openToReceiveCalls(this);
5369c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                mAutoRegistration.start(mSipGroup);
5379c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            }
538226ac3ad92a383436a13da89959178d51a0cec1bSantos Cordon            if (SSGE_DBG) log("openToReceiveCalls: " + obfuscateSipUri(getUri()) + ": "
539845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan                    + mIncomingCallPendingIntent);
5409c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
5419c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
5429c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        public void onConnectivityChanged(boolean connected)
5439c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                throws SipException {
5449329db04f13480ccdff013dcc00cdb96f12a921cWink Saville            if (SSGE_DBG) {
5459329db04f13480ccdff013dcc00cdb96f12a921cWink Saville                log("onConnectivityChanged: connected=" + connected + " uri="
546226ac3ad92a383436a13da89959178d51a0cec1bSantos Cordon                    + obfuscateSipUri(getUri()) + ": " + mIncomingCallPendingIntent);
5479329db04f13480ccdff013dcc00cdb96f12a921cWink Saville            }
5489c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            mSipGroup.onConnectivityChanged();
5499c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            if (connected) {
5501b5111f16c1401437d577dfd547af10aa691d44fChia-chi Yeh                mSipGroup.reset();
551617479363dcafe01bfa1fa025e1d9d122864a0ceHung-ying Tyan                if (mOpenedToReceiveCalls) openToReceiveCalls();
5529c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            } else {
5539c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                mSipGroup.close();
5549c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                mAutoRegistration.stop();
5559c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            }
5569c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
5579c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
5589c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        public void close() {
559617479363dcafe01bfa1fa025e1d9d122864a0ceHung-ying Tyan            mOpenedToReceiveCalls = false;
5609c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            mSipGroup.close();
5619c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            mAutoRegistration.stop();
562226ac3ad92a383436a13da89959178d51a0cec1bSantos Cordon            if (SSGE_DBG) log("close: " + obfuscateSipUri(getUri()) + ": "
563226ac3ad92a383436a13da89959178d51a0cec1bSantos Cordon                    + mIncomingCallPendingIntent);
5649c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
5659c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
5669c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        public ISipSession createSession(ISipSessionListener listener) {
5679329db04f13480ccdff013dcc00cdb96f12a921cWink Saville            if (SSGE_DBG) log("createSession");
5689c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            return mSipGroup.createSession(listener);
5699c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
5709c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
5719c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        @Override
572845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan        public void onRinging(ISipSession s, SipProfile caller,
5739c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                String sessionDescription) {
574845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan            SipSessionGroup.SipSessionImpl session =
575845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan                    (SipSessionGroup.SipSessionImpl) s;
5769c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            synchronized (SipService.this) {
5779c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                try {
578ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan                    if (!isRegistered() || callingSelf(this, session)) {
5799329db04f13480ccdff013dcc00cdb96f12a921cWink Saville                        if (SSGE_DBG) log("onRinging: end notReg or self");
5809c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                        session.endCall();
5819c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                        return;
5829c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                    }
5839c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
5849c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                    // send out incoming call broadcast
5859c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                    addPendingSession(session);
5869c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                    Intent intent = SipManager.createIncomingCallBroadcast(
587845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan                            session.getCallId(), sessionDescription);
5889329db04f13480ccdff013dcc00cdb96f12a921cWink Saville                    if (SSGE_DBG) log("onRinging: uri=" + getUri() + ": "
5899c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                            + caller.getUri() + ": " + session.getCallId()
590845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan                            + " " + mIncomingCallPendingIntent);
591845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan                    mIncomingCallPendingIntent.send(mContext,
592845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan                            SipManager.INCOMING_CALL_RESULT_CODE, intent);
593845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan                } catch (PendingIntent.CanceledException e) {
5949329db04f13480ccdff013dcc00cdb96f12a921cWink Saville                    loge("onRinging: pendingIntent is canceled, drop incoming call", e);
595845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan                    session.endCall();
5969c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                }
5979c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            }
5989c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
5999c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
6009c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        @Override
6019c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        public void onError(ISipSession session, int errorCode,
6029c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                String message) {
6039329db04f13480ccdff013dcc00cdb96f12a921cWink Saville            if (SSGE_DBG) log("onError: errorCode=" + errorCode + " desc="
6049c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                    + SipErrorCode.toString(errorCode) + ": " + message);
6059c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
6069c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
607617479363dcafe01bfa1fa025e1d9d122864a0ceHung-ying Tyan        public boolean isOpenedToReceiveCalls() {
608617479363dcafe01bfa1fa025e1d9d122864a0ceHung-ying Tyan            return mOpenedToReceiveCalls;
6099c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
6109c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
6119c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        public boolean isRegistered() {
6129c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            return mAutoRegistration.isRegistered();
6139c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
6149c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
6159c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        private String getUri() {
6169c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            return mSipGroup.getLocalProfileUri();
6179c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
6189329db04f13480ccdff013dcc00cdb96f12a921cWink Saville
6199329db04f13480ccdff013dcc00cdb96f12a921cWink Saville        private void log(String s) {
6209329db04f13480ccdff013dcc00cdb96f12a921cWink Saville            Rlog.d(SSGE_TAG, s);
6219329db04f13480ccdff013dcc00cdb96f12a921cWink Saville        }
6229329db04f13480ccdff013dcc00cdb96f12a921cWink Saville
6239329db04f13480ccdff013dcc00cdb96f12a921cWink Saville        private void loge(String s, Throwable t) {
6249329db04f13480ccdff013dcc00cdb96f12a921cWink Saville            Rlog.e(SSGE_TAG, s, t);
6259329db04f13480ccdff013dcc00cdb96f12a921cWink Saville        }
6269329db04f13480ccdff013dcc00cdb96f12a921cWink Saville
6279c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    }
6289c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
6299329db04f13480ccdff013dcc00cdb96f12a921cWink Saville    private class SipKeepAliveProcessCallback implements Runnable,
6308a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan            SipSessionGroup.KeepAliveProcessCallback {
6319329db04f13480ccdff013dcc00cdb96f12a921cWink Saville        private static final String SKAI_TAG = "SipKeepAliveProcessCallback";
6329329db04f13480ccdff013dcc00cdb96f12a921cWink Saville        private static final boolean SKAI_DBG = true;
6337d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan        private static final int MIN_INTERVAL = 5; // in seconds
6348a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan        private static final int PASS_THRESHOLD = 10;
6357d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan        private static final int NAT_MEASUREMENT_RETRY_INTERVAL = 120; // in seconds
63637f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh        private SipProfile mLocalProfile;
637469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang        private SipSessionGroupExt mGroup;
638469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang        private SipSessionGroup.SipSessionImpl mSession;
639cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan        private int mMinInterval;
64044ccfb03bb349a90546ddb3dc0063cbf4aaddaf1Hung-ying Tyan        private int mMaxInterval;
64144ccfb03bb349a90546ddb3dc0063cbf4aaddaf1Hung-ying Tyan        private int mInterval;
64237f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh        private int mPassCount;
64344ccfb03bb349a90546ddb3dc0063cbf4aaddaf1Hung-ying Tyan
6449329db04f13480ccdff013dcc00cdb96f12a921cWink Saville        public SipKeepAliveProcessCallback(SipProfile localProfile,
645cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan                int minInterval, int maxInterval) {
646cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan            mMaxInterval = maxInterval;
647cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan            mMinInterval = minInterval;
64837f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh            mLocalProfile = localProfile;
649469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang        }
650469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang
651469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang        public void start() {
6528a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan            synchronized (SipService.this) {
65337f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh                if (mSession != null) {
65437f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh                    return;
6557d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan                }
65637f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh
65737f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh                mInterval = (mMaxInterval + mMinInterval) / 2;
65837f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh                mPassCount = 0;
65937f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh
66037f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh                // Don't start measurement if the interval is too small
66137f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh                if (mInterval < DEFAULT_KEEPALIVE_INTERVAL || checkTermination()) {
6629329db04f13480ccdff013dcc00cdb96f12a921cWink Saville                    if (SKAI_DBG) log("start: measurement aborted; interval=[" +
66337f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh                            mMinInterval + "," + mMaxInterval + "]");
66437f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh                    return;
66537f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh                }
66637f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh
6678a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                try {
6689329db04f13480ccdff013dcc00cdb96f12a921cWink Saville                    if (SKAI_DBG) log("start: interval=" + mInterval);
66937f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh
67037f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh                    mGroup = new SipSessionGroupExt(mLocalProfile, null, null);
67137f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh                    // TODO: remove this line once SipWakeupTimer can better handle
67237f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh                    // variety of timeout values
67337f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh                    mGroup.setWakeupTimer(new SipWakeupTimer(mContext, mExecutor));
67437f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh
67537f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh                    mSession = (SipSessionGroup.SipSessionImpl)
67637f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh                            mGroup.createSession(null);
6778a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                    mSession.startKeepAliveProcess(mInterval, this);
67837f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh                } catch (Throwable t) {
67937f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh                    onError(SipErrorCode.CLIENT_ERROR, t.toString());
6808a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                }
6818a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan            }
682469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang        }
683469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang
684469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang        public void stop() {
6858a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan            synchronized (SipService.this) {
6867d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan                if (mSession != null) {
6877d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan                    mSession.stopKeepAliveProcess();
6887d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan                    mSession = null;
6897d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan                }
69037f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh                if (mGroup != null) {
69137f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh                    mGroup.close();
69237f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh                    mGroup = null;
69337f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh                }
6947d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan                mTimer.cancel(this);
6959329db04f13480ccdff013dcc00cdb96f12a921cWink Saville                if (SKAI_DBG) log("stop");
696469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang            }
697469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang        }
698469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang
6998a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan        private void restart() {
700469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang            synchronized (SipService.this) {
7017d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan                // Return immediately if the measurement process is stopped
7027d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan                if (mSession == null) return;
7037d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan
7049329db04f13480ccdff013dcc00cdb96f12a921cWink Saville                if (SKAI_DBG) log("restart: interval=" + mInterval);
705469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang                try {
7068a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                    mSession.stopKeepAliveProcess();
7077d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan                    mPassCount = 0;
7088a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                    mSession.startKeepAliveProcess(mInterval, this);
7098a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                } catch (SipException e) {
7109329db04f13480ccdff013dcc00cdb96f12a921cWink Saville                    loge("restart", e);
711469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang                }
712469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang            }
713469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang        }
714469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang
715cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan        private boolean checkTermination() {
716cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan            return ((mMaxInterval - mMinInterval) < MIN_INTERVAL);
717cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan        }
718cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan
7198a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan        // SipSessionGroup.KeepAliveProcessCallback
7208a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan        @Override
7218a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan        public void onResponse(boolean portChanged) {
7229c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            synchronized (SipService.this) {
7238a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                if (!portChanged) {
72444ccfb03bb349a90546ddb3dc0063cbf4aaddaf1Hung-ying Tyan                    if (++mPassCount != PASS_THRESHOLD) return;
7258a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                    // update the interval, since the current interval is good to
7268a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                    // keep the port mapping.
727cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan                    if (mKeepAliveInterval > 0) {
728cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan                        mLastGoodKeepAliveInterval = mKeepAliveInterval;
729cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan                    }
7308a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                    mKeepAliveInterval = mMinInterval = mInterval;
7319329db04f13480ccdff013dcc00cdb96f12a921cWink Saville                    if (SKAI_DBG) {
7329329db04f13480ccdff013dcc00cdb96f12a921cWink Saville                        log("onResponse: portChanged=" + portChanged + " mKeepAliveInterval="
7338a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                                + mKeepAliveInterval);
734257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan                    }
7358a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                    onKeepAliveIntervalChanged();
7368a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                } else {
7378a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                    // Since the rport is changed, shorten the interval.
7388a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                    mMaxInterval = mInterval;
7398a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                }
740cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan                if (checkTermination()) {
7418a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                    // update mKeepAliveInterval and stop measurement.
7428a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                    stop();
743cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan                    // If all the measurements failed, we still set it to
744cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan                    // mMinInterval; If mMinInterval still doesn't work, a new
745cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan                    // measurement with min interval=DEFAULT_KEEPALIVE_INTERVAL
746cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan                    // will be conducted.
7478a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                    mKeepAliveInterval = mMinInterval;
7489329db04f13480ccdff013dcc00cdb96f12a921cWink Saville                    if (SKAI_DBG) {
7499329db04f13480ccdff013dcc00cdb96f12a921cWink Saville                        log("onResponse: checkTermination mKeepAliveInterval="
7508a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                                + mKeepAliveInterval);
751469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang                    }
7528a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                } else {
7538a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                    // calculate the new interval and continue.
7548a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                    mInterval = (mMaxInterval + mMinInterval) / 2;
7559329db04f13480ccdff013dcc00cdb96f12a921cWink Saville                    if (SKAI_DBG) {
7569329db04f13480ccdff013dcc00cdb96f12a921cWink Saville                        log("onResponse: mKeepAliveInterval=" + mKeepAliveInterval
7579329db04f13480ccdff013dcc00cdb96f12a921cWink Saville                                + ", new mInterval=" + mInterval);
7588a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                    }
7598a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                    restart();
7609c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                }
7619c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            }
7629c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
7639c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
7648a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan        // SipSessionGroup.KeepAliveProcessCallback
7658a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan        @Override
7668a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan        public void onError(int errorCode, String description) {
7679329db04f13480ccdff013dcc00cdb96f12a921cWink Saville            if (SKAI_DBG) loge("onError: errorCode=" + errorCode + " desc=" + description);
7687d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan            restartLater();
7697d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan        }
7707d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan
7717d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan        // timeout handler
7727d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan        @Override
7737d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan        public void run() {
7747d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan            mTimer.cancel(this);
7757d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan            restart();
7767d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan        }
7777d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan
7787d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan        private void restartLater() {
7798a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan            synchronized (SipService.this) {
7807d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan                int interval = NAT_MEASUREMENT_RETRY_INTERVAL;
7817d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan                mTimer.cancel(this);
7827d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan                mTimer.set(interval * 1000, this);
7838a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan            }
7849c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
7859329db04f13480ccdff013dcc00cdb96f12a921cWink Saville
7869329db04f13480ccdff013dcc00cdb96f12a921cWink Saville        private void log(String s) {
7879329db04f13480ccdff013dcc00cdb96f12a921cWink Saville            Rlog.d(SKAI_TAG, s);
7889329db04f13480ccdff013dcc00cdb96f12a921cWink Saville        }
7899329db04f13480ccdff013dcc00cdb96f12a921cWink Saville
7909329db04f13480ccdff013dcc00cdb96f12a921cWink Saville        private void loge(String s) {
7919329db04f13480ccdff013dcc00cdb96f12a921cWink Saville            Rlog.d(SKAI_TAG, s);
7929329db04f13480ccdff013dcc00cdb96f12a921cWink Saville        }
7939329db04f13480ccdff013dcc00cdb96f12a921cWink Saville
7949329db04f13480ccdff013dcc00cdb96f12a921cWink Saville        private void loge(String s, Throwable t) {
7959329db04f13480ccdff013dcc00cdb96f12a921cWink Saville            Rlog.d(SKAI_TAG, s, t);
7969329db04f13480ccdff013dcc00cdb96f12a921cWink Saville        }
7979c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    }
7989c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
7999329db04f13480ccdff013dcc00cdb96f12a921cWink Saville    private class SipAutoReg extends SipSessionAdapter
8008a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan            implements Runnable, SipSessionGroup.KeepAliveProcessCallback {
8019329db04f13480ccdff013dcc00cdb96f12a921cWink Saville        private String SAR_TAG;
8029329db04f13480ccdff013dcc00cdb96f12a921cWink Saville        private static final boolean SAR_DBG = true;
8037d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan        private static final int MIN_KEEPALIVE_SUCCESS_COUNT = 10;
8047d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan
8059c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        private SipSessionGroup.SipSessionImpl mSession;
8068a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan        private SipSessionGroup.SipSessionImpl mKeepAliveSession;
8079c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        private SipSessionListenerProxy mProxy = new SipSessionListenerProxy();
8089c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        private int mBackoff = 1;
8099c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        private boolean mRegistered;
8109c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        private long mExpiryTime;
8119c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        private int mErrorCode;
8129c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        private String mErrorMessage;
813d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan        private boolean mRunning = false;
8149c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
8157d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan        private int mKeepAliveSuccessCount = 0;
8167d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan
8179c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        public void start(SipSessionGroup group) {
818d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan            if (!mRunning) {
819d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan                mRunning = true;
8209c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                mBackoff = 1;
8219c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                mSession = (SipSessionGroup.SipSessionImpl)
8229c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                        group.createSession(this);
8239c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                // return right away if no active network connection.
8249c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                if (mSession == null) return;
8259c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
8269c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                // start unregistration to clear up old registration at server
8279c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                // TODO: when rfc5626 is deployed, use reg-id and sip.instance
8289c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                // in registration to avoid adding duplicate entries to server
829257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan                mMyWakeLock.acquire(mSession);
8309c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                mSession.unregister();
831226ac3ad92a383436a13da89959178d51a0cec1bSantos Cordon                SAR_TAG = "SipAutoReg:" +
832226ac3ad92a383436a13da89959178d51a0cec1bSantos Cordon                        obfuscateSipUri(mSession.getLocalProfile().getUriString());
8339329db04f13480ccdff013dcc00cdb96f12a921cWink Saville                if (SAR_DBG) log("start: group=" + group);
8349c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            }
8359c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
8369c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
8377d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan        private void startKeepAliveProcess(int interval) {
8389329db04f13480ccdff013dcc00cdb96f12a921cWink Saville            if (SAR_DBG) log("startKeepAliveProcess: interval=" + interval);
8397d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan            if (mKeepAliveSession == null) {
8407d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan                mKeepAliveSession = mSession.duplicate();
8417d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan            } else {
8427d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan                mKeepAliveSession.stopKeepAliveProcess();
8437d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan            }
8447d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan            try {
8457d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan                mKeepAliveSession.startKeepAliveProcess(interval, this);
8467d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan            } catch (SipException e) {
8479329db04f13480ccdff013dcc00cdb96f12a921cWink Saville                loge("startKeepAliveProcess: interval=" + interval, e);
8487d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan            }
8497d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan        }
8507d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan
8517d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan        private void stopKeepAliveProcess() {
8527d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan            if (mKeepAliveSession != null) {
8537d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan                mKeepAliveSession.stopKeepAliveProcess();
8547d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan                mKeepAliveSession = null;
8557d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan            }
8567d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan            mKeepAliveSuccessCount = 0;
8577d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan        }
8587d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan
8598a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan        // SipSessionGroup.KeepAliveProcessCallback
8608a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan        @Override
8618a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan        public void onResponse(boolean portChanged) {
8628a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan            synchronized (SipService.this) {
86344ccfb03bb349a90546ddb3dc0063cbf4aaddaf1Hung-ying Tyan                if (portChanged) {
8647d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan                    int interval = getKeepAliveInterval();
8657d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan                    if (mKeepAliveSuccessCount < MIN_KEEPALIVE_SUCCESS_COUNT) {
8669329db04f13480ccdff013dcc00cdb96f12a921cWink Saville                        if (SAR_DBG) {
8679329db04f13480ccdff013dcc00cdb96f12a921cWink Saville                            log("onResponse: keepalive doesn't work with interval "
8689329db04f13480ccdff013dcc00cdb96f12a921cWink Saville                                    + interval + ", past success count="
8699329db04f13480ccdff013dcc00cdb96f12a921cWink Saville                                    + mKeepAliveSuccessCount);
8709329db04f13480ccdff013dcc00cdb96f12a921cWink Saville                        }
8717d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan                        if (interval > DEFAULT_KEEPALIVE_INTERVAL) {
8727d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan                            restartPortMappingLifetimeMeasurement(
8737d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan                                    mSession.getLocalProfile(), interval);
8747d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan                            mKeepAliveSuccessCount = 0;
8757d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan                        }
8767d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan                    } else {
8779329db04f13480ccdff013dcc00cdb96f12a921cWink Saville                        if (SAR_DBG) {
8789329db04f13480ccdff013dcc00cdb96f12a921cWink Saville                            log("keep keepalive going with interval "
87985caf063c027ba0d1defeaff8850e12b6428c4f7Chia-chi Yeh                                    + interval + ", past success count="
88085caf063c027ba0d1defeaff8850e12b6428c4f7Chia-chi Yeh                                    + mKeepAliveSuccessCount);
88185caf063c027ba0d1defeaff8850e12b6428c4f7Chia-chi Yeh                        }
8827d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan                        mKeepAliveSuccessCount /= 2;
8837d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan                    }
88444ccfb03bb349a90546ddb3dc0063cbf4aaddaf1Hung-ying Tyan                } else {
88544ccfb03bb349a90546ddb3dc0063cbf4aaddaf1Hung-ying Tyan                    // Start keep-alive interval measurement on the first
88644ccfb03bb349a90546ddb3dc0063cbf4aaddaf1Hung-ying Tyan                    // successfully kept-alive SipSessionGroup
88744ccfb03bb349a90546ddb3dc0063cbf4aaddaf1Hung-ying Tyan                    startPortMappingLifetimeMeasurement(
88844ccfb03bb349a90546ddb3dc0063cbf4aaddaf1Hung-ying Tyan                            mSession.getLocalProfile());
8897d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan                    mKeepAliveSuccessCount++;
89044ccfb03bb349a90546ddb3dc0063cbf4aaddaf1Hung-ying Tyan                }
8918a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan
8928a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                if (!mRunning || !portChanged) return;
8939dbe2c72276b9968593054dcfd39fd5135a574aaHung-ying Tyan
8949dbe2c72276b9968593054dcfd39fd5135a574aaHung-ying Tyan                // The keep alive process is stopped when port is changed;
8959dbe2c72276b9968593054dcfd39fd5135a574aaHung-ying Tyan                // Nullify the session so that the process can be restarted
8969dbe2c72276b9968593054dcfd39fd5135a574aaHung-ying Tyan                // again when the re-registration is done
8979dbe2c72276b9968593054dcfd39fd5135a574aaHung-ying Tyan                mKeepAliveSession = null;
8989dbe2c72276b9968593054dcfd39fd5135a574aaHung-ying Tyan
8998a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                // Acquire wake lock for the registration process. The
9008a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                // lock will be released when registration is complete.
9018a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                mMyWakeLock.acquire(mSession);
9028a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                mSession.register(EXPIRY_TIME);
9038a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan            }
9048a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan        }
9058a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan
9068a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan        // SipSessionGroup.KeepAliveProcessCallback
9078a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan        @Override
9088a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan        public void onError(int errorCode, String description) {
9099329db04f13480ccdff013dcc00cdb96f12a921cWink Saville            if (SAR_DBG) {
9109329db04f13480ccdff013dcc00cdb96f12a921cWink Saville                loge("onError: errorCode=" + errorCode + " desc=" + description);
91185caf063c027ba0d1defeaff8850e12b6428c4f7Chia-chi Yeh            }
91244ccfb03bb349a90546ddb3dc0063cbf4aaddaf1Hung-ying Tyan            onResponse(true); // re-register immediately
9138a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan        }
9148a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan
9159c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        public void stop() {
916d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan            if (!mRunning) return;
917d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan            mRunning = false;
918257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan            mMyWakeLock.release(mSession);
919257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan            if (mSession != null) {
920257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan                mSession.setListener(null);
9217d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh                if (mNetworkType != -1 && mRegistered) mSession.unregister();
922257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan            }
923d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan
9249c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            mTimer.cancel(this);
9257d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan            stopKeepAliveProcess();
9269c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
927d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan            mRegistered = false;
928d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan            setListener(mProxy.getListener());
9299c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
9309c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
9318a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan        public void onKeepAliveIntervalChanged() {
9328a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan            if (mKeepAliveSession != null) {
9338a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                int newInterval = getKeepAliveInterval();
9349329db04f13480ccdff013dcc00cdb96f12a921cWink Saville                if (SAR_DBG) {
9359329db04f13480ccdff013dcc00cdb96f12a921cWink Saville                    log("onKeepAliveIntervalChanged: interval=" + newInterval);
9368a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                }
9377d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan                mKeepAliveSuccessCount = 0;
9387d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan                startKeepAliveProcess(newInterval);
9398a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan            }
9408a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan        }
9418a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan
9429c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        public void setListener(ISipSessionListener listener) {
9439c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            synchronized (SipService.this) {
9449c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                mProxy.setListener(listener);
9459c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
9469c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                try {
9479c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                    int state = (mSession == null)
9489c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                            ? SipSession.State.READY_TO_CALL
9499c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                            : mSession.getState();
9509c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                    if ((state == SipSession.State.REGISTERING)
9519c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                            || (state == SipSession.State.DEREGISTERING)) {
9529c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                        mProxy.onRegistering(mSession);
9539c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                    } else if (mRegistered) {
9549c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                        int duration = (int)
9559c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                                (mExpiryTime - SystemClock.elapsedRealtime());
9569c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                        mProxy.onRegistrationDone(mSession, duration);
9579c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                    } else if (mErrorCode != SipErrorCode.NO_ERROR) {
9589c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                        if (mErrorCode == SipErrorCode.TIME_OUT) {
9599c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                            mProxy.onRegistrationTimeout(mSession);
9609c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                        } else {
9619c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                            mProxy.onRegistrationFailed(mSession, mErrorCode,
9629c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                                    mErrorMessage);
9639c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                        }
9647d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh                    } else if (mNetworkType == -1) {
965d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan                        mProxy.onRegistrationFailed(mSession,
966d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan                                SipErrorCode.DATA_CONNECTION_LOST,
967d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan                                "no data connection");
968d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan                    } else if (!mRunning) {
969d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan                        mProxy.onRegistrationFailed(mSession,
970d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan                                SipErrorCode.CLIENT_ERROR,
971d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan                                "registration not running");
972d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan                    } else {
973d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan                        mProxy.onRegistrationFailed(mSession,
974d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan                                SipErrorCode.IN_PROGRESS,
975d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan                                String.valueOf(state));
9769c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                    }
9779c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                } catch (Throwable t) {
9789329db04f13480ccdff013dcc00cdb96f12a921cWink Saville                    loge("setListener: ", t);
9799c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                }
9809c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            }
9819c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
9829c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
9839c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        public boolean isRegistered() {
9849c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            return mRegistered;
9859c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
9869c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
987257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan        // timeout handler: re-register
9888a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan        @Override
9899c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        public void run() {
990d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan            synchronized (SipService.this) {
991d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan                if (!mRunning) return;
992d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan
993d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan                mErrorCode = SipErrorCode.NO_ERROR;
994d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan                mErrorMessage = null;
9959329db04f13480ccdff013dcc00cdb96f12a921cWink Saville                if (SAR_DBG) log("run: registering");
9967d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh                if (mNetworkType != -1) {
997257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan                    mMyWakeLock.acquire(mSession);
998257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan                    mSession.register(EXPIRY_TIME);
999257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan                }
10009c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            }
10019c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
10029c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
10039c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        private void restart(int duration) {
10049329db04f13480ccdff013dcc00cdb96f12a921cWink Saville            if (SAR_DBG) log("restart: duration=" + duration + "s later.");
10059c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            mTimer.cancel(this);
10069c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            mTimer.set(duration * 1000, this);
10079c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
10089c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
10099c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        private int backoffDuration() {
10109c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            int duration = SHORT_EXPIRY_TIME * mBackoff;
10119c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            if (duration > 3600) {
10129c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                duration = 3600;
10139c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            } else {
10149c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                mBackoff *= 2;
10159c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            }
10169c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            return duration;
10179c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
10189c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
10199c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        @Override
10209c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        public void onRegistering(ISipSession session) {
10219329db04f13480ccdff013dcc00cdb96f12a921cWink Saville            if (SAR_DBG) log("onRegistering: " + session);
10229c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            synchronized (SipService.this) {
1023d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan                if (notCurrentSession(session)) return;
1024d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan
10259c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                mRegistered = false;
10269c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                mProxy.onRegistering(session);
10279c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            }
10289c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
10299c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
1030d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan        private boolean notCurrentSession(ISipSession session) {
1031d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan            if (session != mSession) {
1032d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan                ((SipSessionGroup.SipSessionImpl) session).setListener(null);
1033257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan                mMyWakeLock.release(session);
1034d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan                return true;
1035d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan            }
1036d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan            return !mRunning;
1037d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan        }
1038d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan
10399c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        @Override
10409c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        public void onRegistrationDone(ISipSession session, int duration) {
10419329db04f13480ccdff013dcc00cdb96f12a921cWink Saville            if (SAR_DBG) log("onRegistrationDone: " + session);
10429c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            synchronized (SipService.this) {
1043d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan                if (notCurrentSession(session)) return;
10449c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
10459c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                mProxy.onRegistrationDone(session, duration);
10469c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
10479c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                if (duration > 0) {
10489c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                    mExpiryTime = SystemClock.elapsedRealtime()
10499c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                            + (duration * 1000);
10509c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
10519c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                    if (!mRegistered) {
10529c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                        mRegistered = true;
10539c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                        // allow some overlap to avoid call drop during renew
10549c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                        duration -= MIN_EXPIRY_TIME;
10559c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                        if (duration < MIN_EXPIRY_TIME) {
10569c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                            duration = MIN_EXPIRY_TIME;
10579c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                        }
10589c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                        restart(duration);
10599c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
10608a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                        SipProfile localProfile = mSession.getLocalProfile();
10618a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                        if ((mKeepAliveSession == null) && (isBehindNAT(mLocalIp)
10628a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan                                || localProfile.getSendKeepAlive())) {
10637d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan                            startKeepAliveProcess(getKeepAliveInterval());
10649c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                        }
10659c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                    }
1066257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan                    mMyWakeLock.release(session);
10679c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                } else {
10689c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                    mRegistered = false;
10699c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                    mExpiryTime = -1L;
10709329db04f13480ccdff013dcc00cdb96f12a921cWink Saville                    if (SAR_DBG) log("Refresh registration immediately");
10719c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                    run();
10729c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                }
10739c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            }
10749c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
10759c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
10769c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        @Override
10779c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        public void onRegistrationFailed(ISipSession session, int errorCode,
10789c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                String message) {
10799329db04f13480ccdff013dcc00cdb96f12a921cWink Saville            if (SAR_DBG) log("onRegistrationFailed: " + session + ": "
10809c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                    + SipErrorCode.toString(errorCode) + ": " + message);
10819c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            synchronized (SipService.this) {
1082d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan                if (notCurrentSession(session)) return;
10839c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
1084fcc474636f42243cfce960158373b9c49636a556Hung-ying Tyan                switch (errorCode) {
1085fcc474636f42243cfce960158373b9c49636a556Hung-ying Tyan                    case SipErrorCode.INVALID_CREDENTIALS:
1086fcc474636f42243cfce960158373b9c49636a556Hung-ying Tyan                    case SipErrorCode.SERVER_UNREACHABLE:
10879329db04f13480ccdff013dcc00cdb96f12a921cWink Saville                        if (SAR_DBG) log("   pause auto-registration");
1088fcc474636f42243cfce960158373b9c49636a556Hung-ying Tyan                        stop();
10890b88a073712b1510db7c636f89c4e19f0131449aHung-ying Tyan                        break;
1090fcc474636f42243cfce960158373b9c49636a556Hung-ying Tyan                    default:
1091fcc474636f42243cfce960158373b9c49636a556Hung-ying Tyan                        restartLater();
10929c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                }
1093d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan
1094d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan                mErrorCode = errorCode;
1095d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan                mErrorMessage = message;
1096d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan                mProxy.onRegistrationFailed(session, errorCode, message);
1097257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan                mMyWakeLock.release(session);
10989c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            }
10999c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
11009c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
11019c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        @Override
11029c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        public void onRegistrationTimeout(ISipSession session) {
11039329db04f13480ccdff013dcc00cdb96f12a921cWink Saville            if (SAR_DBG) log("onRegistrationTimeout: " + session);
11049c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            synchronized (SipService.this) {
1105d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan                if (notCurrentSession(session)) return;
1106d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan
11079c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                mErrorCode = SipErrorCode.TIME_OUT;
11089c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                mProxy.onRegistrationTimeout(session);
1109fcc474636f42243cfce960158373b9c49636a556Hung-ying Tyan                restartLater();
1110257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan                mMyWakeLock.release(session);
11119c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            }
11129c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
11139c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
1114fcc474636f42243cfce960158373b9c49636a556Hung-ying Tyan        private void restartLater() {
11159329db04f13480ccdff013dcc00cdb96f12a921cWink Saville            if (SAR_DBG) loge("restartLater");
11169c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            mRegistered = false;
11179c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            restart(backoffDuration());
11189c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
11199329db04f13480ccdff013dcc00cdb96f12a921cWink Saville
11209329db04f13480ccdff013dcc00cdb96f12a921cWink Saville        private void log(String s) {
11219329db04f13480ccdff013dcc00cdb96f12a921cWink Saville            Rlog.d(SAR_TAG, s);
11229329db04f13480ccdff013dcc00cdb96f12a921cWink Saville        }
11239329db04f13480ccdff013dcc00cdb96f12a921cWink Saville
11249329db04f13480ccdff013dcc00cdb96f12a921cWink Saville        private void loge(String s) {
11259329db04f13480ccdff013dcc00cdb96f12a921cWink Saville            Rlog.e(SAR_TAG, s);
11269329db04f13480ccdff013dcc00cdb96f12a921cWink Saville        }
11279329db04f13480ccdff013dcc00cdb96f12a921cWink Saville
11289329db04f13480ccdff013dcc00cdb96f12a921cWink Saville        private void loge(String s, Throwable e) {
11299329db04f13480ccdff013dcc00cdb96f12a921cWink Saville            Rlog.e(SAR_TAG, s, e);
11309329db04f13480ccdff013dcc00cdb96f12a921cWink Saville        }
11319c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    }
11329c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
11339c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    private class ConnectivityReceiver extends BroadcastReceiver {
11349c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        @Override
113579d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh        public void onReceive(Context context, Intent intent) {
113679d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh            Bundle bundle = intent.getExtras();
113779d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh            if (bundle != null) {
113879d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh                final NetworkInfo info = (NetworkInfo)
113979d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh                        bundle.get(ConnectivityManager.EXTRA_NETWORK_INFO);
11409c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
114179d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh                // Run the handler in MyExecutor to be protected by wake lock
114279d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh                mExecutor.execute(new Runnable() {
11439329db04f13480ccdff013dcc00cdb96f12a921cWink Saville                    @Override
114479d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh                    public void run() {
114579d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh                        onConnectivityChanged(info);
11469c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                    }
114779d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh                });
11489c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            }
11499c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
115079d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh    }
115179d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh
115279d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh    private void registerReceivers() {
115379d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh        mContext.registerReceiver(mConnectivityReceiver,
115479d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh                new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));
11559329db04f13480ccdff013dcc00cdb96f12a921cWink Saville        if (DBG) log("registerReceivers:");
115679d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh    }
11579c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
115879d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh    private void unregisterReceivers() {
115979d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh        mContext.unregisterReceiver(mConnectivityReceiver);
11609329db04f13480ccdff013dcc00cdb96f12a921cWink Saville        if (DBG) log("unregisterReceivers:");
116179d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh
116279d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh        // Reset variables maintained by ConnectivityReceiver.
116379d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh        mWifiLock.release();
11647d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh        mNetworkType = -1;
11657d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh    }
11667d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh
11677d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh    private void updateWakeLocks() {
11687d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh        for (SipSessionGroupExt group : mSipGroups.values()) {
11697d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh            if (group.isOpenedToReceiveCalls()) {
11707d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh                // Also grab the WifiLock when we are disconnected, so the
11717d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh                // system will keep trying to reconnect. It will be released
11727d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh                // when the system eventually connects to something else.
11737d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh                if (mNetworkType == ConnectivityManager.TYPE_WIFI || mNetworkType == -1) {
11747d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh                    mWifiLock.acquire();
11757d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh                } else {
11767d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh                    mWifiLock.release();
11777d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh                }
11787d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh                return;
11797d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh            }
11807d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh        }
11817d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh        mWifiLock.release();
11827d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh        mMyWakeLock.reset(); // in case there's a leak
118379d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh    }
118479d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh
118579d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh    private synchronized void onConnectivityChanged(NetworkInfo info) {
118679d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh        // We only care about the default network, and getActiveNetworkInfo()
118779d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh        // is the only way to distinguish them. However, as broadcasts are
118879d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh        // delivered asynchronously, we might miss DISCONNECTED events from
118979d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh        // getActiveNetworkInfo(), which is critical to our SIP stack. To
119079d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh        // solve this, if it is a DISCONNECTED event to our current network,
119179d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh        // respect it. Otherwise get a new one from getActiveNetworkInfo().
11927d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh        if (info == null || info.isConnected() || info.getType() != mNetworkType) {
11939c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            ConnectivityManager cm = (ConnectivityManager)
11949c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                    mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
119579d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh            info = cm.getActiveNetworkInfo();
11969c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
11979c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
119879d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh        // Some devices limit SIP on Wi-Fi. In this case, if we are not on
119979d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh        // Wi-Fi, treat it as a DISCONNECTED event.
12007d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh        int networkType = (info != null && info.isConnected()) ? info.getType() : -1;
12017d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh        if (mSipOnWifiOnly && networkType != ConnectivityManager.TYPE_WIFI) {
12027d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh            networkType = -1;
12037d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh        }
12049c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
120579d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh        // Ignore the event if the current active network is not changed.
12067d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh        if (mNetworkType == networkType) {
12079329db04f13480ccdff013dcc00cdb96f12a921cWink Saville            // TODO: Maybe we need to send seq/generation number
120879d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh            return;
120979d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh        }
12109329db04f13480ccdff013dcc00cdb96f12a921cWink Saville        if (DBG) {
12119329db04f13480ccdff013dcc00cdb96f12a921cWink Saville            log("onConnectivityChanged: " + mNetworkType +
121279d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh                    " -> " + networkType);
121379d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh        }
12149c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
121579d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh        try {
12167d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh            if (mNetworkType != -1) {
121779d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh                mLocalIp = null;
121879d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh                stopPortMappingMeasurement();
121979d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh                for (SipSessionGroupExt group : mSipGroups.values()) {
122079d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh                    group.onConnectivityChanged(false);
122179d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh                }
12229c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            }
122379d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh            mNetworkType = networkType;
12249c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
12257d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh            if (mNetworkType != -1) {
122679d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh                mLocalIp = determineLocalIp();
122779d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh                mKeepAliveInterval = -1;
122879d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh                mLastGoodKeepAliveInterval = DEFAULT_KEEPALIVE_INTERVAL;
122979d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh                for (SipSessionGroupExt group : mSipGroups.values()) {
123079d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh                    group.onConnectivityChanged(true);
12319c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan                }
12329c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            }
12337d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh            updateWakeLocks();
123479d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh        } catch (SipException e) {
12359329db04f13480ccdff013dcc00cdb96f12a921cWink Saville            loge("onConnectivityChanged()", e);
12369c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
12379c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan    }
12389c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
1239257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan    private static Looper createLooper() {
1240257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan        HandlerThread thread = new HandlerThread("SipService.Executor");
1241257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan        thread.start();
1242257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan        return thread.getLooper();
1243257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan    }
1244257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan
1245257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan    // Executes immediate tasks in a single thread.
1246257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan    // Hold/release wake lock for running tasks
12474cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan    private class MyExecutor extends Handler implements Executor {
12489c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        MyExecutor() {
12499c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            super(createLooper());
12509c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
12519c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
12524cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan        @Override
12534cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan        public void execute(Runnable task) {
1254257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan            mMyWakeLock.acquire(task);
12559c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            Message.obtain(this, 0/* don't care */, task).sendToTarget();
12569c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
12579c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan
12589c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        @Override
12599c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        public void handleMessage(Message msg) {
12609c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            if (msg.obj instanceof Runnable) {
1261257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan                executeInternal((Runnable) msg.obj);
12629c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            } else {
12639329db04f13480ccdff013dcc00cdb96f12a921cWink Saville                if (DBG) log("handleMessage: not Runnable ignore msg=" + msg);
12649c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan            }
12659c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan        }
1266257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan
1267257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan        private void executeInternal(Runnable task) {
1268257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan            try {
1269257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan                task.run();
1270257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan            } catch (Throwable t) {
12719329db04f13480ccdff013dcc00cdb96f12a921cWink Saville                loge("run task: " + task, t);
1272257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan            } finally {
1273257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan                mMyWakeLock.release(task);
1274257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan            }
1275257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan        }
1276257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan    }
12779329db04f13480ccdff013dcc00cdb96f12a921cWink Saville
12789329db04f13480ccdff013dcc00cdb96f12a921cWink Saville    private void log(String s) {
12799329db04f13480ccdff013dcc00cdb96f12a921cWink Saville        Rlog.d(TAG, s);
12809329db04f13480ccdff013dcc00cdb96f12a921cWink Saville    }
12819329db04f13480ccdff013dcc00cdb96f12a921cWink Saville
12829329db04f13480ccdff013dcc00cdb96f12a921cWink Saville    private static void slog(String s) {
12839329db04f13480ccdff013dcc00cdb96f12a921cWink Saville        Rlog.d(TAG, s);
12849329db04f13480ccdff013dcc00cdb96f12a921cWink Saville    }
12859329db04f13480ccdff013dcc00cdb96f12a921cWink Saville
12869329db04f13480ccdff013dcc00cdb96f12a921cWink Saville    private void loge(String s, Throwable e) {
12879329db04f13480ccdff013dcc00cdb96f12a921cWink Saville        Rlog.e(TAG, s, e);
12889329db04f13480ccdff013dcc00cdb96f12a921cWink Saville    }
1289226ac3ad92a383436a13da89959178d51a0cec1bSantos Cordon
1290226ac3ad92a383436a13da89959178d51a0cec1bSantos Cordon    public static String obfuscateSipUri(String sipUri) {
1291226ac3ad92a383436a13da89959178d51a0cec1bSantos Cordon        StringBuilder sb = new StringBuilder();
1292226ac3ad92a383436a13da89959178d51a0cec1bSantos Cordon        int start = 0;
1293226ac3ad92a383436a13da89959178d51a0cec1bSantos Cordon        sipUri = sipUri.trim();
1294226ac3ad92a383436a13da89959178d51a0cec1bSantos Cordon        if (sipUri.startsWith("sip:")) {
1295226ac3ad92a383436a13da89959178d51a0cec1bSantos Cordon            start = 4;
1296226ac3ad92a383436a13da89959178d51a0cec1bSantos Cordon            sb.append("sip:");
1297226ac3ad92a383436a13da89959178d51a0cec1bSantos Cordon        }
1298226ac3ad92a383436a13da89959178d51a0cec1bSantos Cordon
1299226ac3ad92a383436a13da89959178d51a0cec1bSantos Cordon        char prevC = '\0';
1300226ac3ad92a383436a13da89959178d51a0cec1bSantos Cordon        int len = sipUri.length();
1301226ac3ad92a383436a13da89959178d51a0cec1bSantos Cordon        for (int i = start; i < len; i++) {
1302226ac3ad92a383436a13da89959178d51a0cec1bSantos Cordon            char c = sipUri.charAt(i);
1303226ac3ad92a383436a13da89959178d51a0cec1bSantos Cordon            char nextC = (i + 1 < len) ? sipUri.charAt(i + 1) : '\0';
1304226ac3ad92a383436a13da89959178d51a0cec1bSantos Cordon            char charToAppend = '*';
1305226ac3ad92a383436a13da89959178d51a0cec1bSantos Cordon
1306226ac3ad92a383436a13da89959178d51a0cec1bSantos Cordon            // This logic allows the first and last letter before an '@' sign to show up without
1307226ac3ad92a383436a13da89959178d51a0cec1bSantos Cordon            // obfuscation as well as the first and last letter an '@' sign.
1308226ac3ad92a383436a13da89959178d51a0cec1bSantos Cordon            // e.g.: brad@comment.it => b**d@c******.*t
1309226ac3ad92a383436a13da89959178d51a0cec1bSantos Cordon            if ((i - start < 1) ||
1310226ac3ad92a383436a13da89959178d51a0cec1bSantos Cordon                    (i + 1 == len) ||
1311226ac3ad92a383436a13da89959178d51a0cec1bSantos Cordon                    isAllowedCharacter(c) ||
1312226ac3ad92a383436a13da89959178d51a0cec1bSantos Cordon                    (prevC == '@') ||
1313226ac3ad92a383436a13da89959178d51a0cec1bSantos Cordon                    (nextC == '@')) {
1314226ac3ad92a383436a13da89959178d51a0cec1bSantos Cordon                charToAppend = c;
1315226ac3ad92a383436a13da89959178d51a0cec1bSantos Cordon            }
1316226ac3ad92a383436a13da89959178d51a0cec1bSantos Cordon            sb.append(charToAppend);
1317226ac3ad92a383436a13da89959178d51a0cec1bSantos Cordon            prevC = c;
1318226ac3ad92a383436a13da89959178d51a0cec1bSantos Cordon        }
1319226ac3ad92a383436a13da89959178d51a0cec1bSantos Cordon        return sb.toString();
1320226ac3ad92a383436a13da89959178d51a0cec1bSantos Cordon    }
1321226ac3ad92a383436a13da89959178d51a0cec1bSantos Cordon
1322226ac3ad92a383436a13da89959178d51a0cec1bSantos Cordon    private static boolean isAllowedCharacter(char c) {
1323226ac3ad92a383436a13da89959178d51a0cec1bSantos Cordon        return c == '@' || c == '.';
1324226ac3ad92a383436a13da89959178d51a0cec1bSantos Cordon    }
13259c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan}
1326