WifiWatchdogStateMachine.java revision 6b66e9e4c95b1c866ea63a0122fc199994fd7053
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
406b66e9e4c95b1c866ea63a0122fc199994fd7053Irfan Sheriffimport com.android.internal.R;
41654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levyimport com.android.internal.util.Protocol;
42654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levyimport com.android.internal.util.State;
43654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levyimport com.android.internal.util.StateMachine;
44654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
45654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levyimport java.io.IOException;
46654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levyimport java.io.PrintWriter;
47654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levyimport java.net.HttpURLConnection;
48d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levyimport java.net.InetAddress;
49654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levyimport java.net.URL;
5079e43f679d6102066ee9eff862912806f53bb0e8Isaac Levyimport java.util.HashMap;
51654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levyimport java.util.HashSet;
52654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levyimport java.util.List;
53654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
54654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy/**
55654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy * {@link WifiWatchdogStateMachine} monitors the initial connection to a Wi-Fi
56654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy * network with multiple access points. After the framework successfully
57654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy * connects to an access point, the watchdog verifies connectivity by 'pinging'
58654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy * the configured DNS server using {@link DnsPinger}.
59654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy * <p>
60654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy * On DNS check failure, the BSSID is blacklisted if it is reasonably likely
61654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy * that another AP might have internet access; otherwise the SSID is disabled.
62654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy * <p>
63654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy * On DNS success, the WatchdogService initiates a walled garden check via an
64654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy * http get. A browser window is activated if a walled garden is detected.
65654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy *
66654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy * @hide
67654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy */
68654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levypublic class WifiWatchdogStateMachine extends StateMachine {
69654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
707f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff    private static final boolean DBG = false;
717f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff    private static final String TAG = "WifiWatchdogStateMachine";
726b66e9e4c95b1c866ea63a0122fc199994fd7053Irfan Sheriff    private static final String DISABLED_NETWORK_NOTIFICATION_ID = "WifiWatchdog.networkdisabled";
736b66e9e4c95b1c866ea63a0122fc199994fd7053Irfan Sheriff    private static final String WALLED_GARDEN_NOTIFICATION_ID = "WifiWatchdog.walledgarden";
74654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
75654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    private static final int WIFI_SIGNAL_LEVELS = 4;
76654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    /**
77654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy     * Low signal is defined as less than or equal to cut off
78654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy     */
79998196d64d35c1767dbb08f059fe3af171e44e1dIrfan Sheriff    private static final int LOW_SIGNAL_CUTOFF = 0;
80654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
81d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy    private static final long DEFAULT_DNS_CHECK_SHORT_INTERVAL_MS = 2 * 60 * 1000;
82998196d64d35c1767dbb08f059fe3af171e44e1dIrfan Sheriff    private static final long DEFAULT_DNS_CHECK_LONG_INTERVAL_MS = 60 * 60 * 1000;
83d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy    private static final long DEFAULT_WALLED_GARDEN_INTERVAL_MS = 30 * 60 * 1000;
84654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
85d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy    private static final int DEFAULT_MAX_SSID_BLACKLISTS = 7;
86998196d64d35c1767dbb08f059fe3af171e44e1dIrfan Sheriff    private static final int DEFAULT_NUM_DNS_PINGS = 5; // Multiple pings to detect setup issues
87998196d64d35c1767dbb08f059fe3af171e44e1dIrfan Sheriff    private static final int DEFAULT_MIN_DNS_RESPONSES = 1;
88654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
8988bae17cfd3de40758c5296d15f012f06f08748aIsaac Levy    private static final int DEFAULT_DNS_PING_TIMEOUT_MS = 2000;
90d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy
91d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy    private static final long DEFAULT_BLACKLIST_FOLLOWUP_INTERVAL_MS = 15 * 1000;
92d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy
9388bae17cfd3de40758c5296d15f012f06f08748aIsaac Levy    // See http://go/clientsdns for usage approval
9488bae17cfd3de40758c5296d15f012f06f08748aIsaac Levy    private static final String DEFAULT_WALLED_GARDEN_URL =
9588bae17cfd3de40758c5296d15f012f06f08748aIsaac Levy            "http://clients3.google.com/generate_204";
9688bae17cfd3de40758c5296d15f012f06f08748aIsaac Levy    private static final int WALLED_GARDEN_SOCKET_TIMEOUT_MS = 10000;
97a81ac7c450d9d534c46abc7000cc53779a72c283Irfan Sheriff
98a81ac7c450d9d534c46abc7000cc53779a72c283Irfan Sheriff    /* Some carrier apps might have support captive portal handling. Add some delay to allow
99a81ac7c450d9d534c46abc7000cc53779a72c283Irfan Sheriff        app authentication to be done before our test.
100a81ac7c450d9d534c46abc7000cc53779a72c283Irfan Sheriff       TODO: This should go away once we provide an API to apps to disable walled garden test
101a81ac7c450d9d534c46abc7000cc53779a72c283Irfan Sheriff       for certain SSIDs
102a81ac7c450d9d534c46abc7000cc53779a72c283Irfan Sheriff     */
103a81ac7c450d9d534c46abc7000cc53779a72c283Irfan Sheriff    private static final int WALLED_GARDEN_START_DELAY_MS = 3000;
104a81ac7c450d9d534c46abc7000cc53779a72c283Irfan Sheriff
105998196d64d35c1767dbb08f059fe3af171e44e1dIrfan Sheriff    private static final int DNS_INTRATEST_PING_INTERVAL_MS = 200;
106998196d64d35c1767dbb08f059fe3af171e44e1dIrfan Sheriff    /* With some router setups, it takes a few hunder milli-seconds before connection is active */
107998196d64d35c1767dbb08f059fe3af171e44e1dIrfan Sheriff    private static final int DNS_START_DELAY_MS = 1000;
108654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
109654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    private static final int BASE = Protocol.BASE_WIFI_WATCHDOG;
110654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
111654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    /**
112654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy     * Indicates the enable setting of WWS may have changed
113654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy     */
114a81ac7c450d9d534c46abc7000cc53779a72c283Irfan Sheriff    private static final int EVENT_WATCHDOG_TOGGLED                 = BASE + 1;
115654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
116654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    /**
117654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy     * Indicates the wifi network state has changed. Passed w/ original intent
118654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy     * which has a non-null networkInfo object
119654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy     */
120a81ac7c450d9d534c46abc7000cc53779a72c283Irfan Sheriff    private static final int EVENT_NETWORK_STATE_CHANGE             = BASE + 2;
121654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    /**
122654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy     * Indicates the signal has changed. Passed with arg1
123654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy     * {@link #mNetEventCounter} and arg2 [raw signal strength]
124654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy     */
125a81ac7c450d9d534c46abc7000cc53779a72c283Irfan Sheriff    private static final int EVENT_RSSI_CHANGE                      = BASE + 3;
126a81ac7c450d9d534c46abc7000cc53779a72c283Irfan Sheriff    private static final int EVENT_SCAN_RESULTS_AVAILABLE           = BASE + 4;
127a81ac7c450d9d534c46abc7000cc53779a72c283Irfan Sheriff    private static final int EVENT_WIFI_RADIO_STATE_CHANGE          = BASE + 5;
128a81ac7c450d9d534c46abc7000cc53779a72c283Irfan Sheriff    private static final int EVENT_WATCHDOG_SETTINGS_CHANGE         = BASE + 6;
129654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
130a81ac7c450d9d534c46abc7000cc53779a72c283Irfan Sheriff    private static final int MESSAGE_HANDLE_WALLED_GARDEN           = BASE + 100;
131a81ac7c450d9d534c46abc7000cc53779a72c283Irfan Sheriff    private static final int MESSAGE_HANDLE_BAD_AP                  = BASE + 101;
132654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    /**
133654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy     * arg1 == mOnlineWatchState.checkCount
134654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy     */
135a81ac7c450d9d534c46abc7000cc53779a72c283Irfan Sheriff    private static final int MESSAGE_SINGLE_DNS_CHECK               = BASE + 102;
136a81ac7c450d9d534c46abc7000cc53779a72c283Irfan Sheriff    private static final int MESSAGE_NETWORK_FOLLOWUP               = BASE + 103;
137a81ac7c450d9d534c46abc7000cc53779a72c283Irfan Sheriff    private static final int MESSAGE_DELAYED_WALLED_GARDEN_CHECK    = BASE + 104;
138654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
139654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    private Context mContext;
140654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    private ContentResolver mContentResolver;
141654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    private WifiManager mWifiManager;
142654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    private DnsPinger mDnsPinger;
143654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    private IntentFilter mIntentFilter;
144654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    private BroadcastReceiver mBroadcastReceiver;
145654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
146654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    private DefaultState mDefaultState = new DefaultState();
147654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    private WatchdogDisabledState mWatchdogDisabledState = new WatchdogDisabledState();
148654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    private WatchdogEnabledState mWatchdogEnabledState = new WatchdogEnabledState();
149654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    private NotConnectedState mNotConnectedState = new NotConnectedState();
150654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    private ConnectedState mConnectedState = new ConnectedState();
151654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    private DnsCheckingState mDnsCheckingState = new DnsCheckingState();
152654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    private OnlineWatchState mOnlineWatchState = new OnlineWatchState();
153654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    private DnsCheckFailureState mDnsCheckFailureState = new DnsCheckFailureState();
154a81ac7c450d9d534c46abc7000cc53779a72c283Irfan Sheriff    private DelayWalledGardenState mDelayWalledGardenState = new DelayWalledGardenState();
155654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    private WalledGardenState mWalledGardenState = new WalledGardenState();
156654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    private BlacklistedApState mBlacklistedApState = new BlacklistedApState();
157654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
158d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy    private long mDnsCheckShortIntervalMs;
159d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy    private long mDnsCheckLongIntervalMs;
160d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy    private long mWalledGardenIntervalMs;
161d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy    private int mMaxSsidBlacklists;
162d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy    private int mNumDnsPings;
163d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy    private int mMinDnsResponses;
164d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy    private int mDnsPingTimeoutMs;
165d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy    private long mBlacklistFollowupIntervalMs;
166d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy    private boolean mWalledGardenTestEnabled;
167d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy    private String mWalledGardenUrl;
168d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy
169d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy    private boolean mShowDisabledNotification;
170654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    /**
171654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy     * The {@link WifiInfo} object passed to WWSM on network broadcasts
172654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy     */
1738dc6a1b2823f374a176fb21b8a174664a5f825faIsaac Levy    private WifiInfo mConnectionInfo;
174654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    private int mNetEventCounter = 0;
175654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
176654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    /**
177654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy     * Currently maintained but not used, TODO
178654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy     */
179654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    private HashSet<String> mBssids = new HashSet<String>();
180d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy    private int mNumCheckFailures = 0;
181654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
182654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    private Long mLastWalledGardenCheckTime = null;
183654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
184654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    /**
185654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy     * This is set by the blacklisted state and reset when connected to a new AP.
186654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy     * It triggers a disableNetwork call if a DNS check fails.
187654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy     */
188654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    public boolean mDisableAPNextFailure = false;
1899b2886e24301e5d4e7052ec4a6eaff273d3f516cRobert Greenwalt    private static boolean sWifiOnly = false;
1906b66e9e4c95b1c866ea63a0122fc199994fd7053Irfan Sheriff    private boolean mDisabledNotificationShown;
1916b66e9e4c95b1c866ea63a0122fc199994fd7053Irfan Sheriff    private boolean mWalledGardenNotificationShown;
1928dc6a1b2823f374a176fb21b8a174664a5f825faIsaac Levy    public boolean mHasConnectedWifiManager = false;
193654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
194654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    /**
195654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy     * STATE MAP
196654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy     *          Default
197654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy     *         /       \
198654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy     * Disabled     Enabled
199654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy     *             /       \
200d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy     * NotConnected      Connected
201654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy     *                  /---------\
202654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy     *               (all other states)
203654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy     */
204654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    private WifiWatchdogStateMachine(Context context) {
2057f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff        super(TAG);
206654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        mContext = context;
207654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        mContentResolver = context.getContentResolver();
208654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
209d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy        mDnsPinger = new DnsPinger(mContext, "WifiWatchdogStateMachine.DnsPinger",
210d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                                this.getHandler().getLooper(), this.getHandler(),
211d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                                ConnectivityManager.TYPE_WIFI);
212654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
213654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        setupNetworkReceiver();
214654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
215654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        // The content observer to listen needs a handler
216654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        registerForSettingsChanges();
217d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy        registerForWatchdogToggle();
218654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        addState(mDefaultState);
219654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            addState(mWatchdogDisabledState, mDefaultState);
220654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            addState(mWatchdogEnabledState, mDefaultState);
221654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                addState(mNotConnectedState, mWatchdogEnabledState);
222654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                addState(mConnectedState, mWatchdogEnabledState);
223654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    addState(mDnsCheckingState, mConnectedState);
224654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    addState(mDnsCheckFailureState, mConnectedState);
225a81ac7c450d9d534c46abc7000cc53779a72c283Irfan Sheriff                    addState(mDelayWalledGardenState, mConnectedState);
226654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    addState(mWalledGardenState, mConnectedState);
227654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    addState(mBlacklistedApState, mConnectedState);
228654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    addState(mOnlineWatchState, mConnectedState);
229654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
230654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        setInitialState(mWatchdogDisabledState);
231d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy        updateSettings();
232654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    }
233654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
234654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    public static WifiWatchdogStateMachine makeWifiWatchdogStateMachine(Context context) {
2354ad39d6ac16961df0e7a3e4b4e7075aaa5202787Isaac Levy        ContentResolver contentResolver = context.getContentResolver();
2369b2886e24301e5d4e7052ec4a6eaff273d3f516cRobert Greenwalt
2379b2886e24301e5d4e7052ec4a6eaff273d3f516cRobert Greenwalt        ConnectivityManager cm = (ConnectivityManager) context.getSystemService(
2389b2886e24301e5d4e7052ec4a6eaff273d3f516cRobert Greenwalt                Context.CONNECTIVITY_SERVICE);
2399b2886e24301e5d4e7052ec4a6eaff273d3f516cRobert Greenwalt        sWifiOnly = (cm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE) == false);
2409b2886e24301e5d4e7052ec4a6eaff273d3f516cRobert Greenwalt
2414ad39d6ac16961df0e7a3e4b4e7075aaa5202787Isaac Levy        // Disable for wifi only devices.
2424ad39d6ac16961df0e7a3e4b4e7075aaa5202787Isaac Levy        if (Settings.Secure.getString(contentResolver, Settings.Secure.WIFI_WATCHDOG_ON) == null &&
2439b2886e24301e5d4e7052ec4a6eaff273d3f516cRobert Greenwalt                sWifiOnly) {
2444ad39d6ac16961df0e7a3e4b4e7075aaa5202787Isaac Levy            putSettingsBoolean(contentResolver, Settings.Secure.WIFI_WATCHDOG_ON, false);
2454ad39d6ac16961df0e7a3e4b4e7075aaa5202787Isaac Levy        }
246654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        WifiWatchdogStateMachine wwsm = new WifiWatchdogStateMachine(context);
247654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        wwsm.start();
248654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        wwsm.sendMessage(EVENT_WATCHDOG_TOGGLED);
249654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        return wwsm;
250654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    }
251654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
252654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    /**
253654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy   *
254654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy   */
255654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    private void setupNetworkReceiver() {
256654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        mBroadcastReceiver = new BroadcastReceiver() {
257654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            @Override
258654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            public void onReceive(Context context, Intent intent) {
259654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                String action = intent.getAction();
260654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
261654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    sendMessage(EVENT_NETWORK_STATE_CHANGE, intent);
262654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                } else if (action.equals(WifiManager.RSSI_CHANGED_ACTION)) {
263654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    obtainMessage(EVENT_RSSI_CHANGE, mNetEventCounter,
264654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                            intent.getIntExtra(WifiManager.EXTRA_NEW_RSSI, -200)).sendToTarget();
265654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                } else if (action.equals(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) {
266654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    sendMessage(EVENT_SCAN_RESULTS_AVAILABLE);
267654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                } else if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) {
268654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    sendMessage(EVENT_WIFI_RADIO_STATE_CHANGE,
269654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                            intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
270654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                                    WifiManager.WIFI_STATE_UNKNOWN));
271654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                }
272654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            }
273654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        };
274654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
275654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        mIntentFilter = new IntentFilter();
276654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        mIntentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
277654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        mIntentFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
278654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        mIntentFilter.addAction(WifiManager.RSSI_CHANGED_ACTION);
279654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        mIntentFilter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
280654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    }
281654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
282654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    /**
283654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy     * Observes the watchdog on/off setting, and takes action when changed.
284654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy     */
285d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy    private void registerForWatchdogToggle() {
286654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        ContentObserver contentObserver = new ContentObserver(this.getHandler()) {
287654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            @Override
288654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            public void onChange(boolean selfChange) {
289654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                sendMessage(EVENT_WATCHDOG_TOGGLED);
290654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            }
291654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        };
292654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
293654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        mContext.getContentResolver().registerContentObserver(
294654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                Settings.Secure.getUriFor(Settings.Secure.WIFI_WATCHDOG_ON),
295654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                false, contentObserver);
296654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    }
297654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
298654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    /**
299d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy     * Observes watchdogs secure setting changes.
300d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy     */
301d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy    private void registerForSettingsChanges() {
302d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy        ContentObserver contentObserver = new ContentObserver(this.getHandler()) {
303d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy            @Override
304d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy            public void onChange(boolean selfChange) {
305d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                sendMessage(EVENT_WATCHDOG_SETTINGS_CHANGE);
306d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy            }
307d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy        };
308d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy
309d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy        mContext.getContentResolver().registerContentObserver(
310d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                Settings.Secure.getUriFor(
311d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                        Settings.Secure.WIFI_WATCHDOG_DNS_CHECK_SHORT_INTERVAL_MS),
312d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                        false, contentObserver);
313d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy        mContext.getContentResolver().registerContentObserver(
314d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                Settings.Secure.getUriFor(Settings.Secure.WIFI_WATCHDOG_DNS_CHECK_LONG_INTERVAL_MS),
315d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                false, contentObserver);
316d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy        mContext.getContentResolver().registerContentObserver(
317d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                Settings.Secure.getUriFor(Settings.Secure.WIFI_WATCHDOG_WALLED_GARDEN_INTERVAL_MS),
318d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                false, contentObserver);
319d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy        mContext.getContentResolver().registerContentObserver(
320d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                Settings.Secure.getUriFor(Settings.Secure.WIFI_WATCHDOG_MAX_SSID_BLACKLISTS),
321d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                false, contentObserver);
322d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy        mContext.getContentResolver().registerContentObserver(
323d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                Settings.Secure.getUriFor(Settings.Secure.WIFI_WATCHDOG_NUM_DNS_PINGS),
324d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                false, contentObserver);
325d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy        mContext.getContentResolver().registerContentObserver(
326d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                Settings.Secure.getUriFor(Settings.Secure.WIFI_WATCHDOG_MIN_DNS_RESPONSES),
327d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                false, contentObserver);
328d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy        mContext.getContentResolver().registerContentObserver(
329d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                Settings.Secure.getUriFor(Settings.Secure.WIFI_WATCHDOG_DNS_PING_TIMEOUT_MS),
330d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                false, contentObserver);
331d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy        mContext.getContentResolver().registerContentObserver(
332d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                Settings.Secure.getUriFor(
333d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                        Settings.Secure.WIFI_WATCHDOG_BLACKLIST_FOLLOWUP_INTERVAL_MS),
334d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                        false, contentObserver);
335d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy        mContext.getContentResolver().registerContentObserver(
336d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                Settings.Secure.getUriFor(Settings.Secure.WIFI_WATCHDOG_WALLED_GARDEN_TEST_ENABLED),
337d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                false, contentObserver);
338d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy        mContext.getContentResolver().registerContentObserver(
339d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                Settings.Secure.getUriFor(Settings.Secure.WIFI_WATCHDOG_WALLED_GARDEN_URL),
340d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                false, contentObserver);
3418dc6a1b2823f374a176fb21b8a174664a5f825faIsaac Levy        mContext.getContentResolver().registerContentObserver(
3428dc6a1b2823f374a176fb21b8a174664a5f825faIsaac Levy                Settings.Secure.getUriFor(Settings.Secure.WIFI_WATCHDOG_SHOW_DISABLED_NETWORK_POPUP)
3438dc6a1b2823f374a176fb21b8a174664a5f825faIsaac Levy                , false, contentObserver);
344d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy    }
345d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy
346d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy    /**
347654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy     * DNS based detection techniques do not work at all hotspots. The one sure
348654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy     * way to check a walled garden is to see if a URL fetch on a known address
349654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy     * fetches the data we expect
350654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy     */
351654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    private boolean isWalledGardenConnection() {
352654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        HttpURLConnection urlConnection = null;
353654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        try {
354d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy            URL url = new URL(mWalledGardenUrl);
355654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            urlConnection = (HttpURLConnection) url.openConnection();
35688bae17cfd3de40758c5296d15f012f06f08748aIsaac Levy            urlConnection.setInstanceFollowRedirects(false);
35788bae17cfd3de40758c5296d15f012f06f08748aIsaac Levy            urlConnection.setConnectTimeout(WALLED_GARDEN_SOCKET_TIMEOUT_MS);
35888bae17cfd3de40758c5296d15f012f06f08748aIsaac Levy            urlConnection.setReadTimeout(WALLED_GARDEN_SOCKET_TIMEOUT_MS);
35988bae17cfd3de40758c5296d15f012f06f08748aIsaac Levy            urlConnection.setUseCaches(false);
36088bae17cfd3de40758c5296d15f012f06f08748aIsaac Levy            urlConnection.getInputStream();
36188bae17cfd3de40758c5296d15f012f06f08748aIsaac Levy            // We got a valid response, but not from the real google
36288bae17cfd3de40758c5296d15f012f06f08748aIsaac Levy            return urlConnection.getResponseCode() != 204;
363654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        } catch (IOException e) {
36488bae17cfd3de40758c5296d15f012f06f08748aIsaac Levy            if (DBG) {
3657f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff                log("Walled garden check - probably not a portal: exception " + e);
36688bae17cfd3de40758c5296d15f012f06f08748aIsaac Levy            }
367654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            return false;
368654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        } finally {
36988bae17cfd3de40758c5296d15f012f06f08748aIsaac Levy            if (urlConnection != null) {
370654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                urlConnection.disconnect();
37188bae17cfd3de40758c5296d15f012f06f08748aIsaac Levy            }
372654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        }
373654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    }
374654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
375654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    private boolean rssiStrengthAboveCutoff(int rssi) {
376654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        return WifiManager.calculateSignalLevel(rssi, WIFI_SIGNAL_LEVELS) > LOW_SIGNAL_CUTOFF;
377654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    }
378654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
379654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    public void dump(PrintWriter pw) {
380654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        pw.print("WatchdogStatus: ");
381654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        pw.print("State " + getCurrentState());
3828dc6a1b2823f374a176fb21b8a174664a5f825faIsaac Levy        pw.println(", network [" + mConnectionInfo + "]");
383d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy        pw.print("checkFailures   " + mNumCheckFailures);
384654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        pw.println(", bssids: " + mBssids);
385654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        pw.println("lastSingleCheck: " + mOnlineWatchState.lastCheckTime);
386654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    }
387654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
388654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    private boolean isWatchdogEnabled() {
389d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy        return getSettingsBoolean(mContentResolver, Settings.Secure.WIFI_WATCHDOG_ON, true);
390654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    }
391654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
392d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy    private void updateSettings() {
393d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy        mDnsCheckShortIntervalMs = Secure.getLong(mContentResolver,
394d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                Secure.WIFI_WATCHDOG_DNS_CHECK_SHORT_INTERVAL_MS,
395d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                DEFAULT_DNS_CHECK_SHORT_INTERVAL_MS);
396d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy        mDnsCheckLongIntervalMs = Secure.getLong(mContentResolver,
397d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                Secure.WIFI_WATCHDOG_DNS_CHECK_LONG_INTERVAL_MS,
398d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                DEFAULT_DNS_CHECK_LONG_INTERVAL_MS);
399d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy        mMaxSsidBlacklists = Secure.getInt(mContentResolver,
400d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                Secure.WIFI_WATCHDOG_MAX_SSID_BLACKLISTS,
401d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                DEFAULT_MAX_SSID_BLACKLISTS);
402d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy        mNumDnsPings = Secure.getInt(mContentResolver,
403d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                Secure.WIFI_WATCHDOG_NUM_DNS_PINGS,
404d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                DEFAULT_NUM_DNS_PINGS);
405d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy        mMinDnsResponses = Secure.getInt(mContentResolver,
406d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                Secure.WIFI_WATCHDOG_MIN_DNS_RESPONSES,
407d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                DEFAULT_MIN_DNS_RESPONSES);
408d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy        mDnsPingTimeoutMs = Secure.getInt(mContentResolver,
409d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                Secure.WIFI_WATCHDOG_DNS_PING_TIMEOUT_MS,
410d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                DEFAULT_DNS_PING_TIMEOUT_MS);
411d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy        mBlacklistFollowupIntervalMs = Secure.getLong(mContentResolver,
412d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                Settings.Secure.WIFI_WATCHDOG_BLACKLIST_FOLLOWUP_INTERVAL_MS,
413d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                DEFAULT_BLACKLIST_FOLLOWUP_INTERVAL_MS);
414d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy        mWalledGardenTestEnabled = getSettingsBoolean(mContentResolver,
415d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                Settings.Secure.WIFI_WATCHDOG_WALLED_GARDEN_TEST_ENABLED, true);
416d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy        mWalledGardenUrl = getSettingsStr(mContentResolver,
417d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                Settings.Secure.WIFI_WATCHDOG_WALLED_GARDEN_URL,
418d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                DEFAULT_WALLED_GARDEN_URL);
419d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy        mWalledGardenIntervalMs = Secure.getLong(mContentResolver,
420d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                Secure.WIFI_WATCHDOG_WALLED_GARDEN_INTERVAL_MS,
421d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                DEFAULT_WALLED_GARDEN_INTERVAL_MS);
4228dc6a1b2823f374a176fb21b8a174664a5f825faIsaac Levy        mShowDisabledNotification = getSettingsBoolean(mContentResolver,
4238dc6a1b2823f374a176fb21b8a174664a5f825faIsaac Levy                Settings.Secure.WIFI_WATCHDOG_SHOW_DISABLED_NETWORK_POPUP, true);
424d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy    }
425654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
426654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    /**
427654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy     * Helper to return wait time left given a min interval and last run
428654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy     *
429654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy     * @param interval minimum wait interval
430654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy     * @param lastTime last time action was performed in
431654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy     *            SystemClock.elapsedRealtime(). Null if never.
432654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy     * @return non negative time to wait
433654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy     */
434654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    private static long waitTime(long interval, Long lastTime) {
435654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        if (lastTime == null)
436654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            return 0;
437654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        long wait = interval + lastTime - SystemClock.elapsedRealtime();
438654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        return wait > 0 ? wait : 0;
439654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    }
440654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
441654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    private static String wifiInfoToStr(WifiInfo wifiInfo) {
442654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        if (wifiInfo == null)
443654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            return "null";
444654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        return "(" + wifiInfo.getSSID() + ", " + wifiInfo.getBSSID() + ")";
445654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    }
446654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
447654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    /**
4488dc6a1b2823f374a176fb21b8a174664a5f825faIsaac Levy     * Uses {@link #mConnectionInfo}.
4498dc6a1b2823f374a176fb21b8a174664a5f825faIsaac Levy     */
4508dc6a1b2823f374a176fb21b8a174664a5f825faIsaac Levy    private void updateBssids() {
4518dc6a1b2823f374a176fb21b8a174664a5f825faIsaac Levy        String curSsid = mConnectionInfo.getSSID();
4528dc6a1b2823f374a176fb21b8a174664a5f825faIsaac Levy        List<ScanResult> results = mWifiManager.getScanResults();
4538dc6a1b2823f374a176fb21b8a174664a5f825faIsaac Levy        int oldNumBssids = mBssids.size();
4548dc6a1b2823f374a176fb21b8a174664a5f825faIsaac Levy
4558dc6a1b2823f374a176fb21b8a174664a5f825faIsaac Levy        if (results == null) {
4568dc6a1b2823f374a176fb21b8a174664a5f825faIsaac Levy            if (DBG) {
4577f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff                log("updateBssids: Got null scan results!");
4588dc6a1b2823f374a176fb21b8a174664a5f825faIsaac Levy            }
4598dc6a1b2823f374a176fb21b8a174664a5f825faIsaac Levy            return;
4608dc6a1b2823f374a176fb21b8a174664a5f825faIsaac Levy        }
4618dc6a1b2823f374a176fb21b8a174664a5f825faIsaac Levy
4628dc6a1b2823f374a176fb21b8a174664a5f825faIsaac Levy        for (ScanResult result : results) {
4638dc6a1b2823f374a176fb21b8a174664a5f825faIsaac Levy            if (result == null || result.SSID == null) {
4648dc6a1b2823f374a176fb21b8a174664a5f825faIsaac Levy                if (DBG) {
4657f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff                    log("Received invalid scan result: " + result);
4668dc6a1b2823f374a176fb21b8a174664a5f825faIsaac Levy                }
4678dc6a1b2823f374a176fb21b8a174664a5f825faIsaac Levy                continue;
4688dc6a1b2823f374a176fb21b8a174664a5f825faIsaac Levy            }
4698dc6a1b2823f374a176fb21b8a174664a5f825faIsaac Levy            if (curSsid.equals(result.SSID))
4708dc6a1b2823f374a176fb21b8a174664a5f825faIsaac Levy                mBssids.add(result.BSSID);
4718dc6a1b2823f374a176fb21b8a174664a5f825faIsaac Levy        }
4728dc6a1b2823f374a176fb21b8a174664a5f825faIsaac Levy    }
4738dc6a1b2823f374a176fb21b8a174664a5f825faIsaac Levy
474654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    private void resetWatchdogState() {
4757f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff        if (DBG) {
4767f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff            log("Resetting watchdog state...");
47788bae17cfd3de40758c5296d15f012f06f08748aIsaac Levy        }
4788dc6a1b2823f374a176fb21b8a174664a5f825faIsaac Levy        mConnectionInfo = null;
479654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        mDisableAPNextFailure = false;
480654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        mLastWalledGardenCheckTime = null;
481d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy        mNumCheckFailures = 0;
482654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        mBssids.clear();
4836b66e9e4c95b1c866ea63a0122fc199994fd7053Irfan Sheriff        setDisabledNetworkNotificationVisible(false);
4846b66e9e4c95b1c866ea63a0122fc199994fd7053Irfan Sheriff        setWalledGardenNotificationVisible(false);
485654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    }
486654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
4876b66e9e4c95b1c866ea63a0122fc199994fd7053Irfan Sheriff    private void setWalledGardenNotificationVisible(boolean visible) {
4886b66e9e4c95b1c866ea63a0122fc199994fd7053Irfan Sheriff        // If it should be hidden and it is already hidden, then noop
4896b66e9e4c95b1c866ea63a0122fc199994fd7053Irfan Sheriff        if (!visible && !mWalledGardenNotificationShown) {
4906b66e9e4c95b1c866ea63a0122fc199994fd7053Irfan Sheriff            return;
4916b66e9e4c95b1c866ea63a0122fc199994fd7053Irfan Sheriff        }
492654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
493d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy        Resources r = Resources.getSystem();
494d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy        NotificationManager notificationManager = (NotificationManager) mContext
4956b66e9e4c95b1c866ea63a0122fc199994fd7053Irfan Sheriff            .getSystemService(Context.NOTIFICATION_SERVICE);
4966b66e9e4c95b1c866ea63a0122fc199994fd7053Irfan Sheriff
4976b66e9e4c95b1c866ea63a0122fc199994fd7053Irfan Sheriff        if (visible) {
4986b66e9e4c95b1c866ea63a0122fc199994fd7053Irfan Sheriff            Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(mWalledGardenUrl));
4996b66e9e4c95b1c866ea63a0122fc199994fd7053Irfan Sheriff            intent.setFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT | Intent.FLAG_ACTIVITY_NEW_TASK);
5006b66e9e4c95b1c866ea63a0122fc199994fd7053Irfan Sheriff
5016b66e9e4c95b1c866ea63a0122fc199994fd7053Irfan Sheriff            CharSequence title = r.getString(R.string.wifi_available_sign_in, 0);
5026b66e9e4c95b1c866ea63a0122fc199994fd7053Irfan Sheriff            CharSequence details = r.getString(R.string.wifi_available_sign_in_detailed,
5036b66e9e4c95b1c866ea63a0122fc199994fd7053Irfan Sheriff                    mConnectionInfo.getSSID());
5046b66e9e4c95b1c866ea63a0122fc199994fd7053Irfan Sheriff
5056b66e9e4c95b1c866ea63a0122fc199994fd7053Irfan Sheriff            Notification notification = new Notification();
5066b66e9e4c95b1c866ea63a0122fc199994fd7053Irfan Sheriff            notification.when = 0;
5076b66e9e4c95b1c866ea63a0122fc199994fd7053Irfan Sheriff            notification.icon = com.android.internal.R.drawable.stat_notify_wifi_in_range;
5086b66e9e4c95b1c866ea63a0122fc199994fd7053Irfan Sheriff            notification.flags = Notification.FLAG_AUTO_CANCEL;
5096b66e9e4c95b1c866ea63a0122fc199994fd7053Irfan Sheriff            notification.contentIntent = PendingIntent.getActivity(mContext, 0, intent, 0);
5106b66e9e4c95b1c866ea63a0122fc199994fd7053Irfan Sheriff            notification.tickerText = title;
5116b66e9e4c95b1c866ea63a0122fc199994fd7053Irfan Sheriff            notification.setLatestEventInfo(mContext, title, details, notification.contentIntent);
5126b66e9e4c95b1c866ea63a0122fc199994fd7053Irfan Sheriff
5136b66e9e4c95b1c866ea63a0122fc199994fd7053Irfan Sheriff            notificationManager.notify(WALLED_GARDEN_NOTIFICATION_ID, 1, notification);
5146b66e9e4c95b1c866ea63a0122fc199994fd7053Irfan Sheriff        } else {
5156b66e9e4c95b1c866ea63a0122fc199994fd7053Irfan Sheriff            notificationManager.cancel(WALLED_GARDEN_NOTIFICATION_ID, 1);
5166b66e9e4c95b1c866ea63a0122fc199994fd7053Irfan Sheriff        }
5176b66e9e4c95b1c866ea63a0122fc199994fd7053Irfan Sheriff        mWalledGardenNotificationShown = visible;
5188dc6a1b2823f374a176fb21b8a174664a5f825faIsaac Levy    }
5198dc6a1b2823f374a176fb21b8a174664a5f825faIsaac Levy
5206b66e9e4c95b1c866ea63a0122fc199994fd7053Irfan Sheriff    private void setDisabledNetworkNotificationVisible(boolean visible) {
5216b66e9e4c95b1c866ea63a0122fc199994fd7053Irfan Sheriff        // If it should be hidden and it is already hidden, then noop
5226b66e9e4c95b1c866ea63a0122fc199994fd7053Irfan Sheriff        if (!visible && !mDisabledNotificationShown) {
5236b66e9e4c95b1c866ea63a0122fc199994fd7053Irfan Sheriff            return;
5246b66e9e4c95b1c866ea63a0122fc199994fd7053Irfan Sheriff        }
5256b66e9e4c95b1c866ea63a0122fc199994fd7053Irfan Sheriff
5266b66e9e4c95b1c866ea63a0122fc199994fd7053Irfan Sheriff        Resources r = Resources.getSystem();
5276b66e9e4c95b1c866ea63a0122fc199994fd7053Irfan Sheriff        NotificationManager notificationManager = (NotificationManager) mContext
5286b66e9e4c95b1c866ea63a0122fc199994fd7053Irfan Sheriff            .getSystemService(Context.NOTIFICATION_SERVICE);
5296b66e9e4c95b1c866ea63a0122fc199994fd7053Irfan Sheriff
5306b66e9e4c95b1c866ea63a0122fc199994fd7053Irfan Sheriff        if (visible) {
5316b66e9e4c95b1c866ea63a0122fc199994fd7053Irfan Sheriff            CharSequence title = r.getText(R.string.wifi_watchdog_network_disabled);
5326b66e9e4c95b1c866ea63a0122fc199994fd7053Irfan Sheriff            String msg = mConnectionInfo.getSSID() +
5336b66e9e4c95b1c866ea63a0122fc199994fd7053Irfan Sheriff                r.getText(R.string.wifi_watchdog_network_disabled_detailed);
5346b66e9e4c95b1c866ea63a0122fc199994fd7053Irfan Sheriff
5356b66e9e4c95b1c866ea63a0122fc199994fd7053Irfan Sheriff            Notification wifiDisabledWarning = new Notification.Builder(mContext)
5366b66e9e4c95b1c866ea63a0122fc199994fd7053Irfan Sheriff                .setSmallIcon(R.drawable.stat_sys_warning)
5376b66e9e4c95b1c866ea63a0122fc199994fd7053Irfan Sheriff                .setDefaults(Notification.DEFAULT_ALL)
5386b66e9e4c95b1c866ea63a0122fc199994fd7053Irfan Sheriff                .setTicker(title)
5396b66e9e4c95b1c866ea63a0122fc199994fd7053Irfan Sheriff                .setContentTitle(title)
5406b66e9e4c95b1c866ea63a0122fc199994fd7053Irfan Sheriff                .setContentText(msg)
5416b66e9e4c95b1c866ea63a0122fc199994fd7053Irfan Sheriff                .setContentIntent(PendingIntent.getActivity(mContext, 0,
5426b66e9e4c95b1c866ea63a0122fc199994fd7053Irfan Sheriff                            new Intent(WifiManager.ACTION_PICK_WIFI_NETWORK)
5436b66e9e4c95b1c866ea63a0122fc199994fd7053Irfan Sheriff                            .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK), 0))
5446b66e9e4c95b1c866ea63a0122fc199994fd7053Irfan Sheriff                .setWhen(System.currentTimeMillis())
5456b66e9e4c95b1c866ea63a0122fc199994fd7053Irfan Sheriff                .setAutoCancel(true)
5466b66e9e4c95b1c866ea63a0122fc199994fd7053Irfan Sheriff                .getNotification();
5476b66e9e4c95b1c866ea63a0122fc199994fd7053Irfan Sheriff
5486b66e9e4c95b1c866ea63a0122fc199994fd7053Irfan Sheriff            notificationManager.notify(DISABLED_NETWORK_NOTIFICATION_ID, 1, wifiDisabledWarning);
5496b66e9e4c95b1c866ea63a0122fc199994fd7053Irfan Sheriff        } else {
5506b66e9e4c95b1c866ea63a0122fc199994fd7053Irfan Sheriff            notificationManager.cancel(DISABLED_NETWORK_NOTIFICATION_ID, 1);
5518dc6a1b2823f374a176fb21b8a174664a5f825faIsaac Levy        }
5526b66e9e4c95b1c866ea63a0122fc199994fd7053Irfan Sheriff        mDisabledNotificationShown = visible;
553654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    }
554654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
555654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    class DefaultState extends State {
556654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        @Override
557654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        public boolean processMessage(Message msg) {
558d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy            switch (msg.what) {
559d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                case EVENT_WATCHDOG_SETTINGS_CHANGE:
560d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                    updateSettings();
5617f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff                    if (DBG) {
5627f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff                        log("Updating wifi-watchdog secure settings");
563d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                    }
564d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                    return HANDLED;
565d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy            }
5667f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff            if (DBG) {
5677f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff                log("Caught message " + msg.what + " in state " +
568654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                        getCurrentState().getName());
569654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            }
570654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            return HANDLED;
571654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        }
572654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    }
573654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
574654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    class WatchdogDisabledState extends State {
575654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        @Override
576654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        public boolean processMessage(Message msg) {
577654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            switch (msg.what) {
578654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                case EVENT_WATCHDOG_TOGGLED:
579654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    if (isWatchdogEnabled())
580654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                        transitionTo(mNotConnectedState);
581654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    return HANDLED;
582654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            }
583654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            return NOT_HANDLED;
584654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        }
585654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    }
586654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
587654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    class WatchdogEnabledState extends State {
588654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        @Override
589654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        public void enter() {
590654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            resetWatchdogState();
591654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            mContext.registerReceiver(mBroadcastReceiver, mIntentFilter);
5927f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff            if (DBG) log("WifiWatchdogService enabled");
593654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        }
594654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
595654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        @Override
596654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        public boolean processMessage(Message msg) {
597654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            switch (msg.what) {
598654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                case EVENT_WATCHDOG_TOGGLED:
599654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    if (!isWatchdogEnabled())
600654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                        transitionTo(mWatchdogDisabledState);
601654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    return HANDLED;
602654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                case EVENT_NETWORK_STATE_CHANGE:
603654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    Intent stateChangeIntent = (Intent) msg.obj;
604654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    NetworkInfo networkInfo = (NetworkInfo)
605654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                            stateChangeIntent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
606654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
6076b66e9e4c95b1c866ea63a0122fc199994fd7053Irfan Sheriff                    setDisabledNetworkNotificationVisible(false);
6086b66e9e4c95b1c866ea63a0122fc199994fd7053Irfan Sheriff                    setWalledGardenNotificationVisible(false);
609654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    switch (networkInfo.getState()) {
610654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                        case CONNECTED:
61188bae17cfd3de40758c5296d15f012f06f08748aIsaac Levy                            WifiInfo wifiInfo = (WifiInfo)
61288bae17cfd3de40758c5296d15f012f06f08748aIsaac Levy                                stateChangeIntent.getParcelableExtra(WifiManager.EXTRA_WIFI_INFO);
613654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                            if (wifiInfo == null) {
6147f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff                                loge("Connected --> WifiInfo object null!");
615654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                                return HANDLED;
616654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                            }
617654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
618654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                            if (wifiInfo.getSSID() == null || wifiInfo.getBSSID() == null) {
6197f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff                                loge("Received wifiInfo object with null elts: "
620654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                                        + wifiInfoToStr(wifiInfo));
621654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                                return HANDLED;
622654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                            }
623654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
624654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                            initConnection(wifiInfo);
6258dc6a1b2823f374a176fb21b8a174664a5f825faIsaac Levy                            mConnectionInfo = wifiInfo;
6268dc6a1b2823f374a176fb21b8a174664a5f825faIsaac Levy                            updateBssids();
627654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                            transitionTo(mDnsCheckingState);
628654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                            mNetEventCounter++;
62932f04e9009046f72242932bf4e820802148e423aIrfan Sheriff                            break;
63032f04e9009046f72242932bf4e820802148e423aIrfan Sheriff                        default:
631654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                            mNetEventCounter++;
632654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                            transitionTo(mNotConnectedState);
63332f04e9009046f72242932bf4e820802148e423aIrfan Sheriff                            break;
634654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    }
635654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    return HANDLED;
636654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                case EVENT_WIFI_RADIO_STATE_CHANGE:
637654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    if ((Integer) msg.obj == WifiManager.WIFI_STATE_DISABLING) {
6387f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff                        if (DBG) log("WifiStateDisabling -- Resetting WatchdogState");
639654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                        resetWatchdogState();
640654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                        mNetEventCounter++;
641654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                        transitionTo(mNotConnectedState);
642654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    }
643654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    return HANDLED;
644654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            }
645654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
646654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            return NOT_HANDLED;
647654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        }
648654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
649654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        /**
650654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy         * @param wifiInfo Info object with non-null ssid and bssid
651654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy         */
652654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        private void initConnection(WifiInfo wifiInfo) {
6537f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff            if (DBG) {
6547f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff                log("Connected:: old " + wifiInfoToStr(mConnectionInfo) +
655654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                        " ==> new " + wifiInfoToStr(wifiInfo));
656654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            }
657654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
6588dc6a1b2823f374a176fb21b8a174664a5f825faIsaac Levy            if (mConnectionInfo == null || !wifiInfo.getSSID().equals(mConnectionInfo.getSSID())) {
659654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                resetWatchdogState();
6608dc6a1b2823f374a176fb21b8a174664a5f825faIsaac Levy            } else if (!wifiInfo.getBSSID().equals(mConnectionInfo.getBSSID())) {
661654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                mDisableAPNextFailure = false;
662654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            }
663654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        }
664654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
665654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        @Override
666654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        public void exit() {
667654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            mContext.unregisterReceiver(mBroadcastReceiver);
6687f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff            if (DBG) log("WifiWatchdogService disabled");
669654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        }
670654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    }
671654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
672654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    class NotConnectedState extends State {
673654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    }
674654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
675654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    class ConnectedState extends State {
676654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        @Override
677654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        public boolean processMessage(Message msg) {
678654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            switch (msg.what) {
679654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                case EVENT_SCAN_RESULTS_AVAILABLE:
6808dc6a1b2823f374a176fb21b8a174664a5f825faIsaac Levy                    updateBssids();
681654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    return HANDLED;
682d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                case EVENT_WATCHDOG_SETTINGS_CHANGE:
683d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                    // Stop current checks, but let state update
684d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                    transitionTo(mOnlineWatchState);
685d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                    return NOT_HANDLED;
686654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            }
687654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            return NOT_HANDLED;
688654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        }
689654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    }
690654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
691654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    class DnsCheckingState extends State {
69279e43f679d6102066ee9eff862912806f53bb0e8Isaac Levy        List<InetAddress> mDnsList;
69379e43f679d6102066ee9eff862912806f53bb0e8Isaac Levy        int[] dnsCheckSuccesses;
69479e43f679d6102066ee9eff862912806f53bb0e8Isaac Levy        String dnsCheckLogStr;
69579e43f679d6102066ee9eff862912806f53bb0e8Isaac Levy        String[] dnsResponseStrs;
69679e43f679d6102066ee9eff862912806f53bb0e8Isaac Levy        /** Keeps track of active dns pings.  Map is from pingID to index in mDnsList */
69779e43f679d6102066ee9eff862912806f53bb0e8Isaac Levy        HashMap<Integer, Integer> idDnsMap = new HashMap<Integer, Integer>();
698654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
699654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        @Override
700654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        public void enter() {
70179e43f679d6102066ee9eff862912806f53bb0e8Isaac Levy            mDnsList = mDnsPinger.getDnsList();
70279e43f679d6102066ee9eff862912806f53bb0e8Isaac Levy            int numDnses = mDnsList.size();
70379e43f679d6102066ee9eff862912806f53bb0e8Isaac Levy            dnsCheckSuccesses = new int[numDnses];
70479e43f679d6102066ee9eff862912806f53bb0e8Isaac Levy            dnsResponseStrs = new String[numDnses];
70579e43f679d6102066ee9eff862912806f53bb0e8Isaac Levy            for (int i = 0; i < numDnses; i++)
70679e43f679d6102066ee9eff862912806f53bb0e8Isaac Levy                dnsResponseStrs[i] = "";
70779e43f679d6102066ee9eff862912806f53bb0e8Isaac Levy
708654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            if (DBG) {
709d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                dnsCheckLogStr = String.format("Pinging %s on ssid [%s]: ",
71079e43f679d6102066ee9eff862912806f53bb0e8Isaac Levy                        mDnsList, mConnectionInfo.getSSID());
7117f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff                log(dnsCheckLogStr);
712654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            }
713654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
71479e43f679d6102066ee9eff862912806f53bb0e8Isaac Levy            idDnsMap.clear();
715d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy            for (int i=0; i < mNumDnsPings; i++) {
71679e43f679d6102066ee9eff862912806f53bb0e8Isaac Levy                for (int j = 0; j < numDnses; j++) {
71779e43f679d6102066ee9eff862912806f53bb0e8Isaac Levy                    idDnsMap.put(mDnsPinger.pingDnsAsync(mDnsList.get(j), mDnsPingTimeoutMs,
718998196d64d35c1767dbb08f059fe3af171e44e1dIrfan Sheriff                            DNS_START_DELAY_MS + DNS_INTRATEST_PING_INTERVAL_MS * i), j);
71979e43f679d6102066ee9eff862912806f53bb0e8Isaac Levy                }
720d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy            }
721654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        }
722654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
723654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        @Override
724654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        public boolean processMessage(Message msg) {
725d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy            if (msg.what != DnsPinger.DNS_PING_RESULT) {
726654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                return NOT_HANDLED;
727654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            }
728654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
729d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy            int pingID = msg.arg1;
730d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy            int pingResponseTime = msg.arg2;
731654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
73279e43f679d6102066ee9eff862912806f53bb0e8Isaac Levy            Integer dnsServerId = idDnsMap.get(pingID);
73379e43f679d6102066ee9eff862912806f53bb0e8Isaac Levy            if (dnsServerId == null) {
7347f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff                loge("Received a Dns response with unknown ID!");
735d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                return HANDLED;
736d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy            }
73779e43f679d6102066ee9eff862912806f53bb0e8Isaac Levy
73879e43f679d6102066ee9eff862912806f53bb0e8Isaac Levy            idDnsMap.remove(pingID);
739654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            if (pingResponseTime >= 0)
74079e43f679d6102066ee9eff862912806f53bb0e8Isaac Levy                dnsCheckSuccesses[dnsServerId]++;
741654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
742654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            if (DBG) {
743654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                if (pingResponseTime >= 0) {
74479e43f679d6102066ee9eff862912806f53bb0e8Isaac Levy                    dnsResponseStrs[dnsServerId] += "|" + pingResponseTime;
745654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                } else {
74679e43f679d6102066ee9eff862912806f53bb0e8Isaac Levy                    dnsResponseStrs[dnsServerId] += "|x";
747654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                }
748654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            }
749654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
750654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            /**
751654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy             * After a full ping count, if we have more responses than this
752654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy             * cutoff, the outcome is success; else it is 'failure'.
753654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy             */
754654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
755654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            /**
756654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy             * Our final success count will be at least this big, so we're
757654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy             * guaranteed to succeed.
758654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy             */
75979e43f679d6102066ee9eff862912806f53bb0e8Isaac Levy            if (dnsCheckSuccesses[dnsServerId] >= mMinDnsResponses) {
760654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                // DNS CHECKS OK, NOW WALLED GARDEN
761654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                if (DBG) {
7627f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff                    log(makeLogString() + "  SUCCESS");
763654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                }
764654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
765654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                if (!shouldCheckWalledGarden()) {
766654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    transitionTo(mOnlineWatchState);
767654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    return HANDLED;
768654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                }
769654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
770a81ac7c450d9d534c46abc7000cc53779a72c283Irfan Sheriff                transitionTo(mDelayWalledGardenState);
771654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                return HANDLED;
772654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            }
773654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
77479e43f679d6102066ee9eff862912806f53bb0e8Isaac Levy            if (idDnsMap.isEmpty()) {
775654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                if (DBG) {
7767f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff                    log(makeLogString() + "  FAILURE");
777654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                }
778654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                transitionTo(mDnsCheckFailureState);
779654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                return HANDLED;
780654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            }
781654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
782654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            return HANDLED;
783654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        }
784654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
78579e43f679d6102066ee9eff862912806f53bb0e8Isaac Levy        private String makeLogString() {
78679e43f679d6102066ee9eff862912806f53bb0e8Isaac Levy            String logStr = dnsCheckLogStr;
78779e43f679d6102066ee9eff862912806f53bb0e8Isaac Levy            for (String respStr : dnsResponseStrs)
78879e43f679d6102066ee9eff862912806f53bb0e8Isaac Levy                logStr += " [" + respStr + "]";
78979e43f679d6102066ee9eff862912806f53bb0e8Isaac Levy            return logStr;
79079e43f679d6102066ee9eff862912806f53bb0e8Isaac Levy        }
79179e43f679d6102066ee9eff862912806f53bb0e8Isaac Levy
792d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy        @Override
793d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy        public void exit() {
794d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy            mDnsPinger.cancelPings();
795d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy        }
796d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy
797654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        private boolean shouldCheckWalledGarden() {
798d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy            if (!mWalledGardenTestEnabled) {
7997f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff                if (DBG)
8007f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff                    log("Skipping walled garden check - disabled");
801654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                return false;
802654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            }
803d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy            long waitTime = waitTime(mWalledGardenIntervalMs,
804654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    mLastWalledGardenCheckTime);
805654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            if (waitTime > 0) {
806654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                if (DBG) {
8077f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff                    log("Skipping walled garden check - wait " +
808654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                            waitTime + " ms.");
809654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                }
810654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                return false;
811654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            }
812654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            return true;
813654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        }
814654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    }
815654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
816a81ac7c450d9d534c46abc7000cc53779a72c283Irfan Sheriff    class DelayWalledGardenState extends State {
817a81ac7c450d9d534c46abc7000cc53779a72c283Irfan Sheriff        @Override
818a81ac7c450d9d534c46abc7000cc53779a72c283Irfan Sheriff        public void enter() {
819a81ac7c450d9d534c46abc7000cc53779a72c283Irfan Sheriff            sendMessageDelayed(MESSAGE_DELAYED_WALLED_GARDEN_CHECK, WALLED_GARDEN_START_DELAY_MS);
820a81ac7c450d9d534c46abc7000cc53779a72c283Irfan Sheriff        }
821a81ac7c450d9d534c46abc7000cc53779a72c283Irfan Sheriff
822a81ac7c450d9d534c46abc7000cc53779a72c283Irfan Sheriff        @Override
823a81ac7c450d9d534c46abc7000cc53779a72c283Irfan Sheriff        public boolean processMessage(Message msg) {
824a81ac7c450d9d534c46abc7000cc53779a72c283Irfan Sheriff            switch (msg.what) {
825a81ac7c450d9d534c46abc7000cc53779a72c283Irfan Sheriff                case MESSAGE_DELAYED_WALLED_GARDEN_CHECK:
826a81ac7c450d9d534c46abc7000cc53779a72c283Irfan Sheriff                    mLastWalledGardenCheckTime = SystemClock.elapsedRealtime();
827a81ac7c450d9d534c46abc7000cc53779a72c283Irfan Sheriff                    if (isWalledGardenConnection()) {
828a81ac7c450d9d534c46abc7000cc53779a72c283Irfan Sheriff                        if (DBG) log("Walled garden test complete - walled garden detected");
829a81ac7c450d9d534c46abc7000cc53779a72c283Irfan Sheriff                        transitionTo(mWalledGardenState);
830a81ac7c450d9d534c46abc7000cc53779a72c283Irfan Sheriff                    } else {
831a81ac7c450d9d534c46abc7000cc53779a72c283Irfan Sheriff                        if (DBG) log("Walled garden test complete - online");
832a81ac7c450d9d534c46abc7000cc53779a72c283Irfan Sheriff                        transitionTo(mOnlineWatchState);
833a81ac7c450d9d534c46abc7000cc53779a72c283Irfan Sheriff                    }
834a81ac7c450d9d534c46abc7000cc53779a72c283Irfan Sheriff                    return HANDLED;
835a81ac7c450d9d534c46abc7000cc53779a72c283Irfan Sheriff                default:
836a81ac7c450d9d534c46abc7000cc53779a72c283Irfan Sheriff                    return NOT_HANDLED;
837a81ac7c450d9d534c46abc7000cc53779a72c283Irfan Sheriff            }
838a81ac7c450d9d534c46abc7000cc53779a72c283Irfan Sheriff        }
839a81ac7c450d9d534c46abc7000cc53779a72c283Irfan Sheriff    }
840a81ac7c450d9d534c46abc7000cc53779a72c283Irfan Sheriff
841654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    class OnlineWatchState extends State {
842654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        /**
843654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy         * Signals a short-wait message is enqueued for the current 'guard' counter
844654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy         */
845654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        boolean unstableSignalChecks = false;
846654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
847654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        /**
848654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy         * The signal is unstable.  We should enqueue a short-wait check, if one is enqueued
849654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy         * already
850654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy         */
851654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        boolean signalUnstable = false;
852654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
853654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        /**
854654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy         * A monotonic counter to ensure that at most one check message will be processed from any
855654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy         * set of check messages currently enqueued.  Avoids duplicate checks when a low-signal
856654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy         * event is observed.
857654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy         */
858654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        int checkGuard = 0;
859654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        Long lastCheckTime = null;
860654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
86179e43f679d6102066ee9eff862912806f53bb0e8Isaac Levy        /** Keeps track of dns pings.  Map is from pingID to InetAddress used for ping */
86279e43f679d6102066ee9eff862912806f53bb0e8Isaac Levy        HashMap<Integer, InetAddress> pingInfoMap = new HashMap<Integer, InetAddress>();
863d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy
864654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        @Override
865654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        public void enter() {
866654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            lastCheckTime = SystemClock.elapsedRealtime();
867654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            signalUnstable = false;
868654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            checkGuard++;
869654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            unstableSignalChecks = false;
87079e43f679d6102066ee9eff862912806f53bb0e8Isaac Levy            pingInfoMap.clear();
871654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            triggerSingleDnsCheck();
872654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        }
873654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
874654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        @Override
875654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        public boolean processMessage(Message msg) {
876654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            switch (msg.what) {
877654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                case EVENT_RSSI_CHANGE:
878654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    if (msg.arg1 != mNetEventCounter) {
879654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                        if (DBG) {
8807f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff                            log("Rssi change message out of sync, ignoring");
881654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                        }
882654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                        return HANDLED;
883654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    }
884654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    int newRssi = msg.arg2;
885654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    signalUnstable = !rssiStrengthAboveCutoff(newRssi);
8867f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff                    if (DBG) {
8877f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff                        log("OnlineWatchState:: new rssi " + newRssi + " --> level " +
888654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                                WifiManager.calculateSignalLevel(newRssi, WIFI_SIGNAL_LEVELS));
889654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    }
890654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
891654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    if (signalUnstable && !unstableSignalChecks) {
8927f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff                        if (DBG) {
8937f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff                            log("Sending triggered check msg");
894654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                        }
895654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                        triggerSingleDnsCheck();
896654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    }
897654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    return HANDLED;
898654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                case MESSAGE_SINGLE_DNS_CHECK:
899654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    if (msg.arg1 != checkGuard) {
9007f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff                        if (DBG) {
9017f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff                            log("Single check msg out of sync, ignoring.");
902654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                        }
903654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                        return HANDLED;
904654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    }
905654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    lastCheckTime = SystemClock.elapsedRealtime();
90679e43f679d6102066ee9eff862912806f53bb0e8Isaac Levy                    pingInfoMap.clear();
90779e43f679d6102066ee9eff862912806f53bb0e8Isaac Levy                    for (InetAddress curDns: mDnsPinger.getDnsList()) {
90879e43f679d6102066ee9eff862912806f53bb0e8Isaac Levy                        pingInfoMap.put(mDnsPinger.pingDnsAsync(curDns, mDnsPingTimeoutMs, 0),
90979e43f679d6102066ee9eff862912806f53bb0e8Isaac Levy                                curDns);
91079e43f679d6102066ee9eff862912806f53bb0e8Isaac Levy                    }
911d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                    return HANDLED;
912d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                case DnsPinger.DNS_PING_RESULT:
91379e43f679d6102066ee9eff862912806f53bb0e8Isaac Levy                    InetAddress curDnsServer = pingInfoMap.get(msg.arg1);
91479e43f679d6102066ee9eff862912806f53bb0e8Isaac Levy                    if (curDnsServer == null) {
915d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                        return HANDLED;
916d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                    }
91779e43f679d6102066ee9eff862912806f53bb0e8Isaac Levy                    pingInfoMap.remove(msg.arg1);
918d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy                    int responseTime = msg.arg2;
919654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    if (responseTime >= 0) {
9207f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff                        if (DBG) {
9217f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff                            log("Single DNS ping OK. Response time: "
92279e43f679d6102066ee9eff862912806f53bb0e8Isaac Levy                                    + responseTime + " from DNS " + curDnsServer);
923654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                        }
92479e43f679d6102066ee9eff862912806f53bb0e8Isaac Levy                        pingInfoMap.clear();
925654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
926654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                        checkGuard++;
927654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                        unstableSignalChecks = false;
928654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                        triggerSingleDnsCheck();
929654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    } else {
93079e43f679d6102066ee9eff862912806f53bb0e8Isaac Levy                        if (pingInfoMap.isEmpty()) {
93179e43f679d6102066ee9eff862912806f53bb0e8Isaac Levy                            if (DBG) {
9327f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff                                log("Single dns ping failure. All dns servers failed, "
93379e43f679d6102066ee9eff862912806f53bb0e8Isaac Levy                                        + "starting full checks.");
93479e43f679d6102066ee9eff862912806f53bb0e8Isaac Levy                            }
93579e43f679d6102066ee9eff862912806f53bb0e8Isaac Levy                            transitionTo(mDnsCheckingState);
936654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                        }
937654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    }
938654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    return HANDLED;
939654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            }
940654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            return NOT_HANDLED;
941654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        }
942654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
943d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy        @Override
944d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy        public void exit() {
945d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy            mDnsPinger.cancelPings();
946d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy        }
947d2fe04b71a89a0608eb7c67065dead2a1f540122Isaac Levy
948654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        /**
949d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy         * Times a dns check with an interval based on {@link #signalUnstable}
950654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy         */
951654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        private void triggerSingleDnsCheck() {
952654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            long waitInterval;
953654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            if (signalUnstable) {
954d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                waitInterval = mDnsCheckShortIntervalMs;
955654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                unstableSignalChecks = true;
956654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            } else {
957d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                waitInterval = mDnsCheckLongIntervalMs;
958654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            }
959654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            sendMessageDelayed(obtainMessage(MESSAGE_SINGLE_DNS_CHECK, checkGuard, 0),
960654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    waitTime(waitInterval, lastCheckTime));
961654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        }
962654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    }
963654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
964654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    class DnsCheckFailureState extends State {
9654ad39d6ac16961df0e7a3e4b4e7075aaa5202787Isaac Levy
966654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        @Override
967654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        public void enter() {
968d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy            mNumCheckFailures++;
969654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            obtainMessage(MESSAGE_HANDLE_BAD_AP, mNetEventCounter, 0).sendToTarget();
970654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        }
971654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
972654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        @Override
973654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        public boolean processMessage(Message msg) {
974654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            if (msg.what != MESSAGE_HANDLE_BAD_AP) {
975654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                return NOT_HANDLED;
976654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            }
977654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
978654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            if (msg.arg1 != mNetEventCounter) {
9797f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff                if (DBG) {
9807f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff                    log("Msg out of sync, ignoring...");
981654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                }
982654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                return HANDLED;
983654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            }
984654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
9858dc6a1b2823f374a176fb21b8a174664a5f825faIsaac Levy            if (mDisableAPNextFailure || mNumCheckFailures >= mBssids.size()
9868dc6a1b2823f374a176fb21b8a174664a5f825faIsaac Levy                    || mNumCheckFailures >= mMaxSsidBlacklists) {
9879b2886e24301e5d4e7052ec4a6eaff273d3f516cRobert Greenwalt                if (sWifiOnly) {
9887f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff                    log("Would disable bad network, but device has no mobile data!" +
9894ad39d6ac16961df0e7a3e4b4e7075aaa5202787Isaac Levy                            "  Going idle...");
9904ad39d6ac16961df0e7a3e4b4e7075aaa5202787Isaac Levy                    // This state should be called idle -- will be changing flow.
9914ad39d6ac16961df0e7a3e4b4e7075aaa5202787Isaac Levy                    transitionTo(mNotConnectedState);
9924ad39d6ac16961df0e7a3e4b4e7075aaa5202787Isaac Levy                    return HANDLED;
9934ad39d6ac16961df0e7a3e4b4e7075aaa5202787Isaac Levy                }
9948dc6a1b2823f374a176fb21b8a174664a5f825faIsaac Levy
995654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                // TODO : Unban networks if they had low signal ?
9967f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff                log("Disabling current SSID " + wifiInfoToStr(mConnectionInfo)
997d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                        + ".  " + "numCheckFailures " + mNumCheckFailures
998d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                        + ", numAPs " + mBssids.size());
9998dc6a1b2823f374a176fb21b8a174664a5f825faIsaac Levy                int networkId = mConnectionInfo.getNetworkId();
10008dc6a1b2823f374a176fb21b8a174664a5f825faIsaac Levy                if (!mHasConnectedWifiManager) {
10018dc6a1b2823f374a176fb21b8a174664a5f825faIsaac Levy                    mWifiManager.asyncConnect(mContext, getHandler());
10028dc6a1b2823f374a176fb21b8a174664a5f825faIsaac Levy                    mHasConnectedWifiManager = true;
10038dc6a1b2823f374a176fb21b8a174664a5f825faIsaac Levy                }
10048dc6a1b2823f374a176fb21b8a174664a5f825faIsaac Levy                mWifiManager.disableNetwork(networkId, WifiConfiguration.DISABLED_DNS_FAILURE);
10058dc6a1b2823f374a176fb21b8a174664a5f825faIsaac Levy                if (mShowDisabledNotification && mConnectionInfo.isExplicitConnect()) {
10066b66e9e4c95b1c866ea63a0122fc199994fd7053Irfan Sheriff                    setDisabledNetworkNotificationVisible(true);
1007d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                }
1008654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                transitionTo(mNotConnectedState);
1009654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            } else {
10107f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff                log("Blacklisting current BSSID.  " + wifiInfoToStr(mConnectionInfo)
1011d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                       + "numCheckFailures " + mNumCheckFailures + ", numAPs " + mBssids.size());
1012654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
10138dc6a1b2823f374a176fb21b8a174664a5f825faIsaac Levy                mWifiManager.addToBlacklist(mConnectionInfo.getBSSID());
1014654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                mWifiManager.reassociate();
1015654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                transitionTo(mBlacklistedApState);
1016654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            }
1017654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            return HANDLED;
1018654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        }
1019654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    }
1020654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
1021654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    class WalledGardenState extends State {
1022654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        @Override
1023654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        public void enter() {
1024654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            obtainMessage(MESSAGE_HANDLE_WALLED_GARDEN, mNetEventCounter, 0).sendToTarget();
1025654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        }
1026654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
1027654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        @Override
1028654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        public boolean processMessage(Message msg) {
1029654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            if (msg.what != MESSAGE_HANDLE_WALLED_GARDEN) {
1030654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                return NOT_HANDLED;
1031654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            }
1032654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
1033654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            if (msg.arg1 != mNetEventCounter) {
10347f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff                if (DBG) {
10357f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff                    log("WalledGardenState::Msg out of sync, ignoring...");
1036654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                }
1037654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                return HANDLED;
1038654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            }
10396b66e9e4c95b1c866ea63a0122fc199994fd7053Irfan Sheriff            setWalledGardenNotificationVisible(true);
1040654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            transitionTo(mOnlineWatchState);
1041654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            return HANDLED;
1042654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        }
1043654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    }
1044654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
1045654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    class BlacklistedApState extends State {
1046654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        @Override
1047654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        public void enter() {
1048654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            mDisableAPNextFailure = true;
1049654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            sendMessageDelayed(obtainMessage(MESSAGE_NETWORK_FOLLOWUP, mNetEventCounter, 0),
1050d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                    mBlacklistFollowupIntervalMs);
1051654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        }
1052654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
1053654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        @Override
1054654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        public boolean processMessage(Message msg) {
1055654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            if (msg.what != MESSAGE_NETWORK_FOLLOWUP) {
1056654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                return NOT_HANDLED;
1057654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            }
1058654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
1059654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            if (msg.arg1 != mNetEventCounter) {
10607f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff                if (DBG) {
10617f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff                    log("BlacklistedApState::Msg out of sync, ignoring...");
1062654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                }
1063654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                return HANDLED;
1064654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            }
1065654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
1066654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            transitionTo(mDnsCheckingState);
1067654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            return HANDLED;
1068654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        }
1069654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    }
1070d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy
1071d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy
1072d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy    /**
1073d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy     * Convenience function for retrieving a single secure settings value
1074d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy     * as a string with a default value.
1075d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy     *
1076d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy     * @param cr The ContentResolver to access.
1077d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy     * @param name The name of the setting to retrieve.
1078d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy     * @param def Value to return if the setting is not defined.
1079d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy     *
1080d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy     * @return The setting's current value, or 'def' if it is not defined
1081d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy     */
1082d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy    private static String getSettingsStr(ContentResolver cr, String name, String def) {
1083d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy        String v = Settings.Secure.getString(cr, name);
1084d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy        return v != null ? v : def;
1085d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy    }
1086d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy
1087d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy    /**
1088d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy     * Convenience function for retrieving a single secure settings value
1089d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy     * as a boolean.  Note that internally setting values are always
1090d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy     * stored as strings; this function converts the string to a boolean
1091d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy     * for you.  The default value will be returned if the setting is
1092d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy     * not defined or not a valid boolean.
1093d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy     *
1094d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy     * @param cr The ContentResolver to access.
1095d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy     * @param name The name of the setting to retrieve.
1096d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy     * @param def Value to return if the setting is not defined.
1097d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy     *
1098d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy     * @return The setting's current value, or 'def' if it is not defined
1099d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy     * or not a valid boolean.
1100d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy     */
1101d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy    private static boolean getSettingsBoolean(ContentResolver cr, String name, boolean def) {
1102d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy        return Settings.Secure.getInt(cr, name, def ? 1 : 0) == 1;
1103d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy    }
1104d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy
1105d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy    /**
1106d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy     * Convenience function for updating a single settings value as an
1107d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy     * integer. This will either create a new entry in the table if the
1108d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy     * given name does not exist, or modify the value of the existing row
1109d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy     * with that name.  Note that internally setting values are always
1110d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy     * stored as strings, so this function converts the given value to a
1111d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy     * string before storing it.
1112d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy     *
1113d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy     * @param cr The ContentResolver to access.
1114d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy     * @param name The name of the setting to modify.
1115d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy     * @param value The new value for the setting.
1116d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy     * @return true if the value was set, false on database errors
1117d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy     */
1118d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy    private static boolean putSettingsBoolean(ContentResolver cr, String name, boolean value) {
1119d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy        return Settings.Secure.putInt(cr, name, value ? 1 : 0);
1120d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy    }
1121d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy
11227f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff    private void log(String s) {
11237f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff        Log.d(TAG, s);
11247f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff    }
1125d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy
11267f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff    private void loge(String s) {
11277f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff        Log.e(TAG, s);
11287f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff    }
1129654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy}
1130