WifiWatchdogStateMachine.java revision 7f8a12c75cf2b376fce58fc22b5ecb1b64acf110
1654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy/*
2654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy * Copyright (C) 2011 The Android Open Source Project
3654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy *
4654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy * Licensed under the Apache License, Version 2.0 (the "License");
5654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy * you may not use this file except in compliance with the License.
6654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy * You may obtain a copy of the License at
7654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy *
8654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy *      http://www.apache.org/licenses/LICENSE-2.0
9654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy *
10654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy * Unless required by applicable law or agreed to in writing, software
11654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy * distributed under the License is distributed on an "AS IS" BASIS,
12654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy * See the License for the specific language governing permissions and
14654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy * limitations under the License.
15654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy */
16654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
17654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levypackage android.net.wifi;
18654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
19d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levyimport android.app.Notification;
20d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levyimport android.app.NotificationManager;
21d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levyimport android.app.PendingIntent;
22654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levyimport android.content.BroadcastReceiver;
23654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levyimport android.content.ContentResolver;
24654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levyimport android.content.Context;
25654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levyimport android.content.Intent;
26654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levyimport android.content.IntentFilter;
27d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levyimport android.content.res.Resources;
28654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levyimport android.database.ContentObserver;
29654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levyimport android.net.ConnectivityManager;
30654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levyimport android.net.DnsPinger;
31654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levyimport android.net.NetworkInfo;
32654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levyimport android.net.Uri;
33654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levyimport android.os.Message;
34654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levyimport android.os.SystemClock;
354ad39d6ac16961df0e7a3e4b4e7075aaa5202787Isaac Levyimport android.os.SystemProperties;
36654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levyimport android.provider.Settings;
37d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levyimport android.provider.Settings.Secure;
389b2886e24301e5d4e7052ec4a6eaff273d3f516cRobert Greenwaltimport android.util.Log;
39654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
40654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levyimport com.android.internal.util.Protocol;
41654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levyimport com.android.internal.util.State;
42654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levyimport com.android.internal.util.StateMachine;
43654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
44654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levyimport java.io.IOException;
45654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levyimport java.io.PrintWriter;
46654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levyimport java.net.HttpURLConnection;
47d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levyimport java.net.InetAddress;
48654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levyimport java.net.URL;
4979e43f679d6102066ee9eff862912806f53bb0e8Isaac Levyimport java.util.HashMap;
50654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levyimport java.util.HashSet;
51654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levyimport java.util.List;
52654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
53654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy/**
54654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy * {@link WifiWatchdogStateMachine} monitors the initial connection to a Wi-Fi
55654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy * network with multiple access points. After the framework successfully
56654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy * connects to an access point, the watchdog verifies connectivity by 'pinging'
57654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy * the configured DNS server using {@link DnsPinger}.
58654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy * <p>
59654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy * On DNS check failure, the BSSID is blacklisted if it is reasonably likely
60654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy * that another AP might have internet access; otherwise the SSID is disabled.
61654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy * <p>
62654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy * On DNS success, the WatchdogService initiates a walled garden check via an
63654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy * http get. A browser window is activated if a walled garden is detected.
64654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy *
65654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy * @hide
66654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy */
67654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levypublic class WifiWatchdogStateMachine extends StateMachine {
68654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
697f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff    private static final boolean DBG = false;
707f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff    private static final String TAG = "WifiWatchdogStateMachine";
718dc6a1b2823f374a176fb21b8a174664a5f825faIsaac Levy    private static final String WATCHDOG_NOTIFICATION_ID = "Android.System.WifiWatchdog";
72654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
73654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    private static final int WIFI_SIGNAL_LEVELS = 4;
74654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    /**
75654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy     * Low signal is defined as less than or equal to cut off
76654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy     */
77998196d64d35c1767dbb08f059fe3af171e44e1dIrfan Sheriff    private static final int LOW_SIGNAL_CUTOFF = 0;
78654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
79d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy    private static final long DEFAULT_DNS_CHECK_SHORT_INTERVAL_MS = 2 * 60 * 1000;
80998196d64d35c1767dbb08f059fe3af171e44e1dIrfan Sheriff    private static final long DEFAULT_DNS_CHECK_LONG_INTERVAL_MS = 60 * 60 * 1000;
81d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy    private static final long DEFAULT_WALLED_GARDEN_INTERVAL_MS = 30 * 60 * 1000;
82654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
83d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy    private static final int DEFAULT_MAX_SSID_BLACKLISTS = 7;
84998196d64d35c1767dbb08f059fe3af171e44e1dIrfan Sheriff    private static final int DEFAULT_NUM_DNS_PINGS = 5; // Multiple pings to detect setup issues
85998196d64d35c1767dbb08f059fe3af171e44e1dIrfan Sheriff    private static final int DEFAULT_MIN_DNS_RESPONSES = 1;
86654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
8788bae17cfd3de40758c5296d15f012f06f08748aIsaac Levy    private static final int DEFAULT_DNS_PING_TIMEOUT_MS = 2000;
88d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy
89d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy    private static final long DEFAULT_BLACKLIST_FOLLOWUP_INTERVAL_MS = 15 * 1000;
90d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy
9188bae17cfd3de40758c5296d15f012f06f08748aIsaac Levy    // See http://go/clientsdns for usage approval
9288bae17cfd3de40758c5296d15f012f06f08748aIsaac Levy    private static final String DEFAULT_WALLED_GARDEN_URL =
9388bae17cfd3de40758c5296d15f012f06f08748aIsaac Levy            "http://clients3.google.com/generate_204";
9488bae17cfd3de40758c5296d15f012f06f08748aIsaac Levy    private static final int WALLED_GARDEN_SOCKET_TIMEOUT_MS = 10000;
95998196d64d35c1767dbb08f059fe3af171e44e1dIrfan Sheriff    private static final int DNS_INTRATEST_PING_INTERVAL_MS = 200;
96998196d64d35c1767dbb08f059fe3af171e44e1dIrfan Sheriff    /* With some router setups, it takes a few hunder milli-seconds before connection is active */
97998196d64d35c1767dbb08f059fe3af171e44e1dIrfan Sheriff    private static final int DNS_START_DELAY_MS = 1000;
98654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
99654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    private static final int BASE = Protocol.BASE_WIFI_WATCHDOG;
100654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
101654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    /**
102654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy     * Indicates the enable setting of WWS may have changed
103654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy     */
104654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    private static final int EVENT_WATCHDOG_TOGGLED = BASE + 1;
105654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
106654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    /**
107654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy     * Indicates the wifi network state has changed. Passed w/ original intent
108654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy     * which has a non-null networkInfo object
109654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy     */
110654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    private static final int EVENT_NETWORK_STATE_CHANGE = BASE + 2;
111654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    /**
112654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy     * Indicates the signal has changed. Passed with arg1
113654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy     * {@link #mNetEventCounter} and arg2 [raw signal strength]
114654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy     */
115654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    private static final int EVENT_RSSI_CHANGE = BASE + 3;
116654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    private static final int EVENT_SCAN_RESULTS_AVAILABLE = BASE + 4;
117654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    private static final int EVENT_WIFI_RADIO_STATE_CHANGE = BASE + 5;
118d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy    private static final int EVENT_WATCHDOG_SETTINGS_CHANGE = BASE + 6;
119654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
120d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy    private static final int MESSAGE_HANDLE_WALLED_GARDEN = BASE + 100;
121d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy    private static final int MESSAGE_HANDLE_BAD_AP = BASE + 101;
122654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    /**
123654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy     * arg1 == mOnlineWatchState.checkCount
124654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy     */
125654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    private static final int MESSAGE_SINGLE_DNS_CHECK = BASE + 103;
126654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    private static final int MESSAGE_NETWORK_FOLLOWUP = BASE + 104;
127654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
128654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    private Context mContext;
129654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    private ContentResolver mContentResolver;
130654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    private WifiManager mWifiManager;
131654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    private DnsPinger mDnsPinger;
132654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    private IntentFilter mIntentFilter;
133654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    private BroadcastReceiver mBroadcastReceiver;
134654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
135654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    private DefaultState mDefaultState = new DefaultState();
136654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    private WatchdogDisabledState mWatchdogDisabledState = new WatchdogDisabledState();
137654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    private WatchdogEnabledState mWatchdogEnabledState = new WatchdogEnabledState();
138654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    private NotConnectedState mNotConnectedState = new NotConnectedState();
139654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    private ConnectedState mConnectedState = new ConnectedState();
140654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    private DnsCheckingState mDnsCheckingState = new DnsCheckingState();
141654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    private OnlineWatchState mOnlineWatchState = new OnlineWatchState();
142654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    private DnsCheckFailureState mDnsCheckFailureState = new DnsCheckFailureState();
143654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    private WalledGardenState mWalledGardenState = new WalledGardenState();
144654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    private BlacklistedApState mBlacklistedApState = new BlacklistedApState();
145654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
146d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy    private long mDnsCheckShortIntervalMs;
147d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy    private long mDnsCheckLongIntervalMs;
148d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy    private long mWalledGardenIntervalMs;
149d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy    private int mMaxSsidBlacklists;
150d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy    private int mNumDnsPings;
151d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy    private int mMinDnsResponses;
152d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy    private int mDnsPingTimeoutMs;
153d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy    private long mBlacklistFollowupIntervalMs;
154d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy    private boolean mWalledGardenTestEnabled;
155d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy    private String mWalledGardenUrl;
156d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy
157d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy    private boolean mShowDisabledNotification;
158654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    /**
159654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy     * The {@link WifiInfo} object passed to WWSM on network broadcasts
160654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy     */
1618dc6a1b2823f374a176fb21b8a174664a5f825faIsaac Levy    private WifiInfo mConnectionInfo;
162654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    private int mNetEventCounter = 0;
163654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
164654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    /**
165654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy     * Currently maintained but not used, TODO
166654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy     */
167654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    private HashSet<String> mBssids = new HashSet<String>();
168d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy    private int mNumCheckFailures = 0;
169654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
170654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    private Long mLastWalledGardenCheckTime = null;
171654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
172654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    /**
173654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy     * This is set by the blacklisted state and reset when connected to a new AP.
174654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy     * It triggers a disableNetwork call if a DNS check fails.
175654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy     */
176654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    public boolean mDisableAPNextFailure = false;
1779b2886e24301e5d4e7052ec4a6eaff273d3f516cRobert Greenwalt    private static boolean sWifiOnly = false;
1788dc6a1b2823f374a176fb21b8a174664a5f825faIsaac Levy    private boolean mNotificationShown;
1798dc6a1b2823f374a176fb21b8a174664a5f825faIsaac Levy    public boolean mHasConnectedWifiManager = false;
180654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
181654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    /**
182654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy     * STATE MAP
183654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy     *          Default
184654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy     *         /       \
185654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy     * Disabled     Enabled
186654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy     *             /       \
187d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy     * NotConnected      Connected
188654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy     *                  /---------\
189654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy     *               (all other states)
190654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy     */
191654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    private WifiWatchdogStateMachine(Context context) {
1927f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff        super(TAG);
193654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        mContext = context;
194654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        mContentResolver = context.getContentResolver();
195654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
196d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy        mDnsPinger = new DnsPinger(mContext, "WifiWatchdogStateMachine.DnsPinger",
197d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                                this.getHandler().getLooper(), this.getHandler(),
198d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                                ConnectivityManager.TYPE_WIFI);
199654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
200654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        setupNetworkReceiver();
201654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
202654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        // The content observer to listen needs a handler
203654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        registerForSettingsChanges();
204d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy        registerForWatchdogToggle();
205654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        addState(mDefaultState);
206654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            addState(mWatchdogDisabledState, mDefaultState);
207654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            addState(mWatchdogEnabledState, mDefaultState);
208654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                addState(mNotConnectedState, mWatchdogEnabledState);
209654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                addState(mConnectedState, mWatchdogEnabledState);
210654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    addState(mDnsCheckingState, mConnectedState);
211654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    addState(mDnsCheckFailureState, mConnectedState);
212654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    addState(mWalledGardenState, mConnectedState);
213654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    addState(mBlacklistedApState, mConnectedState);
214654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    addState(mOnlineWatchState, mConnectedState);
215654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
216654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        setInitialState(mWatchdogDisabledState);
217d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy        updateSettings();
218654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    }
219654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
220654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    public static WifiWatchdogStateMachine makeWifiWatchdogStateMachine(Context context) {
2214ad39d6ac16961df0e7a3e4b4e7075aaa5202787Isaac Levy        ContentResolver contentResolver = context.getContentResolver();
2229b2886e24301e5d4e7052ec4a6eaff273d3f516cRobert Greenwalt
2239b2886e24301e5d4e7052ec4a6eaff273d3f516cRobert Greenwalt        ConnectivityManager cm = (ConnectivityManager) context.getSystemService(
2249b2886e24301e5d4e7052ec4a6eaff273d3f516cRobert Greenwalt                Context.CONNECTIVITY_SERVICE);
2259b2886e24301e5d4e7052ec4a6eaff273d3f516cRobert Greenwalt        sWifiOnly = (cm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE) == false);
2269b2886e24301e5d4e7052ec4a6eaff273d3f516cRobert Greenwalt
2274ad39d6ac16961df0e7a3e4b4e7075aaa5202787Isaac Levy        // Disable for wifi only devices.
2284ad39d6ac16961df0e7a3e4b4e7075aaa5202787Isaac Levy        if (Settings.Secure.getString(contentResolver, Settings.Secure.WIFI_WATCHDOG_ON) == null &&
2299b2886e24301e5d4e7052ec4a6eaff273d3f516cRobert Greenwalt                sWifiOnly) {
2304ad39d6ac16961df0e7a3e4b4e7075aaa5202787Isaac Levy            putSettingsBoolean(contentResolver, Settings.Secure.WIFI_WATCHDOG_ON, false);
2314ad39d6ac16961df0e7a3e4b4e7075aaa5202787Isaac Levy        }
232654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        WifiWatchdogStateMachine wwsm = new WifiWatchdogStateMachine(context);
233654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        wwsm.start();
234654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        wwsm.sendMessage(EVENT_WATCHDOG_TOGGLED);
235654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        return wwsm;
236654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    }
237654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
238654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    /**
239654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy   *
240654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy   */
241654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    private void setupNetworkReceiver() {
242654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        mBroadcastReceiver = new BroadcastReceiver() {
243654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            @Override
244654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            public void onReceive(Context context, Intent intent) {
245654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                String action = intent.getAction();
246654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
247654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    sendMessage(EVENT_NETWORK_STATE_CHANGE, intent);
248654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                } else if (action.equals(WifiManager.RSSI_CHANGED_ACTION)) {
249654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    obtainMessage(EVENT_RSSI_CHANGE, mNetEventCounter,
250654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                            intent.getIntExtra(WifiManager.EXTRA_NEW_RSSI, -200)).sendToTarget();
251654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                } else if (action.equals(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) {
252654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    sendMessage(EVENT_SCAN_RESULTS_AVAILABLE);
253654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                } else if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) {
254654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    sendMessage(EVENT_WIFI_RADIO_STATE_CHANGE,
255654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                            intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
256654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                                    WifiManager.WIFI_STATE_UNKNOWN));
257654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                }
258654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            }
259654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        };
260654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
261654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        mIntentFilter = new IntentFilter();
262654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        mIntentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
263654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        mIntentFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
264654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        mIntentFilter.addAction(WifiManager.RSSI_CHANGED_ACTION);
265654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        mIntentFilter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
266654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    }
267654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
268654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    /**
269654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy     * Observes the watchdog on/off setting, and takes action when changed.
270654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy     */
271d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy    private void registerForWatchdogToggle() {
272654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        ContentObserver contentObserver = new ContentObserver(this.getHandler()) {
273654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            @Override
274654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            public void onChange(boolean selfChange) {
275654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                sendMessage(EVENT_WATCHDOG_TOGGLED);
276654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            }
277654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        };
278654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
279654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        mContext.getContentResolver().registerContentObserver(
280654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                Settings.Secure.getUriFor(Settings.Secure.WIFI_WATCHDOG_ON),
281654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                false, contentObserver);
282654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    }
283654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
284654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    /**
285d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy     * Observes watchdogs secure setting changes.
286d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy     */
287d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy    private void registerForSettingsChanges() {
288d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy        ContentObserver contentObserver = new ContentObserver(this.getHandler()) {
289d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy            @Override
290d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy            public void onChange(boolean selfChange) {
291d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                sendMessage(EVENT_WATCHDOG_SETTINGS_CHANGE);
292d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy            }
293d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy        };
294d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy
295d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy        mContext.getContentResolver().registerContentObserver(
296d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                Settings.Secure.getUriFor(
297d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                        Settings.Secure.WIFI_WATCHDOG_DNS_CHECK_SHORT_INTERVAL_MS),
298d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                        false, contentObserver);
299d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy        mContext.getContentResolver().registerContentObserver(
300d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                Settings.Secure.getUriFor(Settings.Secure.WIFI_WATCHDOG_DNS_CHECK_LONG_INTERVAL_MS),
301d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                false, contentObserver);
302d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy        mContext.getContentResolver().registerContentObserver(
303d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                Settings.Secure.getUriFor(Settings.Secure.WIFI_WATCHDOG_WALLED_GARDEN_INTERVAL_MS),
304d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                false, contentObserver);
305d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy        mContext.getContentResolver().registerContentObserver(
306d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                Settings.Secure.getUriFor(Settings.Secure.WIFI_WATCHDOG_MAX_SSID_BLACKLISTS),
307d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                false, contentObserver);
308d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy        mContext.getContentResolver().registerContentObserver(
309d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                Settings.Secure.getUriFor(Settings.Secure.WIFI_WATCHDOG_NUM_DNS_PINGS),
310d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                false, contentObserver);
311d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy        mContext.getContentResolver().registerContentObserver(
312d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                Settings.Secure.getUriFor(Settings.Secure.WIFI_WATCHDOG_MIN_DNS_RESPONSES),
313d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                false, contentObserver);
314d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy        mContext.getContentResolver().registerContentObserver(
315d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                Settings.Secure.getUriFor(Settings.Secure.WIFI_WATCHDOG_DNS_PING_TIMEOUT_MS),
316d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                false, contentObserver);
317d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy        mContext.getContentResolver().registerContentObserver(
318d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                Settings.Secure.getUriFor(
319d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                        Settings.Secure.WIFI_WATCHDOG_BLACKLIST_FOLLOWUP_INTERVAL_MS),
320d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                        false, contentObserver);
321d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy        mContext.getContentResolver().registerContentObserver(
322d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                Settings.Secure.getUriFor(Settings.Secure.WIFI_WATCHDOG_WALLED_GARDEN_TEST_ENABLED),
323d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                false, contentObserver);
324d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy        mContext.getContentResolver().registerContentObserver(
325d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                Settings.Secure.getUriFor(Settings.Secure.WIFI_WATCHDOG_WALLED_GARDEN_URL),
326d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                false, contentObserver);
3278dc6a1b2823f374a176fb21b8a174664a5f825faIsaac Levy        mContext.getContentResolver().registerContentObserver(
3288dc6a1b2823f374a176fb21b8a174664a5f825faIsaac Levy                Settings.Secure.getUriFor(Settings.Secure.WIFI_WATCHDOG_SHOW_DISABLED_NETWORK_POPUP)
3298dc6a1b2823f374a176fb21b8a174664a5f825faIsaac Levy                , false, contentObserver);
330d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy    }
331d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy
332d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy    /**
333654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy     * DNS based detection techniques do not work at all hotspots. The one sure
334654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy     * way to check a walled garden is to see if a URL fetch on a known address
335654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy     * fetches the data we expect
336654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy     */
337654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    private boolean isWalledGardenConnection() {
338654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        HttpURLConnection urlConnection = null;
339654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        try {
340d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy            URL url = new URL(mWalledGardenUrl);
341654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            urlConnection = (HttpURLConnection) url.openConnection();
34288bae17cfd3de40758c5296d15f012f06f08748aIsaac Levy            urlConnection.setInstanceFollowRedirects(false);
34388bae17cfd3de40758c5296d15f012f06f08748aIsaac Levy            urlConnection.setConnectTimeout(WALLED_GARDEN_SOCKET_TIMEOUT_MS);
34488bae17cfd3de40758c5296d15f012f06f08748aIsaac Levy            urlConnection.setReadTimeout(WALLED_GARDEN_SOCKET_TIMEOUT_MS);
34588bae17cfd3de40758c5296d15f012f06f08748aIsaac Levy            urlConnection.setUseCaches(false);
34688bae17cfd3de40758c5296d15f012f06f08748aIsaac Levy            urlConnection.getInputStream();
34788bae17cfd3de40758c5296d15f012f06f08748aIsaac Levy            // We got a valid response, but not from the real google
34888bae17cfd3de40758c5296d15f012f06f08748aIsaac Levy            return urlConnection.getResponseCode() != 204;
349654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        } catch (IOException e) {
35088bae17cfd3de40758c5296d15f012f06f08748aIsaac Levy            if (DBG) {
3517f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff                log("Walled garden check - probably not a portal: exception " + e);
35288bae17cfd3de40758c5296d15f012f06f08748aIsaac Levy            }
353654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            return false;
354654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        } finally {
35588bae17cfd3de40758c5296d15f012f06f08748aIsaac Levy            if (urlConnection != null) {
356654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                urlConnection.disconnect();
35788bae17cfd3de40758c5296d15f012f06f08748aIsaac Levy            }
358654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        }
359654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    }
360654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
361654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    private boolean rssiStrengthAboveCutoff(int rssi) {
362654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        return WifiManager.calculateSignalLevel(rssi, WIFI_SIGNAL_LEVELS) > LOW_SIGNAL_CUTOFF;
363654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    }
364654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
365654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    public void dump(PrintWriter pw) {
366654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        pw.print("WatchdogStatus: ");
367654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        pw.print("State " + getCurrentState());
3688dc6a1b2823f374a176fb21b8a174664a5f825faIsaac Levy        pw.println(", network [" + mConnectionInfo + "]");
369d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy        pw.print("checkFailures   " + mNumCheckFailures);
370654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        pw.println(", bssids: " + mBssids);
371654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        pw.println("lastSingleCheck: " + mOnlineWatchState.lastCheckTime);
372654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    }
373654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
374654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    private boolean isWatchdogEnabled() {
375d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy        return getSettingsBoolean(mContentResolver, Settings.Secure.WIFI_WATCHDOG_ON, true);
376654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    }
377654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
378d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy    private void updateSettings() {
379d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy        mDnsCheckShortIntervalMs = Secure.getLong(mContentResolver,
380d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                Secure.WIFI_WATCHDOG_DNS_CHECK_SHORT_INTERVAL_MS,
381d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                DEFAULT_DNS_CHECK_SHORT_INTERVAL_MS);
382d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy        mDnsCheckLongIntervalMs = Secure.getLong(mContentResolver,
383d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                Secure.WIFI_WATCHDOG_DNS_CHECK_LONG_INTERVAL_MS,
384d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                DEFAULT_DNS_CHECK_LONG_INTERVAL_MS);
385d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy        mMaxSsidBlacklists = Secure.getInt(mContentResolver,
386d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                Secure.WIFI_WATCHDOG_MAX_SSID_BLACKLISTS,
387d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                DEFAULT_MAX_SSID_BLACKLISTS);
388d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy        mNumDnsPings = Secure.getInt(mContentResolver,
389d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                Secure.WIFI_WATCHDOG_NUM_DNS_PINGS,
390d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                DEFAULT_NUM_DNS_PINGS);
391d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy        mMinDnsResponses = Secure.getInt(mContentResolver,
392d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                Secure.WIFI_WATCHDOG_MIN_DNS_RESPONSES,
393d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                DEFAULT_MIN_DNS_RESPONSES);
394d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy        mDnsPingTimeoutMs = Secure.getInt(mContentResolver,
395d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                Secure.WIFI_WATCHDOG_DNS_PING_TIMEOUT_MS,
396d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                DEFAULT_DNS_PING_TIMEOUT_MS);
397d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy        mBlacklistFollowupIntervalMs = Secure.getLong(mContentResolver,
398d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                Settings.Secure.WIFI_WATCHDOG_BLACKLIST_FOLLOWUP_INTERVAL_MS,
399d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                DEFAULT_BLACKLIST_FOLLOWUP_INTERVAL_MS);
400d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy        mWalledGardenTestEnabled = getSettingsBoolean(mContentResolver,
401d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                Settings.Secure.WIFI_WATCHDOG_WALLED_GARDEN_TEST_ENABLED, true);
402d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy        mWalledGardenUrl = getSettingsStr(mContentResolver,
403d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                Settings.Secure.WIFI_WATCHDOG_WALLED_GARDEN_URL,
404d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                DEFAULT_WALLED_GARDEN_URL);
405d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy        mWalledGardenIntervalMs = Secure.getLong(mContentResolver,
406d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                Secure.WIFI_WATCHDOG_WALLED_GARDEN_INTERVAL_MS,
407d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                DEFAULT_WALLED_GARDEN_INTERVAL_MS);
4088dc6a1b2823f374a176fb21b8a174664a5f825faIsaac Levy        mShowDisabledNotification = getSettingsBoolean(mContentResolver,
4098dc6a1b2823f374a176fb21b8a174664a5f825faIsaac Levy                Settings.Secure.WIFI_WATCHDOG_SHOW_DISABLED_NETWORK_POPUP, true);
410d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy    }
411654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
412654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    /**
413654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy     * Helper to return wait time left given a min interval and last run
414654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy     *
415654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy     * @param interval minimum wait interval
416654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy     * @param lastTime last time action was performed in
417654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy     *            SystemClock.elapsedRealtime(). Null if never.
418654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy     * @return non negative time to wait
419654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy     */
420654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    private static long waitTime(long interval, Long lastTime) {
421654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        if (lastTime == null)
422654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            return 0;
423654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        long wait = interval + lastTime - SystemClock.elapsedRealtime();
424654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        return wait > 0 ? wait : 0;
425654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    }
426654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
427654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    private static String wifiInfoToStr(WifiInfo wifiInfo) {
428654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        if (wifiInfo == null)
429654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            return "null";
430654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        return "(" + wifiInfo.getSSID() + ", " + wifiInfo.getBSSID() + ")";
431654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    }
432654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
433654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    /**
4348dc6a1b2823f374a176fb21b8a174664a5f825faIsaac Levy     * Uses {@link #mConnectionInfo}.
4358dc6a1b2823f374a176fb21b8a174664a5f825faIsaac Levy     */
4368dc6a1b2823f374a176fb21b8a174664a5f825faIsaac Levy    private void updateBssids() {
4378dc6a1b2823f374a176fb21b8a174664a5f825faIsaac Levy        String curSsid = mConnectionInfo.getSSID();
4388dc6a1b2823f374a176fb21b8a174664a5f825faIsaac Levy        List<ScanResult> results = mWifiManager.getScanResults();
4398dc6a1b2823f374a176fb21b8a174664a5f825faIsaac Levy        int oldNumBssids = mBssids.size();
4408dc6a1b2823f374a176fb21b8a174664a5f825faIsaac Levy
4418dc6a1b2823f374a176fb21b8a174664a5f825faIsaac Levy        if (results == null) {
4428dc6a1b2823f374a176fb21b8a174664a5f825faIsaac Levy            if (DBG) {
4437f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff                log("updateBssids: Got null scan results!");
4448dc6a1b2823f374a176fb21b8a174664a5f825faIsaac Levy            }
4458dc6a1b2823f374a176fb21b8a174664a5f825faIsaac Levy            return;
4468dc6a1b2823f374a176fb21b8a174664a5f825faIsaac Levy        }
4478dc6a1b2823f374a176fb21b8a174664a5f825faIsaac Levy
4488dc6a1b2823f374a176fb21b8a174664a5f825faIsaac Levy        for (ScanResult result : results) {
4498dc6a1b2823f374a176fb21b8a174664a5f825faIsaac Levy            if (result == null || result.SSID == null) {
4508dc6a1b2823f374a176fb21b8a174664a5f825faIsaac Levy                if (DBG) {
4517f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff                    log("Received invalid scan result: " + result);
4528dc6a1b2823f374a176fb21b8a174664a5f825faIsaac Levy                }
4538dc6a1b2823f374a176fb21b8a174664a5f825faIsaac Levy                continue;
4548dc6a1b2823f374a176fb21b8a174664a5f825faIsaac Levy            }
4558dc6a1b2823f374a176fb21b8a174664a5f825faIsaac Levy            if (curSsid.equals(result.SSID))
4568dc6a1b2823f374a176fb21b8a174664a5f825faIsaac Levy                mBssids.add(result.BSSID);
4578dc6a1b2823f374a176fb21b8a174664a5f825faIsaac Levy        }
4588dc6a1b2823f374a176fb21b8a174664a5f825faIsaac Levy    }
4598dc6a1b2823f374a176fb21b8a174664a5f825faIsaac Levy
460654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    private void resetWatchdogState() {
4617f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff        if (DBG) {
4627f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff            log("Resetting watchdog state...");
46388bae17cfd3de40758c5296d15f012f06f08748aIsaac Levy        }
4648dc6a1b2823f374a176fb21b8a174664a5f825faIsaac Levy        mConnectionInfo = null;
465654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        mDisableAPNextFailure = false;
466654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        mLastWalledGardenCheckTime = null;
467d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy        mNumCheckFailures = 0;
468654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        mBssids.clear();
4698dc6a1b2823f374a176fb21b8a174664a5f825faIsaac Levy        cancelNetworkNotification();
470654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    }
471654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
472654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    private void popUpBrowser() {
473654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        Uri uri = Uri.parse("http://www.google.com");
474654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        Intent intent = new Intent(Intent.ACTION_VIEW, uri);
475654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        intent.setFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT |
476654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                Intent.FLAG_ACTIVITY_NEW_TASK);
477654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        mContext.startActivity(intent);
478654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    }
479654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
4808dc6a1b2823f374a176fb21b8a174664a5f825faIsaac Levy    private void displayDisabledNetworkNotification(String ssid) {
481d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy        Resources r = Resources.getSystem();
482d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy        CharSequence title =
483d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                r.getText(com.android.internal.R.string.wifi_watchdog_network_disabled);
4848dc6a1b2823f374a176fb21b8a174664a5f825faIsaac Levy        String msg = ssid +
485d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                r.getText(com.android.internal.R.string.wifi_watchdog_network_disabled_detailed);
486d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy
487d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy        Notification wifiDisabledWarning = new Notification.Builder(mContext)
488d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy            .setSmallIcon(com.android.internal.R.drawable.stat_sys_warning)
489d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy            .setDefaults(Notification.DEFAULT_ALL)
490d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy            .setTicker(title)
491d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy            .setContentTitle(title)
492d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy            .setContentText(msg)
493d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy            .setContentIntent(PendingIntent.getActivity(mContext, 0,
4948dc6a1b2823f374a176fb21b8a174664a5f825faIsaac Levy                    new Intent(WifiManager.ACTION_PICK_WIFI_NETWORK)
495d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                        .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK), 0))
496d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy            .setWhen(System.currentTimeMillis())
497d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy            .setAutoCancel(true)
498d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy            .getNotification();
499d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy
500d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy        NotificationManager notificationManager = (NotificationManager) mContext
501d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                .getSystemService(Context.NOTIFICATION_SERVICE);
502d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy
5038dc6a1b2823f374a176fb21b8a174664a5f825faIsaac Levy        notificationManager.notify(WATCHDOG_NOTIFICATION_ID, 1, wifiDisabledWarning);
5048dc6a1b2823f374a176fb21b8a174664a5f825faIsaac Levy        mNotificationShown = true;
5058dc6a1b2823f374a176fb21b8a174664a5f825faIsaac Levy    }
5068dc6a1b2823f374a176fb21b8a174664a5f825faIsaac Levy
5078dc6a1b2823f374a176fb21b8a174664a5f825faIsaac Levy    public void cancelNetworkNotification() {
5088dc6a1b2823f374a176fb21b8a174664a5f825faIsaac Levy        if (mNotificationShown) {
5098dc6a1b2823f374a176fb21b8a174664a5f825faIsaac Levy            NotificationManager notificationManager = (NotificationManager) mContext
5108dc6a1b2823f374a176fb21b8a174664a5f825faIsaac Levy                    .getSystemService(Context.NOTIFICATION_SERVICE);
5118dc6a1b2823f374a176fb21b8a174664a5f825faIsaac Levy            notificationManager.cancel(WATCHDOG_NOTIFICATION_ID, 1);
5128dc6a1b2823f374a176fb21b8a174664a5f825faIsaac Levy            mNotificationShown = false;
5138dc6a1b2823f374a176fb21b8a174664a5f825faIsaac Levy        }
514654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    }
515654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
516654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    class DefaultState extends State {
517654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        @Override
518654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        public boolean processMessage(Message msg) {
519d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy            switch (msg.what) {
520d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                case EVENT_WATCHDOG_SETTINGS_CHANGE:
521d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                    updateSettings();
5227f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff                    if (DBG) {
5237f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff                        log("Updating wifi-watchdog secure settings");
524d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                    }
525d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                    return HANDLED;
526d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy            }
5277f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff            if (DBG) {
5287f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff                log("Caught message " + msg.what + " in state " +
529654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                        getCurrentState().getName());
530654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            }
531654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            return HANDLED;
532654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        }
533654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    }
534654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
535654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    class WatchdogDisabledState extends State {
536654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        @Override
537654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        public boolean processMessage(Message msg) {
538654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            switch (msg.what) {
539654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                case EVENT_WATCHDOG_TOGGLED:
540654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    if (isWatchdogEnabled())
541654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                        transitionTo(mNotConnectedState);
542654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    return HANDLED;
543654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            }
544654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            return NOT_HANDLED;
545654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        }
546654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    }
547654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
548654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    class WatchdogEnabledState extends State {
549654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        @Override
550654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        public void enter() {
551654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            resetWatchdogState();
552654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            mContext.registerReceiver(mBroadcastReceiver, mIntentFilter);
5537f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff            if (DBG) log("WifiWatchdogService enabled");
554654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        }
555654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
556654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        @Override
557654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        public boolean processMessage(Message msg) {
558654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            switch (msg.what) {
559654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                case EVENT_WATCHDOG_TOGGLED:
560654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    if (!isWatchdogEnabled())
561654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                        transitionTo(mWatchdogDisabledState);
562654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    return HANDLED;
563654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                case EVENT_NETWORK_STATE_CHANGE:
564654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    Intent stateChangeIntent = (Intent) msg.obj;
565654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    NetworkInfo networkInfo = (NetworkInfo)
566654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                            stateChangeIntent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
567654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
568654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    switch (networkInfo.getState()) {
569654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                        case CONNECTED:
5708dc6a1b2823f374a176fb21b8a174664a5f825faIsaac Levy                            cancelNetworkNotification();
57188bae17cfd3de40758c5296d15f012f06f08748aIsaac Levy                            WifiInfo wifiInfo = (WifiInfo)
57288bae17cfd3de40758c5296d15f012f06f08748aIsaac Levy                                stateChangeIntent.getParcelableExtra(WifiManager.EXTRA_WIFI_INFO);
573654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                            if (wifiInfo == null) {
5747f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff                                loge("Connected --> WifiInfo object null!");
575654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                                return HANDLED;
576654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                            }
577654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
578654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                            if (wifiInfo.getSSID() == null || wifiInfo.getBSSID() == null) {
5797f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff                                loge("Received wifiInfo object with null elts: "
580654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                                        + wifiInfoToStr(wifiInfo));
581654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                                return HANDLED;
582654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                            }
583654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
584654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                            initConnection(wifiInfo);
5858dc6a1b2823f374a176fb21b8a174664a5f825faIsaac Levy                            mConnectionInfo = wifiInfo;
5868dc6a1b2823f374a176fb21b8a174664a5f825faIsaac Levy                            updateBssids();
587654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                            transitionTo(mDnsCheckingState);
588654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                            mNetEventCounter++;
58932f04e9009046f72242932bf4e820802148e423aIrfan Sheriff                            break;
59032f04e9009046f72242932bf4e820802148e423aIrfan Sheriff                        default:
591654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                            mNetEventCounter++;
592654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                            transitionTo(mNotConnectedState);
59332f04e9009046f72242932bf4e820802148e423aIrfan Sheriff                            break;
594654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    }
595654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    return HANDLED;
596654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                case EVENT_WIFI_RADIO_STATE_CHANGE:
597654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    if ((Integer) msg.obj == WifiManager.WIFI_STATE_DISABLING) {
5987f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff                        if (DBG) log("WifiStateDisabling -- Resetting WatchdogState");
599654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                        resetWatchdogState();
600654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                        mNetEventCounter++;
601654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                        transitionTo(mNotConnectedState);
602654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    }
603654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    return HANDLED;
604654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            }
605654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
606654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            return NOT_HANDLED;
607654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        }
608654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
609654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        /**
610654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy         * @param wifiInfo Info object with non-null ssid and bssid
611654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy         */
612654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        private void initConnection(WifiInfo wifiInfo) {
6137f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff            if (DBG) {
6147f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff                log("Connected:: old " + wifiInfoToStr(mConnectionInfo) +
615654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                        " ==> new " + wifiInfoToStr(wifiInfo));
616654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            }
617654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
6188dc6a1b2823f374a176fb21b8a174664a5f825faIsaac Levy            if (mConnectionInfo == null || !wifiInfo.getSSID().equals(mConnectionInfo.getSSID())) {
619654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                resetWatchdogState();
6208dc6a1b2823f374a176fb21b8a174664a5f825faIsaac Levy            } else if (!wifiInfo.getBSSID().equals(mConnectionInfo.getBSSID())) {
621654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                mDisableAPNextFailure = false;
622654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            }
623654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        }
624654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
625654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        @Override
626654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        public void exit() {
627654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            mContext.unregisterReceiver(mBroadcastReceiver);
6287f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff            if (DBG) log("WifiWatchdogService disabled");
629654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        }
630654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    }
631654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
632654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    class NotConnectedState extends State {
633654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    }
634654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
635654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    class ConnectedState extends State {
636654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        @Override
637654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        public boolean processMessage(Message msg) {
638654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            switch (msg.what) {
639654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                case EVENT_SCAN_RESULTS_AVAILABLE:
6408dc6a1b2823f374a176fb21b8a174664a5f825faIsaac Levy                    updateBssids();
641654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    return HANDLED;
642d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                case EVENT_WATCHDOG_SETTINGS_CHANGE:
643d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                    // Stop current checks, but let state update
644d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                    transitionTo(mOnlineWatchState);
645d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                    return NOT_HANDLED;
646654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            }
647654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            return NOT_HANDLED;
648654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        }
649654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    }
650654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
651654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    class DnsCheckingState extends State {
65279e43f679d6102066ee9eff862912806f53bb0e8Isaac Levy        List<InetAddress> mDnsList;
65379e43f679d6102066ee9eff862912806f53bb0e8Isaac Levy        int[] dnsCheckSuccesses;
65479e43f679d6102066ee9eff862912806f53bb0e8Isaac Levy        String dnsCheckLogStr;
65579e43f679d6102066ee9eff862912806f53bb0e8Isaac Levy        String[] dnsResponseStrs;
65679e43f679d6102066ee9eff862912806f53bb0e8Isaac Levy        /** Keeps track of active dns pings.  Map is from pingID to index in mDnsList */
65779e43f679d6102066ee9eff862912806f53bb0e8Isaac Levy        HashMap<Integer, Integer> idDnsMap = new HashMap<Integer, Integer>();
658654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
659654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        @Override
660654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        public void enter() {
66179e43f679d6102066ee9eff862912806f53bb0e8Isaac Levy            mDnsList = mDnsPinger.getDnsList();
66279e43f679d6102066ee9eff862912806f53bb0e8Isaac Levy            int numDnses = mDnsList.size();
66379e43f679d6102066ee9eff862912806f53bb0e8Isaac Levy            dnsCheckSuccesses = new int[numDnses];
66479e43f679d6102066ee9eff862912806f53bb0e8Isaac Levy            dnsResponseStrs = new String[numDnses];
66579e43f679d6102066ee9eff862912806f53bb0e8Isaac Levy            for (int i = 0; i < numDnses; i++)
66679e43f679d6102066ee9eff862912806f53bb0e8Isaac Levy                dnsResponseStrs[i] = "";
66779e43f679d6102066ee9eff862912806f53bb0e8Isaac Levy
668654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            if (DBG) {
669d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                dnsCheckLogStr = String.format("Pinging %s on ssid [%s]: ",
67079e43f679d6102066ee9eff862912806f53bb0e8Isaac Levy                        mDnsList, mConnectionInfo.getSSID());
6717f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff                log(dnsCheckLogStr);
672654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            }
673654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
67479e43f679d6102066ee9eff862912806f53bb0e8Isaac Levy            idDnsMap.clear();
675d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy            for (int i=0; i < mNumDnsPings; i++) {
67679e43f679d6102066ee9eff862912806f53bb0e8Isaac Levy                for (int j = 0; j < numDnses; j++) {
67779e43f679d6102066ee9eff862912806f53bb0e8Isaac Levy                    idDnsMap.put(mDnsPinger.pingDnsAsync(mDnsList.get(j), mDnsPingTimeoutMs,
678998196d64d35c1767dbb08f059fe3af171e44e1dIrfan Sheriff                            DNS_START_DELAY_MS + DNS_INTRATEST_PING_INTERVAL_MS * i), j);
67979e43f679d6102066ee9eff862912806f53bb0e8Isaac Levy                }
680d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy            }
681654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        }
682654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
683654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        @Override
684654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        public boolean processMessage(Message msg) {
685d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy            if (msg.what != DnsPinger.DNS_PING_RESULT) {
686654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                return NOT_HANDLED;
687654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            }
688654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
689d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy            int pingID = msg.arg1;
690d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy            int pingResponseTime = msg.arg2;
691654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
69279e43f679d6102066ee9eff862912806f53bb0e8Isaac Levy            Integer dnsServerId = idDnsMap.get(pingID);
69379e43f679d6102066ee9eff862912806f53bb0e8Isaac Levy            if (dnsServerId == null) {
6947f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff                loge("Received a Dns response with unknown ID!");
695d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                return HANDLED;
696d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy            }
69779e43f679d6102066ee9eff862912806f53bb0e8Isaac Levy
69879e43f679d6102066ee9eff862912806f53bb0e8Isaac Levy            idDnsMap.remove(pingID);
699654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            if (pingResponseTime >= 0)
70079e43f679d6102066ee9eff862912806f53bb0e8Isaac Levy                dnsCheckSuccesses[dnsServerId]++;
701654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
702654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            if (DBG) {
703654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                if (pingResponseTime >= 0) {
70479e43f679d6102066ee9eff862912806f53bb0e8Isaac Levy                    dnsResponseStrs[dnsServerId] += "|" + pingResponseTime;
705654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                } else {
70679e43f679d6102066ee9eff862912806f53bb0e8Isaac Levy                    dnsResponseStrs[dnsServerId] += "|x";
707654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                }
708654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            }
709654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
710654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            /**
711654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy             * After a full ping count, if we have more responses than this
712654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy             * cutoff, the outcome is success; else it is 'failure'.
713654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy             */
714654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
715654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            /**
716654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy             * Our final success count will be at least this big, so we're
717654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy             * guaranteed to succeed.
718654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy             */
71979e43f679d6102066ee9eff862912806f53bb0e8Isaac Levy            if (dnsCheckSuccesses[dnsServerId] >= mMinDnsResponses) {
720654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                // DNS CHECKS OK, NOW WALLED GARDEN
721654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                if (DBG) {
7227f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff                    log(makeLogString() + "  SUCCESS");
723654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                }
724654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
725654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                if (!shouldCheckWalledGarden()) {
726654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    transitionTo(mOnlineWatchState);
727654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    return HANDLED;
728654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                }
729654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
730654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                mLastWalledGardenCheckTime = SystemClock.elapsedRealtime();
731654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                if (isWalledGardenConnection()) {
7327f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff                    if (DBG) log("Walled garden test complete - walled garden detected");
733654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    transitionTo(mWalledGardenState);
734654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                } else {
7357f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff                    if (DBG) log("Walled garden test complete - online");
736654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    transitionTo(mOnlineWatchState);
737654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                }
738654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                return HANDLED;
739654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            }
740654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
74179e43f679d6102066ee9eff862912806f53bb0e8Isaac Levy            if (idDnsMap.isEmpty()) {
742654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                if (DBG) {
7437f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff                    log(makeLogString() + "  FAILURE");
744654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                }
745654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                transitionTo(mDnsCheckFailureState);
746654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                return HANDLED;
747654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            }
748654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
749654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            return HANDLED;
750654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        }
751654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
75279e43f679d6102066ee9eff862912806f53bb0e8Isaac Levy        private String makeLogString() {
75379e43f679d6102066ee9eff862912806f53bb0e8Isaac Levy            String logStr = dnsCheckLogStr;
75479e43f679d6102066ee9eff862912806f53bb0e8Isaac Levy            for (String respStr : dnsResponseStrs)
75579e43f679d6102066ee9eff862912806f53bb0e8Isaac Levy                logStr += " [" + respStr + "]";
75679e43f679d6102066ee9eff862912806f53bb0e8Isaac Levy            return logStr;
75779e43f679d6102066ee9eff862912806f53bb0e8Isaac Levy        }
75879e43f679d6102066ee9eff862912806f53bb0e8Isaac Levy
759d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy        @Override
760d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy        public void exit() {
761d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy            mDnsPinger.cancelPings();
762d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy        }
763d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy
764654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        private boolean shouldCheckWalledGarden() {
765d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy            if (!mWalledGardenTestEnabled) {
7667f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff                if (DBG)
7677f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff                    log("Skipping walled garden check - disabled");
768654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                return false;
769654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            }
770d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy            long waitTime = waitTime(mWalledGardenIntervalMs,
771654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    mLastWalledGardenCheckTime);
772654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            if (waitTime > 0) {
773654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                if (DBG) {
7747f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff                    log("Skipping walled garden check - wait " +
775654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                            waitTime + " ms.");
776654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                }
777654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                return false;
778654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            }
779654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            return true;
780654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        }
781654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    }
782654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
783654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    class OnlineWatchState extends State {
784654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        /**
785654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy         * Signals a short-wait message is enqueued for the current 'guard' counter
786654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy         */
787654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        boolean unstableSignalChecks = false;
788654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
789654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        /**
790654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy         * The signal is unstable.  We should enqueue a short-wait check, if one is enqueued
791654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy         * already
792654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy         */
793654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        boolean signalUnstable = false;
794654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
795654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        /**
796654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy         * A monotonic counter to ensure that at most one check message will be processed from any
797654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy         * set of check messages currently enqueued.  Avoids duplicate checks when a low-signal
798654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy         * event is observed.
799654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy         */
800654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        int checkGuard = 0;
801654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        Long lastCheckTime = null;
802654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
80379e43f679d6102066ee9eff862912806f53bb0e8Isaac Levy        /** Keeps track of dns pings.  Map is from pingID to InetAddress used for ping */
80479e43f679d6102066ee9eff862912806f53bb0e8Isaac Levy        HashMap<Integer, InetAddress> pingInfoMap = new HashMap<Integer, InetAddress>();
805d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy
806654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        @Override
807654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        public void enter() {
808654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            lastCheckTime = SystemClock.elapsedRealtime();
809654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            signalUnstable = false;
810654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            checkGuard++;
811654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            unstableSignalChecks = false;
81279e43f679d6102066ee9eff862912806f53bb0e8Isaac Levy            pingInfoMap.clear();
813654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            triggerSingleDnsCheck();
814654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        }
815654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
816654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        @Override
817654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        public boolean processMessage(Message msg) {
818654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            switch (msg.what) {
819654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                case EVENT_RSSI_CHANGE:
820654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    if (msg.arg1 != mNetEventCounter) {
821654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                        if (DBG) {
8227f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff                            log("Rssi change message out of sync, ignoring");
823654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                        }
824654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                        return HANDLED;
825654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    }
826654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    int newRssi = msg.arg2;
827654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    signalUnstable = !rssiStrengthAboveCutoff(newRssi);
8287f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff                    if (DBG) {
8297f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff                        log("OnlineWatchState:: new rssi " + newRssi + " --> level " +
830654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                                WifiManager.calculateSignalLevel(newRssi, WIFI_SIGNAL_LEVELS));
831654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    }
832654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
833654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    if (signalUnstable && !unstableSignalChecks) {
8347f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff                        if (DBG) {
8357f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff                            log("Sending triggered check msg");
836654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                        }
837654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                        triggerSingleDnsCheck();
838654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    }
839654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    return HANDLED;
840654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                case MESSAGE_SINGLE_DNS_CHECK:
841654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    if (msg.arg1 != checkGuard) {
8427f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff                        if (DBG) {
8437f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff                            log("Single check msg out of sync, ignoring.");
844654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                        }
845654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                        return HANDLED;
846654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    }
847654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    lastCheckTime = SystemClock.elapsedRealtime();
84879e43f679d6102066ee9eff862912806f53bb0e8Isaac Levy                    pingInfoMap.clear();
84979e43f679d6102066ee9eff862912806f53bb0e8Isaac Levy                    for (InetAddress curDns: mDnsPinger.getDnsList()) {
85079e43f679d6102066ee9eff862912806f53bb0e8Isaac Levy                        pingInfoMap.put(mDnsPinger.pingDnsAsync(curDns, mDnsPingTimeoutMs, 0),
85179e43f679d6102066ee9eff862912806f53bb0e8Isaac Levy                                curDns);
85279e43f679d6102066ee9eff862912806f53bb0e8Isaac Levy                    }
853d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                    return HANDLED;
854d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                case DnsPinger.DNS_PING_RESULT:
85579e43f679d6102066ee9eff862912806f53bb0e8Isaac Levy                    InetAddress curDnsServer = pingInfoMap.get(msg.arg1);
85679e43f679d6102066ee9eff862912806f53bb0e8Isaac Levy                    if (curDnsServer == null) {
857d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                        return HANDLED;
858d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                    }
85979e43f679d6102066ee9eff862912806f53bb0e8Isaac Levy                    pingInfoMap.remove(msg.arg1);
860d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                    int responseTime = msg.arg2;
861654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    if (responseTime >= 0) {
8627f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff                        if (DBG) {
8637f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff                            log("Single DNS ping OK. Response time: "
86479e43f679d6102066ee9eff862912806f53bb0e8Isaac Levy                                    + responseTime + " from DNS " + curDnsServer);
865654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                        }
86679e43f679d6102066ee9eff862912806f53bb0e8Isaac Levy                        pingInfoMap.clear();
867654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
868654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                        checkGuard++;
869654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                        unstableSignalChecks = false;
870654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                        triggerSingleDnsCheck();
871654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    } else {
87279e43f679d6102066ee9eff862912806f53bb0e8Isaac Levy                        if (pingInfoMap.isEmpty()) {
87379e43f679d6102066ee9eff862912806f53bb0e8Isaac Levy                            if (DBG) {
8747f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff                                log("Single dns ping failure. All dns servers failed, "
87579e43f679d6102066ee9eff862912806f53bb0e8Isaac Levy                                        + "starting full checks.");
87679e43f679d6102066ee9eff862912806f53bb0e8Isaac Levy                            }
87779e43f679d6102066ee9eff862912806f53bb0e8Isaac Levy                            transitionTo(mDnsCheckingState);
878654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                        }
879654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    }
880654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    return HANDLED;
881654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            }
882654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            return NOT_HANDLED;
883654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        }
884654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
885d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy        @Override
886d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy        public void exit() {
887d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy            mDnsPinger.cancelPings();
888d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy        }
889d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy
890654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        /**
891d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy         * Times a dns check with an interval based on {@link #signalUnstable}
892654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy         */
893654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        private void triggerSingleDnsCheck() {
894654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            long waitInterval;
895654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            if (signalUnstable) {
896d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                waitInterval = mDnsCheckShortIntervalMs;
897654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                unstableSignalChecks = true;
898654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            } else {
899d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                waitInterval = mDnsCheckLongIntervalMs;
900654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            }
901654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            sendMessageDelayed(obtainMessage(MESSAGE_SINGLE_DNS_CHECK, checkGuard, 0),
902654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    waitTime(waitInterval, lastCheckTime));
903654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        }
904654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    }
905654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
906654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    class DnsCheckFailureState extends State {
9074ad39d6ac16961df0e7a3e4b4e7075aaa5202787Isaac Levy
908654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        @Override
909654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        public void enter() {
910d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy            mNumCheckFailures++;
911654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            obtainMessage(MESSAGE_HANDLE_BAD_AP, mNetEventCounter, 0).sendToTarget();
912654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        }
913654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
914654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        @Override
915654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        public boolean processMessage(Message msg) {
916654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            if (msg.what != MESSAGE_HANDLE_BAD_AP) {
917654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                return NOT_HANDLED;
918654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            }
919654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
920654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            if (msg.arg1 != mNetEventCounter) {
9217f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff                if (DBG) {
9227f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff                    log("Msg out of sync, ignoring...");
923654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                }
924654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                return HANDLED;
925654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            }
926654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
9278dc6a1b2823f374a176fb21b8a174664a5f825faIsaac Levy            if (mDisableAPNextFailure || mNumCheckFailures >= mBssids.size()
9288dc6a1b2823f374a176fb21b8a174664a5f825faIsaac Levy                    || mNumCheckFailures >= mMaxSsidBlacklists) {
9299b2886e24301e5d4e7052ec4a6eaff273d3f516cRobert Greenwalt                if (sWifiOnly) {
9307f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff                    log("Would disable bad network, but device has no mobile data!" +
9314ad39d6ac16961df0e7a3e4b4e7075aaa5202787Isaac Levy                            "  Going idle...");
9324ad39d6ac16961df0e7a3e4b4e7075aaa5202787Isaac Levy                    // This state should be called idle -- will be changing flow.
9334ad39d6ac16961df0e7a3e4b4e7075aaa5202787Isaac Levy                    transitionTo(mNotConnectedState);
9344ad39d6ac16961df0e7a3e4b4e7075aaa5202787Isaac Levy                    return HANDLED;
9354ad39d6ac16961df0e7a3e4b4e7075aaa5202787Isaac Levy                }
9368dc6a1b2823f374a176fb21b8a174664a5f825faIsaac Levy
937654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                // TODO : Unban networks if they had low signal ?
9387f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff                log("Disabling current SSID " + wifiInfoToStr(mConnectionInfo)
939d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                        + ".  " + "numCheckFailures " + mNumCheckFailures
940d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                        + ", numAPs " + mBssids.size());
9418dc6a1b2823f374a176fb21b8a174664a5f825faIsaac Levy                int networkId = mConnectionInfo.getNetworkId();
9428dc6a1b2823f374a176fb21b8a174664a5f825faIsaac Levy                if (!mHasConnectedWifiManager) {
9438dc6a1b2823f374a176fb21b8a174664a5f825faIsaac Levy                    mWifiManager.asyncConnect(mContext, getHandler());
9448dc6a1b2823f374a176fb21b8a174664a5f825faIsaac Levy                    mHasConnectedWifiManager = true;
9458dc6a1b2823f374a176fb21b8a174664a5f825faIsaac Levy                }
9468dc6a1b2823f374a176fb21b8a174664a5f825faIsaac Levy                mWifiManager.disableNetwork(networkId, WifiConfiguration.DISABLED_DNS_FAILURE);
9478dc6a1b2823f374a176fb21b8a174664a5f825faIsaac Levy                if (mShowDisabledNotification && mConnectionInfo.isExplicitConnect()) {
9488dc6a1b2823f374a176fb21b8a174664a5f825faIsaac Levy                    displayDisabledNetworkNotification(mConnectionInfo.getSSID());
949d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                }
950654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                transitionTo(mNotConnectedState);
951654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            } else {
9527f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff                log("Blacklisting current BSSID.  " + wifiInfoToStr(mConnectionInfo)
953d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                       + "numCheckFailures " + mNumCheckFailures + ", numAPs " + mBssids.size());
954654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
9558dc6a1b2823f374a176fb21b8a174664a5f825faIsaac Levy                mWifiManager.addToBlacklist(mConnectionInfo.getBSSID());
956654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                mWifiManager.reassociate();
957654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                transitionTo(mBlacklistedApState);
958654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            }
959654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            return HANDLED;
960654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        }
961654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    }
962654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
963654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    class WalledGardenState extends State {
964654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        @Override
965654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        public void enter() {
966654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            obtainMessage(MESSAGE_HANDLE_WALLED_GARDEN, mNetEventCounter, 0).sendToTarget();
967654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        }
968654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
969654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        @Override
970654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        public boolean processMessage(Message msg) {
971654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            if (msg.what != MESSAGE_HANDLE_WALLED_GARDEN) {
972654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                return NOT_HANDLED;
973654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            }
974654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
975654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            if (msg.arg1 != mNetEventCounter) {
9767f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff                if (DBG) {
9777f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff                    log("WalledGardenState::Msg out of sync, ignoring...");
978654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                }
979654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                return HANDLED;
980654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            }
981654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            popUpBrowser();
982654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            transitionTo(mOnlineWatchState);
983654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            return HANDLED;
984654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        }
985654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    }
986654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
987654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    class BlacklistedApState extends State {
988654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        @Override
989654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        public void enter() {
990654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            mDisableAPNextFailure = true;
991654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            sendMessageDelayed(obtainMessage(MESSAGE_NETWORK_FOLLOWUP, mNetEventCounter, 0),
992d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                    mBlacklistFollowupIntervalMs);
993654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        }
994654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
995654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        @Override
996654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        public boolean processMessage(Message msg) {
997654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            if (msg.what != MESSAGE_NETWORK_FOLLOWUP) {
998654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                return NOT_HANDLED;
999654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            }
1000654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
1001654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            if (msg.arg1 != mNetEventCounter) {
10027f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff                if (DBG) {
10037f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff                    log("BlacklistedApState::Msg out of sync, ignoring...");
1004654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                }
1005654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                return HANDLED;
1006654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            }
1007654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
1008654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            transitionTo(mDnsCheckingState);
1009654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            return HANDLED;
1010654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        }
1011654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    }
1012d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy
1013d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy
1014d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy    /**
1015d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy     * Convenience function for retrieving a single secure settings value
1016d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy     * as a string with a default value.
1017d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy     *
1018d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy     * @param cr The ContentResolver to access.
1019d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy     * @param name The name of the setting to retrieve.
1020d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy     * @param def Value to return if the setting is not defined.
1021d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy     *
1022d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy     * @return The setting's current value, or 'def' if it is not defined
1023d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy     */
1024d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy    private static String getSettingsStr(ContentResolver cr, String name, String def) {
1025d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy        String v = Settings.Secure.getString(cr, name);
1026d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy        return v != null ? v : def;
1027d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy    }
1028d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy
1029d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy    /**
1030d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy     * Convenience function for retrieving a single secure settings value
1031d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy     * as a boolean.  Note that internally setting values are always
1032d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy     * stored as strings; this function converts the string to a boolean
1033d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy     * for you.  The default value will be returned if the setting is
1034d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy     * not defined or not a valid boolean.
1035d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy     *
1036d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy     * @param cr The ContentResolver to access.
1037d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy     * @param name The name of the setting to retrieve.
1038d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy     * @param def Value to return if the setting is not defined.
1039d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy     *
1040d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy     * @return The setting's current value, or 'def' if it is not defined
1041d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy     * or not a valid boolean.
1042d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy     */
1043d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy    private static boolean getSettingsBoolean(ContentResolver cr, String name, boolean def) {
1044d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy        return Settings.Secure.getInt(cr, name, def ? 1 : 0) == 1;
1045d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy    }
1046d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy
1047d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy    /**
1048d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy     * Convenience function for updating a single settings value as an
1049d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy     * integer. This will either create a new entry in the table if the
1050d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy     * given name does not exist, or modify the value of the existing row
1051d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy     * with that name.  Note that internally setting values are always
1052d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy     * stored as strings, so this function converts the given value to a
1053d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy     * string before storing it.
1054d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy     *
1055d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy     * @param cr The ContentResolver to access.
1056d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy     * @param name The name of the setting to modify.
1057d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy     * @param value The new value for the setting.
1058d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy     * @return true if the value was set, false on database errors
1059d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy     */
1060d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy    private static boolean putSettingsBoolean(ContentResolver cr, String name, boolean value) {
1061d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy        return Settings.Secure.putInt(cr, name, value ? 1 : 0);
1062d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy    }
1063d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy
10647f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff    private void log(String s) {
10657f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff        Log.d(TAG, s);
10667f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff    }
1067d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy
10687f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff    private void loge(String s) {
10697f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff        Log.e(TAG, s);
10707f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff    }
1071654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy}
1072