WifiWatchdogStateMachine.java revision 4ad39d6ac16961df0e7a3e4b4e7075aaa5202787
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;
38654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levyimport android.util.Slog;
39654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
40654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levyimport com.android.internal.util.Protocol;
41654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levyimport com.android.internal.util.State;
42654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levyimport com.android.internal.util.StateMachine;
43654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
44654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levyimport java.io.BufferedInputStream;
45654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levyimport java.io.IOException;
46654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levyimport java.io.InputStream;
47654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levyimport java.io.PrintWriter;
48654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levyimport java.net.HttpURLConnection;
49654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levyimport java.net.URL;
50654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levyimport java.util.HashSet;
51654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levyimport java.util.List;
52654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levyimport java.util.Scanner;
53d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levyimport java.util.regex.Pattern;
54654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
55654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy/**
56654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy * {@link WifiWatchdogStateMachine} monitors the initial connection to a Wi-Fi
57654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy * network with multiple access points. After the framework successfully
58654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy * connects to an access point, the watchdog verifies connectivity by 'pinging'
59654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy * the configured DNS server using {@link DnsPinger}.
60654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy * <p>
61654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy * On DNS check failure, the BSSID is blacklisted if it is reasonably likely
62654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy * that another AP might have internet access; otherwise the SSID is disabled.
63654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy * <p>
64654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy * On DNS success, the WatchdogService initiates a walled garden check via an
65654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy * http get. A browser window is activated if a walled garden is detected.
66654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy *
67654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy * @hide
68654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy */
69654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levypublic class WifiWatchdogStateMachine extends StateMachine {
70654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
71d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy
72e046975503e7c6ebd78e35afaad88e3fb1ebfb5aIsaac Levy    private static final boolean VDBG = false;
73654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    private static final boolean DBG = true;
74654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    private static final String WWSM_TAG = "WifiWatchdogStateMachine";
75654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
76654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    private static final int WIFI_SIGNAL_LEVELS = 4;
77654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    /**
78654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy     * Low signal is defined as less than or equal to cut off
79654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy     */
80654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    private static final int LOW_SIGNAL_CUTOFF = 1;
81654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
82d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy    private static final long DEFAULT_DNS_CHECK_SHORT_INTERVAL_MS = 2 * 60 * 1000;
83d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy    private static final long DEFAULT_DNS_CHECK_LONG_INTERVAL_MS = 10 * 60 * 1000;
84d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy    private static final long DEFAULT_WALLED_GARDEN_INTERVAL_MS = 30 * 60 * 1000;
85654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
86d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy    private static final int DEFAULT_MAX_SSID_BLACKLISTS = 7;
87d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy    private static final int DEFAULT_NUM_DNS_PINGS = 5;
88d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy    private static final int DEFAULT_MIN_DNS_RESPONSES = 3;
89654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    private static final long DNS_PING_INTERVAL_MS = 100;
90654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
91d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy    private static final int DEFAULT_DNS_PING_TIMEOUT_MS = 1500;
92d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy
93d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy    private static final long DEFAULT_BLACKLIST_FOLLOWUP_INTERVAL_MS = 15 * 1000;
94d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy
95d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy    private static final String DEFAULT_WALLED_GARDEN_URL = "http://www.google.com/";
96d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy    private static final String DEFAULT_WALLED_GARDEN_PATTERN = "<title>.*Google.*</title>";
97d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy
98654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
99654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    private static final int BASE = Protocol.BASE_WIFI_WATCHDOG;
100654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
101654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    /**
102654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy     * Indicates the enable setting of WWS may have changed
103654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy     */
104654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    private static final int EVENT_WATCHDOG_TOGGLED = BASE + 1;
105654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
106654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    /**
107654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy     * Indicates the wifi network state has changed. Passed w/ original intent
108654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy     * which has a non-null networkInfo object
109654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy     */
110654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    private static final int EVENT_NETWORK_STATE_CHANGE = BASE + 2;
111654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    /**
112654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy     * Indicates the signal has changed. Passed with arg1
113654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy     * {@link #mNetEventCounter} and arg2 [raw signal strength]
114654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy     */
115654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    private static final int EVENT_RSSI_CHANGE = BASE + 3;
116654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    private static final int EVENT_SCAN_RESULTS_AVAILABLE = BASE + 4;
117654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    private static final int EVENT_WIFI_RADIO_STATE_CHANGE = BASE + 5;
118d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy    private static final int EVENT_WATCHDOG_SETTINGS_CHANGE = BASE + 6;
119654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
120654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    private static final int MESSAGE_CHECK_STEP = BASE + 100;
121654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    private static final int MESSAGE_HANDLE_WALLED_GARDEN = BASE + 101;
122654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    private static final int MESSAGE_HANDLE_BAD_AP = BASE + 102;
123654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    /**
124654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy     * arg1 == mOnlineWatchState.checkCount
125654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy     */
126654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    private static final int MESSAGE_SINGLE_DNS_CHECK = BASE + 103;
127654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    private static final int MESSAGE_NETWORK_FOLLOWUP = BASE + 104;
128654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
129654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    private Context mContext;
130654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    private ContentResolver mContentResolver;
131654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    private WifiManager mWifiManager;
132654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    private DnsPinger mDnsPinger;
133654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    private IntentFilter mIntentFilter;
134654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    private BroadcastReceiver mBroadcastReceiver;
135654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
136654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    private DefaultState mDefaultState = new DefaultState();
137654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    private WatchdogDisabledState mWatchdogDisabledState = new WatchdogDisabledState();
138654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    private WatchdogEnabledState mWatchdogEnabledState = new WatchdogEnabledState();
139654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    private NotConnectedState mNotConnectedState = new NotConnectedState();
140654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    private ConnectedState mConnectedState = new ConnectedState();
141654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    private DnsCheckingState mDnsCheckingState = new DnsCheckingState();
142654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    private OnlineWatchState mOnlineWatchState = new OnlineWatchState();
143654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    private DnsCheckFailureState mDnsCheckFailureState = new DnsCheckFailureState();
144654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    private WalledGardenState mWalledGardenState = new WalledGardenState();
145654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    private BlacklistedApState mBlacklistedApState = new BlacklistedApState();
146654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
147d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy    private long mDnsCheckShortIntervalMs;
148d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy    private long mDnsCheckLongIntervalMs;
149d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy    private long mWalledGardenIntervalMs;
150d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy    private int mMaxSsidBlacklists;
151d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy    private int mNumDnsPings;
152d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy    private int mMinDnsResponses;
153d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy    private int mDnsPingTimeoutMs;
154d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy    private long mBlacklistFollowupIntervalMs;
155d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy    private boolean mWalledGardenTestEnabled;
156d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy    private String mWalledGardenUrl;
157d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy    private Pattern mWalledGardenPattern;
158d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy
159d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy    private boolean mShowDisabledNotification;
160654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    /**
161654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy     * The {@link WifiInfo} object passed to WWSM on network broadcasts
162654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy     */
163654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    private WifiInfo mInitialConnInfo;
164654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    private int mNetEventCounter = 0;
165654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
166654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    /**
167654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy     * Currently maintained but not used, TODO
168654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy     */
169654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    private HashSet<String> mBssids = new HashSet<String>();
170d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy    private int mNumCheckFailures = 0;
171654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
172654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    private Long mLastWalledGardenCheckTime = null;
173654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
174654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    /**
175654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy     * This is set by the blacklisted state and reset when connected to a new AP.
176654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy     * It triggers a disableNetwork call if a DNS check fails.
177654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy     */
178654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    public boolean mDisableAPNextFailure = false;
1794ad39d6ac16961df0e7a3e4b4e7075aaa5202787Isaac Levy    public ConnectivityManager mConnectivityManager;
180654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
181654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    /**
182654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy     * STATE MAP
183654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy     *          Default
184654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy     *         /       \
185654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy     * Disabled     Enabled
186654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy     *             /       \
187d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy     * NotConnected      Connected
188654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy     *                  /---------\
189654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy     *               (all other states)
190654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy     */
191654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    private WifiWatchdogStateMachine(Context context) {
192654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        super(WWSM_TAG);
193654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        mContext = context;
194654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        mContentResolver = context.getContentResolver();
195654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
196654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        mDnsPinger = new DnsPinger("WifiWatchdogServer.DnsPinger", context,
197654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                ConnectivityManager.TYPE_WIFI);
198654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
199654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        setupNetworkReceiver();
200654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
201654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        // The content observer to listen needs a handler
202654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        registerForSettingsChanges();
203d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy        registerForWatchdogToggle();
204654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        addState(mDefaultState);
205654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            addState(mWatchdogDisabledState, mDefaultState);
206654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            addState(mWatchdogEnabledState, mDefaultState);
207654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                addState(mNotConnectedState, mWatchdogEnabledState);
208654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                addState(mConnectedState, mWatchdogEnabledState);
209654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    addState(mDnsCheckingState, mConnectedState);
210654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    addState(mDnsCheckFailureState, mConnectedState);
211654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    addState(mWalledGardenState, mConnectedState);
212654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    addState(mBlacklistedApState, mConnectedState);
213654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    addState(mOnlineWatchState, mConnectedState);
214654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
215654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        setInitialState(mWatchdogDisabledState);
216d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy        updateSettings();
217d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy        mShowDisabledNotification = getSettingsBoolean(mContentResolver,
218d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                Settings.Secure.WIFI_WATCHDOG_SHOW_DISABLED_NETWORK_POPUP, true);
219654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    }
220654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
221654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    public static WifiWatchdogStateMachine makeWifiWatchdogStateMachine(Context context) {
2224ad39d6ac16961df0e7a3e4b4e7075aaa5202787Isaac Levy        ContentResolver contentResolver = context.getContentResolver();
2234ad39d6ac16961df0e7a3e4b4e7075aaa5202787Isaac Levy        // Disable for wifi only devices.
2244ad39d6ac16961df0e7a3e4b4e7075aaa5202787Isaac Levy        if (Settings.Secure.getString(contentResolver, Settings.Secure.WIFI_WATCHDOG_ON) == null &&
2254ad39d6ac16961df0e7a3e4b4e7075aaa5202787Isaac Levy                "wifi-only".equals(SystemProperties.get("ro.carrier"))) {
2264ad39d6ac16961df0e7a3e4b4e7075aaa5202787Isaac Levy            putSettingsBoolean(contentResolver, Settings.Secure.WIFI_WATCHDOG_ON, false);
2274ad39d6ac16961df0e7a3e4b4e7075aaa5202787Isaac Levy        }
228654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        WifiWatchdogStateMachine wwsm = new WifiWatchdogStateMachine(context);
229654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        wwsm.start();
230654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        wwsm.sendMessage(EVENT_WATCHDOG_TOGGLED);
231654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        return wwsm;
232654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    }
233654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
234654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    /**
235654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy   *
236654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy   */
237654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    private void setupNetworkReceiver() {
238654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        mBroadcastReceiver = new BroadcastReceiver() {
239654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            @Override
240654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            public void onReceive(Context context, Intent intent) {
241654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                String action = intent.getAction();
242654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
243654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    sendMessage(EVENT_NETWORK_STATE_CHANGE, intent);
244654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                } else if (action.equals(WifiManager.RSSI_CHANGED_ACTION)) {
245654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    obtainMessage(EVENT_RSSI_CHANGE, mNetEventCounter,
246654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                            intent.getIntExtra(WifiManager.EXTRA_NEW_RSSI, -200)).sendToTarget();
247654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                } else if (action.equals(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) {
248654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    sendMessage(EVENT_SCAN_RESULTS_AVAILABLE);
249654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                } else if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) {
250654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    sendMessage(EVENT_WIFI_RADIO_STATE_CHANGE,
251654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                            intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
252654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                                    WifiManager.WIFI_STATE_UNKNOWN));
253654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                }
254654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            }
255654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        };
256654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
257654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        mIntentFilter = new IntentFilter();
258654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        mIntentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
259654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        mIntentFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
260654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        mIntentFilter.addAction(WifiManager.RSSI_CHANGED_ACTION);
261654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        mIntentFilter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
262654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    }
263654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
264654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    /**
265654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy     * Observes the watchdog on/off setting, and takes action when changed.
266654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy     */
267d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy    private void registerForWatchdogToggle() {
268654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        ContentObserver contentObserver = new ContentObserver(this.getHandler()) {
269654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            @Override
270654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            public void onChange(boolean selfChange) {
271654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                sendMessage(EVENT_WATCHDOG_TOGGLED);
272654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            }
273654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        };
274654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
275654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        mContext.getContentResolver().registerContentObserver(
276654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                Settings.Secure.getUriFor(Settings.Secure.WIFI_WATCHDOG_ON),
277654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                false, contentObserver);
278654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    }
279654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
280654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    /**
281d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy     * Observes watchdogs secure setting changes.
282d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy     */
283d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy    private void registerForSettingsChanges() {
284d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy        ContentObserver contentObserver = new ContentObserver(this.getHandler()) {
285d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy            @Override
286d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy            public void onChange(boolean selfChange) {
287d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                sendMessage(EVENT_WATCHDOG_SETTINGS_CHANGE);
288d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy            }
289d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy        };
290d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy
291d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy        mContext.getContentResolver().registerContentObserver(
292d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                Settings.Secure.getUriFor(
293d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                        Settings.Secure.WIFI_WATCHDOG_DNS_CHECK_SHORT_INTERVAL_MS),
294d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                        false, contentObserver);
295d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy        mContext.getContentResolver().registerContentObserver(
296d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                Settings.Secure.getUriFor(Settings.Secure.WIFI_WATCHDOG_DNS_CHECK_LONG_INTERVAL_MS),
297d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                false, contentObserver);
298d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy        mContext.getContentResolver().registerContentObserver(
299d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                Settings.Secure.getUriFor(Settings.Secure.WIFI_WATCHDOG_WALLED_GARDEN_INTERVAL_MS),
300d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                false, contentObserver);
301d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy        mContext.getContentResolver().registerContentObserver(
302d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                Settings.Secure.getUriFor(Settings.Secure.WIFI_WATCHDOG_MAX_SSID_BLACKLISTS),
303d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                false, contentObserver);
304d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy        mContext.getContentResolver().registerContentObserver(
305d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                Settings.Secure.getUriFor(Settings.Secure.WIFI_WATCHDOG_NUM_DNS_PINGS),
306d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                false, contentObserver);
307d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy        mContext.getContentResolver().registerContentObserver(
308d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                Settings.Secure.getUriFor(Settings.Secure.WIFI_WATCHDOG_MIN_DNS_RESPONSES),
309d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                false, contentObserver);
310d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy        mContext.getContentResolver().registerContentObserver(
311d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                Settings.Secure.getUriFor(Settings.Secure.WIFI_WATCHDOG_DNS_PING_TIMEOUT_MS),
312d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                false, contentObserver);
313d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy        mContext.getContentResolver().registerContentObserver(
314d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                Settings.Secure.getUriFor(
315d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                        Settings.Secure.WIFI_WATCHDOG_BLACKLIST_FOLLOWUP_INTERVAL_MS),
316d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                        false, contentObserver);
317d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy        mContext.getContentResolver().registerContentObserver(
318d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                Settings.Secure.getUriFor(Settings.Secure.WIFI_WATCHDOG_WALLED_GARDEN_TEST_ENABLED),
319d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                false, contentObserver);
320d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy        mContext.getContentResolver().registerContentObserver(
321d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                Settings.Secure.getUriFor(Settings.Secure.WIFI_WATCHDOG_WALLED_GARDEN_URL),
322d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                false, contentObserver);
323d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy        mContext.getContentResolver().registerContentObserver(
324d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                Settings.Secure.getUriFor(Settings.Secure.WIFI_WATCHDOG_WALLED_GARDEN_PATTERN),
325d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                false, contentObserver);
326d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy    }
327d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy
328d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy    /**
329654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy     * DNS based detection techniques do not work at all hotspots. The one sure
330654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy     * way to check a walled garden is to see if a URL fetch on a known address
331654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy     * fetches the data we expect
332654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy     */
333654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    private boolean isWalledGardenConnection() {
334654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        InputStream in = null;
335654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        HttpURLConnection urlConnection = null;
336654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        try {
337d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy            URL url = new URL(mWalledGardenUrl);
338654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            urlConnection = (HttpURLConnection) url.openConnection();
339654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            in = new BufferedInputStream(urlConnection.getInputStream());
340654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            Scanner scanner = new Scanner(in);
341d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy            if (scanner.findInLine(mWalledGardenPattern) != null) {
342654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                return false;
343654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            } else {
344654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                return true;
345654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            }
346654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        } catch (IOException e) {
347654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            return false;
348654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        } finally {
349654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            if (in != null) {
350654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                try {
351654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    in.close();
352654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                } catch (IOException e) {
353654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                }
354654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            }
355654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            if (urlConnection != null)
356654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                urlConnection.disconnect();
357654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        }
358654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    }
359654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
360654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    private boolean rssiStrengthAboveCutoff(int rssi) {
361654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        return WifiManager.calculateSignalLevel(rssi, WIFI_SIGNAL_LEVELS) > LOW_SIGNAL_CUTOFF;
362654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    }
363654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
364654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    public void dump(PrintWriter pw) {
365654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        pw.print("WatchdogStatus: ");
366654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        pw.print("State " + getCurrentState());
367654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        pw.println(", network [" + mInitialConnInfo + "]");
368d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy        pw.print("checkFailures   " + mNumCheckFailures);
369654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        pw.println(", bssids: " + mBssids);
370654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        pw.println("lastSingleCheck: " + mOnlineWatchState.lastCheckTime);
371654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    }
372654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
373654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    private boolean isWatchdogEnabled() {
374d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy        return getSettingsBoolean(mContentResolver, Settings.Secure.WIFI_WATCHDOG_ON, true);
375654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    }
376654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
377d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy    private void updateSettings() {
378d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy        mDnsCheckShortIntervalMs = Secure.getLong(mContentResolver,
379d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                Secure.WIFI_WATCHDOG_DNS_CHECK_SHORT_INTERVAL_MS,
380d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                DEFAULT_DNS_CHECK_SHORT_INTERVAL_MS);
381d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy        mDnsCheckLongIntervalMs = Secure.getLong(mContentResolver,
382d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                Secure.WIFI_WATCHDOG_DNS_CHECK_LONG_INTERVAL_MS,
383d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                DEFAULT_DNS_CHECK_LONG_INTERVAL_MS);
384d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy        mMaxSsidBlacklists = Secure.getInt(mContentResolver,
385d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                Secure.WIFI_WATCHDOG_MAX_SSID_BLACKLISTS,
386d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                DEFAULT_MAX_SSID_BLACKLISTS);
387d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy        mNumDnsPings = Secure.getInt(mContentResolver,
388d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                Secure.WIFI_WATCHDOG_NUM_DNS_PINGS,
389d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                DEFAULT_NUM_DNS_PINGS);
390d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy        mMinDnsResponses = Secure.getInt(mContentResolver,
391d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                Secure.WIFI_WATCHDOG_MIN_DNS_RESPONSES,
392d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                DEFAULT_MIN_DNS_RESPONSES);
393d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy        mDnsPingTimeoutMs = Secure.getInt(mContentResolver,
394d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                Secure.WIFI_WATCHDOG_DNS_PING_TIMEOUT_MS,
395d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                DEFAULT_DNS_PING_TIMEOUT_MS);
396d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy        mBlacklistFollowupIntervalMs = Secure.getLong(mContentResolver,
397d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                Settings.Secure.WIFI_WATCHDOG_BLACKLIST_FOLLOWUP_INTERVAL_MS,
398d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                DEFAULT_BLACKLIST_FOLLOWUP_INTERVAL_MS);
399d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy        mWalledGardenTestEnabled = getSettingsBoolean(mContentResolver,
400d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                Settings.Secure.WIFI_WATCHDOG_WALLED_GARDEN_TEST_ENABLED, true);
401d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy        mWalledGardenUrl = getSettingsStr(mContentResolver,
402d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                Settings.Secure.WIFI_WATCHDOG_WALLED_GARDEN_URL,
403d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                DEFAULT_WALLED_GARDEN_URL);
404d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy        mWalledGardenPattern = Pattern.compile(getSettingsStr(mContentResolver,
405d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                Settings.Secure.WIFI_WATCHDOG_WALLED_GARDEN_PATTERN,
406d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                DEFAULT_WALLED_GARDEN_PATTERN));
407d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy        mWalledGardenIntervalMs = Secure.getLong(mContentResolver,
408d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                Secure.WIFI_WATCHDOG_WALLED_GARDEN_INTERVAL_MS,
409d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                DEFAULT_WALLED_GARDEN_INTERVAL_MS);
410d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy    }
411654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
412654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    /**
413654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy     * Helper to return wait time left given a min interval and last run
414654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy     *
415654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy     * @param interval minimum wait interval
416654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy     * @param lastTime last time action was performed in
417654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy     *            SystemClock.elapsedRealtime(). Null if never.
418654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy     * @return non negative time to wait
419654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy     */
420654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    private static long waitTime(long interval, Long lastTime) {
421654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        if (lastTime == null)
422654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            return 0;
423654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        long wait = interval + lastTime - SystemClock.elapsedRealtime();
424654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        return wait > 0 ? wait : 0;
425654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    }
426654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
427654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    private static String wifiInfoToStr(WifiInfo wifiInfo) {
428654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        if (wifiInfo == null)
429654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            return "null";
430654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        return "(" + wifiInfo.getSSID() + ", " + wifiInfo.getBSSID() + ")";
431654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    }
432654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
433654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    /**
434654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy   *
435654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy   */
436654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    private void resetWatchdogState() {
437654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        mInitialConnInfo = null;
438654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        mDisableAPNextFailure = false;
439654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        mLastWalledGardenCheckTime = null;
440d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy        mNumCheckFailures = 0;
441654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        mBssids.clear();
442654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    }
443654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
444654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    private void popUpBrowser() {
445654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        Uri uri = Uri.parse("http://www.google.com");
446654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        Intent intent = new Intent(Intent.ACTION_VIEW, uri);
447654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        intent.setFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT |
448654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                Intent.FLAG_ACTIVITY_NEW_TASK);
449654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        mContext.startActivity(intent);
450654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    }
451654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
452d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy    private void displayDisabledNetworkNotification() {
453d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy        Resources r = Resources.getSystem();
454d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy        CharSequence title =
455d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                r.getText(com.android.internal.R.string.wifi_watchdog_network_disabled);
456d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy        CharSequence msg =
457d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                r.getText(com.android.internal.R.string.wifi_watchdog_network_disabled_detailed);
458d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy
459d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy        Notification wifiDisabledWarning = new Notification.Builder(mContext)
460d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy            .setSmallIcon(com.android.internal.R.drawable.stat_sys_warning)
461d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy            .setDefaults(Notification.DEFAULT_ALL)
462d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy            .setTicker(title)
463d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy            .setContentTitle(title)
464d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy            .setContentText(msg)
465d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy            .setContentIntent(PendingIntent.getActivity(mContext, 0,
466d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                    new Intent(Settings.ACTION_WIFI_IP_SETTINGS)
467d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                        .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK), 0))
468d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy            .setWhen(System.currentTimeMillis())
469d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy            .setAutoCancel(true)
470d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy            .getNotification();
471d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy
472d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy        NotificationManager notificationManager = (NotificationManager) mContext
473d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                .getSystemService(Context.NOTIFICATION_SERVICE);
474d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy
475d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy        notificationManager.notify("WifiWatchdog", wifiDisabledWarning.icon, wifiDisabledWarning);
476654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    }
477654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
4784ad39d6ac16961df0e7a3e4b4e7075aaa5202787Isaac Levy    /**
4794ad39d6ac16961df0e7a3e4b4e7075aaa5202787Isaac Levy     * @return true if there is definitely no mobile data (we'll be less aggressive)
4804ad39d6ac16961df0e7a3e4b4e7075aaa5202787Isaac Levy     */
4814ad39d6ac16961df0e7a3e4b4e7075aaa5202787Isaac Levy    private boolean hasNoMobileData() {
4824ad39d6ac16961df0e7a3e4b4e7075aaa5202787Isaac Levy        if (mConnectivityManager == null) {
4834ad39d6ac16961df0e7a3e4b4e7075aaa5202787Isaac Levy            mConnectivityManager = (ConnectivityManager) mContext.getSystemService(
4844ad39d6ac16961df0e7a3e4b4e7075aaa5202787Isaac Levy                    Context.CONNECTIVITY_SERVICE);
4854ad39d6ac16961df0e7a3e4b4e7075aaa5202787Isaac Levy        }
4864ad39d6ac16961df0e7a3e4b4e7075aaa5202787Isaac Levy        NetworkInfo mobileNetInfo = mConnectivityManager.getNetworkInfo(
4874ad39d6ac16961df0e7a3e4b4e7075aaa5202787Isaac Levy                ConnectivityManager.TYPE_MOBILE);
4884ad39d6ac16961df0e7a3e4b4e7075aaa5202787Isaac Levy        if (mobileNetInfo == null || !mobileNetInfo.isAvailable()) {
4894ad39d6ac16961df0e7a3e4b4e7075aaa5202787Isaac Levy            return true;
4904ad39d6ac16961df0e7a3e4b4e7075aaa5202787Isaac Levy        }
4914ad39d6ac16961df0e7a3e4b4e7075aaa5202787Isaac Levy        return false;
4924ad39d6ac16961df0e7a3e4b4e7075aaa5202787Isaac Levy    }
4934ad39d6ac16961df0e7a3e4b4e7075aaa5202787Isaac Levy
494654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    class DefaultState extends State {
495654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        @Override
496654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        public boolean processMessage(Message msg) {
497d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy            switch (msg.what) {
498d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                case EVENT_WATCHDOG_SETTINGS_CHANGE:
499d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                    updateSettings();
500d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                    if (VDBG) {
501d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                        Slog.d(WWSM_TAG, "Updating wifi-watchdog secure settings");
502d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                    }
503d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                    return HANDLED;
504d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy            }
505654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            if (VDBG) {
506654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                Slog.v(WWSM_TAG, "Caught message " + msg.what + " in state " +
507654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                        getCurrentState().getName());
508654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            }
509654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            return HANDLED;
510654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        }
511654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    }
512654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
513654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    class WatchdogDisabledState extends State {
514654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        @Override
515654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        public boolean processMessage(Message msg) {
516654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            switch (msg.what) {
517654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                case EVENT_WATCHDOG_TOGGLED:
518654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    if (isWatchdogEnabled())
519654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                        transitionTo(mNotConnectedState);
520654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    return HANDLED;
521654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            }
522654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            return NOT_HANDLED;
523654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        }
524654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    }
525654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
526654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    class WatchdogEnabledState extends State {
527654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        @Override
528654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        public void enter() {
529654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            resetWatchdogState();
530654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            mContext.registerReceiver(mBroadcastReceiver, mIntentFilter);
531654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            Slog.i(WWSM_TAG, "WifiWatchdogService enabled");
532654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        }
533654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
534654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        @Override
535654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        public boolean processMessage(Message msg) {
536654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            switch (msg.what) {
537654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                case EVENT_WATCHDOG_TOGGLED:
538654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    if (!isWatchdogEnabled())
539654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                        transitionTo(mWatchdogDisabledState);
540654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    return HANDLED;
541654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                case EVENT_NETWORK_STATE_CHANGE:
542654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    Intent stateChangeIntent = (Intent) msg.obj;
543654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    NetworkInfo networkInfo = (NetworkInfo)
544654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                            stateChangeIntent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
545654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
546654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    switch (networkInfo.getState()) {
547654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                        case CONNECTED:
548654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                            // WifiInfo wifiInfo = (WifiInfo)
549654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                            //         stateChangeIntent
550654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                            //                 .getParcelableExtra(WifiManager.EXTRA_WIFI_INFO);
551654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                            // TODO : Replace with above code when API is changed
552654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                            WifiInfo wifiInfo = mWifiManager.getConnectionInfo();
553654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                            if (wifiInfo == null) {
554654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                                Slog.e(WWSM_TAG, "Connected --> WifiInfo object null!");
555654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                                return HANDLED;
556654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                            }
557654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
558654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                            if (wifiInfo.getSSID() == null || wifiInfo.getBSSID() == null) {
559654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                                Slog.e(WWSM_TAG, "Received wifiInfo object with null elts: "
560654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                                        + wifiInfoToStr(wifiInfo));
561654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                                return HANDLED;
562654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                            }
563654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
564654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                            initConnection(wifiInfo);
565654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                            transitionTo(mDnsCheckingState);
566654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                            mNetEventCounter++;
567654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                            return HANDLED;
568654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                        case DISCONNECTED:
569654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                        case DISCONNECTING:
570654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                            mNetEventCounter++;
571654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                            transitionTo(mNotConnectedState);
572654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                            return HANDLED;
573654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    }
574654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    return HANDLED;
575654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                case EVENT_WIFI_RADIO_STATE_CHANGE:
576654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    if ((Integer) msg.obj == WifiManager.WIFI_STATE_DISABLING) {
577654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                        Slog.i(WWSM_TAG, "WifiStateDisabling -- Resetting WatchdogState");
578654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                        resetWatchdogState();
579654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                        mNetEventCounter++;
580654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                        transitionTo(mNotConnectedState);
581654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    }
582654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    return HANDLED;
583654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            }
584654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
585654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            return NOT_HANDLED;
586654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        }
587654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
588654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        /**
589654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy         * @param wifiInfo Info object with non-null ssid and bssid
590654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy         */
591654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        private void initConnection(WifiInfo wifiInfo) {
592654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            if (VDBG) {
593654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                Slog.v(WWSM_TAG, "Connected:: old " + wifiInfoToStr(mInitialConnInfo) +
594654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                        " ==> new " + wifiInfoToStr(wifiInfo));
595654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            }
596654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
597654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            if (mInitialConnInfo == null || !wifiInfo.getSSID().equals(mInitialConnInfo.getSSID())) {
598654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                resetWatchdogState();
599654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            } else if (!wifiInfo.getBSSID().equals(mInitialConnInfo.getBSSID())) {
600654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                mDisableAPNextFailure = false;
601654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            }
602654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            mInitialConnInfo = wifiInfo;
603654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        }
604654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
605654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        @Override
606654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        public void exit() {
607654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            mContext.unregisterReceiver(mBroadcastReceiver);
608654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            Slog.i(WWSM_TAG, "WifiWatchdogService disabled");
609654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        }
610654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    }
611654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
612654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    class NotConnectedState extends State {
613654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    }
614654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
615654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    class ConnectedState extends State {
616654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        @Override
617654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        public boolean processMessage(Message msg) {
618654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            switch (msg.what) {
619654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                case EVENT_SCAN_RESULTS_AVAILABLE:
620654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    String curSsid = mInitialConnInfo.getSSID();
621654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    List<ScanResult> results = mWifiManager.getScanResults();
622654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    int oldNumBssids = mBssids.size();
623654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
624654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    if (results == null) {
625654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                        if (DBG) {
626654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                            Slog.d(WWSM_TAG, "updateBssids: Got null scan results!");
627654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                        }
628654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                        return HANDLED;
629654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    }
630654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
631654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    for (ScanResult result : results) {
632654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                        if (result == null || result.SSID == null) {
633654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                            if (VDBG) {
634654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                                Slog.v(WWSM_TAG, "Received invalid scan result: " + result);
635654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                            }
636654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                            continue;
637654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                        }
638654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                        if (curSsid.equals(result.SSID))
639654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                            mBssids.add(result.BSSID);
640654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    }
641654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    return HANDLED;
642d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                case EVENT_WATCHDOG_SETTINGS_CHANGE:
643d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                    // Stop current checks, but let state update
644d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                    transitionTo(mOnlineWatchState);
645d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                    return NOT_HANDLED;
646654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            }
647654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            return NOT_HANDLED;
648654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        }
649654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
650654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    }
651654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
652654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    class DnsCheckingState extends State {
653654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        int dnsCheckTries = 0;
654654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        int dnsCheckSuccesses = 0;
655654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        String dnsCheckLogStr = "";
656654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
657654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        @Override
658654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        public void enter() {
659654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            dnsCheckSuccesses = 0;
660654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            dnsCheckTries = 0;
661654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            if (DBG) {
662654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                Slog.d(WWSM_TAG, "Starting DNS pings at " + SystemClock.elapsedRealtime());
663d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                dnsCheckLogStr = String.format("Pinging %s on ssid [%s]: ",
664d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                        mDnsPinger.getDns(), mInitialConnInfo.getSSID());
665654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            }
666654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
667654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            sendCheckStepMessage(0);
668654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        }
669654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
670654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        @Override
671654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        public boolean processMessage(Message msg) {
672654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            if (msg.what != MESSAGE_CHECK_STEP) {
673654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                return NOT_HANDLED;
674654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            }
675654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            if (msg.arg1 != mNetEventCounter) {
676654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                Slog.d(WWSM_TAG, "Check step out of sync, ignoring...");
677654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                return HANDLED;
678654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            }
679654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
680654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            long pingResponseTime = mDnsPinger.pingDns(mDnsPinger.getDns(),
681d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                    mDnsPingTimeoutMs);
682654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
683654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            dnsCheckTries++;
684654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            if (pingResponseTime >= 0)
685654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                dnsCheckSuccesses++;
686654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
687654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            if (DBG) {
688654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                if (pingResponseTime >= 0) {
689654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    dnsCheckLogStr += "|" + pingResponseTime;
690654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                } else {
691654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    dnsCheckLogStr += "|x";
692654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                }
693654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            }
694654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
695654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            if (VDBG) {
696654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                Slog.v(WWSM_TAG, dnsCheckLogStr);
697654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            }
698654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
699654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            /**
700654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy             * After a full ping count, if we have more responses than this
701654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy             * cutoff, the outcome is success; else it is 'failure'.
702654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy             */
703654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
704654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            /**
705654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy             * Our final success count will be at least this big, so we're
706654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy             * guaranteed to succeed.
707654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy             */
708d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy            if (dnsCheckSuccesses >= mMinDnsResponses) {
709654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                // DNS CHECKS OK, NOW WALLED GARDEN
710654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                if (DBG) {
711654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    Slog.d(WWSM_TAG, dnsCheckLogStr + "|  SUCCESS");
712654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                }
713654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
714654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                if (!shouldCheckWalledGarden()) {
715654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    transitionTo(mOnlineWatchState);
716654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    return HANDLED;
717654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                }
718654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
719654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                mLastWalledGardenCheckTime = SystemClock.elapsedRealtime();
720654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                if (isWalledGardenConnection()) {
721654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    if (DBG)
722654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                        Slog.d(WWSM_TAG,
723654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                                "Walled garden test complete - walled garden detected");
724654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    transitionTo(mWalledGardenState);
725654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                } else {
726654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    if (DBG)
727654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                        Slog.d(WWSM_TAG, "Walled garden test complete - online");
728654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    transitionTo(mOnlineWatchState);
729654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                }
730654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                return HANDLED;
731654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            }
732654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
733654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            /**
734654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy             * Our final count will be at most the current count plus the
735654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy             * remaining pings - we're guaranteed to fail.
736654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy             */
737d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy            int remainingChecks = mNumDnsPings - dnsCheckTries;
738d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy            if (remainingChecks + dnsCheckSuccesses < mMinDnsResponses) {
739654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                if (DBG) {
740654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    Slog.d(WWSM_TAG, dnsCheckLogStr + "|  FAILURE");
741654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                }
742654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                transitionTo(mDnsCheckFailureState);
743654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                return HANDLED;
744654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            }
745654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
746654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            // Still in dns check step
747654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            sendCheckStepMessage(DNS_PING_INTERVAL_MS);
748654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            return HANDLED;
749654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        }
750654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
751654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        private boolean shouldCheckWalledGarden() {
752d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy            if (!mWalledGardenTestEnabled) {
753654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                if (VDBG)
754654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    Slog.v(WWSM_TAG, "Skipping walled garden check - disabled");
755654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                return false;
756654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            }
757d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy            long waitTime = waitTime(mWalledGardenIntervalMs,
758654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    mLastWalledGardenCheckTime);
759654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            if (waitTime > 0) {
760654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                if (DBG) {
761654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    Slog.d(WWSM_TAG, "Skipping walled garden check - wait " +
762654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                            waitTime + " ms.");
763654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                }
764654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                return false;
765654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            }
766654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            return true;
767654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        }
768654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
769d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy        private void sendCheckStepMessage(long delay) {
770d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy            sendMessageDelayed(obtainMessage(MESSAGE_CHECK_STEP, mNetEventCounter, 0), delay);
771d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy        }
772d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy
773654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    }
774654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
775654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    class OnlineWatchState extends State {
776654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        /**
777654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy         * Signals a short-wait message is enqueued for the current 'guard' counter
778654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy         */
779654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        boolean unstableSignalChecks = false;
780654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
781654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        /**
782654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy         * The signal is unstable.  We should enqueue a short-wait check, if one is enqueued
783654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy         * already
784654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy         */
785654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        boolean signalUnstable = false;
786654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
787654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        /**
788654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy         * A monotonic counter to ensure that at most one check message will be processed from any
789654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy         * set of check messages currently enqueued.  Avoids duplicate checks when a low-signal
790654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy         * event is observed.
791654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy         */
792654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        int checkGuard = 0;
793654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        Long lastCheckTime = null;
794654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
795654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        @Override
796654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        public void enter() {
797654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            lastCheckTime = SystemClock.elapsedRealtime();
798654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            signalUnstable = false;
799654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            checkGuard++;
800654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            unstableSignalChecks = false;
801654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            triggerSingleDnsCheck();
802654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        }
803654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
804654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        @Override
805654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        public boolean processMessage(Message msg) {
806654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            switch (msg.what) {
807654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                case EVENT_RSSI_CHANGE:
808654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    if (msg.arg1 != mNetEventCounter) {
809654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                        if (DBG) {
810654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                            Slog.d(WWSM_TAG, "Rssi change message out of sync, ignoring");
811654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                        }
812654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                        return HANDLED;
813654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    }
814654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    int newRssi = msg.arg2;
815654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    signalUnstable = !rssiStrengthAboveCutoff(newRssi);
816654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    if (VDBG) {
817654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                        Slog.v(WWSM_TAG, "OnlineWatchState:: new rssi " + newRssi + " --> level " +
818654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                                WifiManager.calculateSignalLevel(newRssi, WIFI_SIGNAL_LEVELS));
819654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    }
820654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
821654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    if (signalUnstable && !unstableSignalChecks) {
822654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                        if (VDBG) {
823654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                            Slog.v(WWSM_TAG, "Sending triggered check msg");
824654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                        }
825654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                        triggerSingleDnsCheck();
826654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    }
827654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    return HANDLED;
828654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                case MESSAGE_SINGLE_DNS_CHECK:
829654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    if (msg.arg1 != checkGuard) {
830654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                        if (VDBG) {
831654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                            Slog.v(WWSM_TAG, "Single check msg out of sync, ignoring.");
832654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                        }
833654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                        return HANDLED;
834654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    }
835654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    lastCheckTime = SystemClock.elapsedRealtime();
836654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    long responseTime = mDnsPinger.pingDns(mDnsPinger.getDns(),
837d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                            mDnsPingTimeoutMs);
838654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    if (responseTime >= 0) {
839654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                        if (VDBG) {
840654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                            Slog.v(WWSM_TAG, "Ran a single DNS ping. Response time: "
841654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                                    + responseTime);
842654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                        }
843654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
844654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                        checkGuard++;
845654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                        unstableSignalChecks = false;
846654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                        triggerSingleDnsCheck();
847654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    } else {
848654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                        if (DBG) {
849654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                            Slog.d(WWSM_TAG, "Single dns ping failure. Starting full checks.");
850654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                        }
851654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                        transitionTo(mDnsCheckingState);
852654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    }
853654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    return HANDLED;
854654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            }
855654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            return NOT_HANDLED;
856654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        }
857654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
858654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        /**
859d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy         * Times a dns check with an interval based on {@link #signalUnstable}
860654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy         */
861654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        private void triggerSingleDnsCheck() {
862654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            long waitInterval;
863654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            if (signalUnstable) {
864d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                waitInterval = mDnsCheckShortIntervalMs;
865654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                unstableSignalChecks = true;
866654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            } else {
867d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                waitInterval = mDnsCheckLongIntervalMs;
868654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            }
869654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            sendMessageDelayed(obtainMessage(MESSAGE_SINGLE_DNS_CHECK, checkGuard, 0),
870654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    waitTime(waitInterval, lastCheckTime));
871654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        }
872654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    }
873654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
874654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    class DnsCheckFailureState extends State {
8754ad39d6ac16961df0e7a3e4b4e7075aaa5202787Isaac Levy
876654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        @Override
877654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        public void enter() {
878d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy            mNumCheckFailures++;
879654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            obtainMessage(MESSAGE_HANDLE_BAD_AP, mNetEventCounter, 0).sendToTarget();
880654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        }
881654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
882654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        @Override
883654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        public boolean processMessage(Message msg) {
884654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            if (msg.what != MESSAGE_HANDLE_BAD_AP) {
885654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                return NOT_HANDLED;
886654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            }
887654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
888654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            if (msg.arg1 != mNetEventCounter) {
889654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                if (VDBG) {
890654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    Slog.v(WWSM_TAG, "Msg out of sync, ignoring...");
891654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                }
892654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                return HANDLED;
893654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            }
894654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
895d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy            if (mDisableAPNextFailure || mNumCheckFailures >= mMaxSsidBlacklists) {
8964ad39d6ac16961df0e7a3e4b4e7075aaa5202787Isaac Levy                if (hasNoMobileData()) {
8974ad39d6ac16961df0e7a3e4b4e7075aaa5202787Isaac Levy                    Slog.w(WWSM_TAG, "Would disable bad network, but device has no mobile data!" +
8984ad39d6ac16961df0e7a3e4b4e7075aaa5202787Isaac Levy                            "  Going idle...");
8994ad39d6ac16961df0e7a3e4b4e7075aaa5202787Isaac Levy                    // This state should be called idle -- will be changing flow.
9004ad39d6ac16961df0e7a3e4b4e7075aaa5202787Isaac Levy                    transitionTo(mNotConnectedState);
9014ad39d6ac16961df0e7a3e4b4e7075aaa5202787Isaac Levy                    return HANDLED;
9024ad39d6ac16961df0e7a3e4b4e7075aaa5202787Isaac Levy                }
903654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                // TODO : Unban networks if they had low signal ?
904654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                Slog.i(WWSM_TAG, "Disabling current SSID " + wifiInfoToStr(mInitialConnInfo)
905d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                        + ".  " + "numCheckFailures " + mNumCheckFailures
906d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                        + ", numAPs " + mBssids.size());
907654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                mWifiManager.disableNetwork(mInitialConnInfo.getNetworkId());
908d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                if (mShowDisabledNotification) {
909d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                    displayDisabledNetworkNotification();
910d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                    mShowDisabledNotification = false;
911d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                    putSettingsBoolean(mContentResolver,
912d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                            Settings.Secure.WIFI_WATCHDOG_SHOW_DISABLED_NETWORK_POPUP, false);
913d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                }
914654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                transitionTo(mNotConnectedState);
915654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            } else {
916d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                Slog.i(WWSM_TAG, "Blacklisting current BSSID.  " + wifiInfoToStr(mInitialConnInfo)
917d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                       + "numCheckFailures " + mNumCheckFailures + ", numAPs " + mBssids.size());
918654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
919654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                mWifiManager.addToBlacklist(mInitialConnInfo.getBSSID());
920654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                mWifiManager.reassociate();
921654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                transitionTo(mBlacklistedApState);
922654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            }
923654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            return HANDLED;
924654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        }
925654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    }
926654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
927654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    class WalledGardenState extends State {
928654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        @Override
929654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        public void enter() {
930654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            obtainMessage(MESSAGE_HANDLE_WALLED_GARDEN, mNetEventCounter, 0).sendToTarget();
931654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        }
932654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
933654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        @Override
934654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        public boolean processMessage(Message msg) {
935654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            if (msg.what != MESSAGE_HANDLE_WALLED_GARDEN) {
936654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                return NOT_HANDLED;
937654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            }
938654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
939654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            if (msg.arg1 != mNetEventCounter) {
940654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                if (VDBG) {
941654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    Slog.v(WWSM_TAG, "WalledGardenState::Msg out of sync, ignoring...");
942654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                }
943654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                return HANDLED;
944654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            }
945654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            popUpBrowser();
946654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            transitionTo(mOnlineWatchState);
947654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            return HANDLED;
948654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        }
949654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    }
950654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
951654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    class BlacklistedApState extends State {
952654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        @Override
953654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        public void enter() {
954654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            mDisableAPNextFailure = true;
955654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            sendMessageDelayed(obtainMessage(MESSAGE_NETWORK_FOLLOWUP, mNetEventCounter, 0),
956d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy                    mBlacklistFollowupIntervalMs);
957654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        }
958654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
959654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        @Override
960654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        public boolean processMessage(Message msg) {
961654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            if (msg.what != MESSAGE_NETWORK_FOLLOWUP) {
962654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                return NOT_HANDLED;
963654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            }
964654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
965654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            if (msg.arg1 != mNetEventCounter) {
966654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                if (VDBG) {
967654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                    Slog.v(WWSM_TAG, "BlacklistedApState::Msg out of sync, ignoring...");
968654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                }
969654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy                return HANDLED;
970654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            }
971654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy
972654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            transitionTo(mDnsCheckingState);
973654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy            return HANDLED;
974654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy        }
975654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy    }
976d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy
977d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy
978d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy    /**
979d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy     * Convenience function for retrieving a single secure settings value
980d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy     * as a string with a default value.
981d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy     *
982d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy     * @param cr The ContentResolver to access.
983d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy     * @param name The name of the setting to retrieve.
984d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy     * @param def Value to return if the setting is not defined.
985d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy     *
986d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy     * @return The setting's current value, or 'def' if it is not defined
987d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy     */
988d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy    private static String getSettingsStr(ContentResolver cr, String name, String def) {
989d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy        String v = Settings.Secure.getString(cr, name);
990d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy        return v != null ? v : def;
991d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy    }
992d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy
993d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy    /**
994d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy     * Convenience function for retrieving a single secure settings value
995d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy     * as a boolean.  Note that internally setting values are always
996d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy     * stored as strings; this function converts the string to a boolean
997d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy     * for you.  The default value will be returned if the setting is
998d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy     * not defined or not a valid boolean.
999d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy     *
1000d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy     * @param cr The ContentResolver to access.
1001d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy     * @param name The name of the setting to retrieve.
1002d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy     * @param def Value to return if the setting is not defined.
1003d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy     *
1004d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy     * @return The setting's current value, or 'def' if it is not defined
1005d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy     * or not a valid boolean.
1006d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy     */
1007d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy    private static boolean getSettingsBoolean(ContentResolver cr, String name, boolean def) {
1008d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy        return Settings.Secure.getInt(cr, name, def ? 1 : 0) == 1;
1009d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy    }
1010d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy
1011d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy    /**
1012d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy     * Convenience function for updating a single settings value as an
1013d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy     * integer. This will either create a new entry in the table if the
1014d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy     * given name does not exist, or modify the value of the existing row
1015d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy     * with that name.  Note that internally setting values are always
1016d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy     * stored as strings, so this function converts the given value to a
1017d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy     * string before storing it.
1018d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy     *
1019d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy     * @param cr The ContentResolver to access.
1020d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy     * @param name The name of the setting to modify.
1021d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy     * @param value The new value for the setting.
1022d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy     * @return true if the value was set, false on database errors
1023d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy     */
1024d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy    private static boolean putSettingsBoolean(ContentResolver cr, String name, boolean value) {
1025d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy        return Settings.Secure.putInt(cr, name, value ? 1 : 0);
1026d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy    }
1027d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy
1028d7b3e6a39b6b2e155b24ef470023bafb3b9fa35aIsaac Levy
1029654f5090754e4e1bf4c1736d0a24769a15a6037eIsaac Levy}
1030