blob: 883fc7175ebb50233746fc20ce9bfde4446401e2 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
Irfan Sheriffa2a1b912010-06-07 09:03:04 -07002 * Copyright (C) 2010 The Android Open Source Project
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server;
18
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080019import android.app.AlarmManager;
Irfan Sheriff0d255342010-07-28 09:35:20 -070020import android.app.Notification;
21import android.app.NotificationManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080022import android.app.PendingIntent;
Jaikumar Ganesh7440fc22010-09-27 17:04:14 -070023import android.bluetooth.BluetoothAdapter;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080024import android.content.BroadcastReceiver;
25import android.content.ContentResolver;
26import android.content.Context;
27import android.content.Intent;
28import android.content.IntentFilter;
29import android.content.pm.PackageManager;
Irfan Sheriff0d255342010-07-28 09:35:20 -070030import android.database.ContentObserver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080031import android.net.wifi.IWifiManager;
Irfan Sheriff4aeca7c52011-03-10 16:53:33 -080032import android.net.wifi.ScanResult;
33import android.net.wifi.SupplicantState;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080034import android.net.wifi.WifiInfo;
35import android.net.wifi.WifiManager;
Irfan Sheriff0d255342010-07-28 09:35:20 -070036import android.net.wifi.WifiStateMachine;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080037import android.net.wifi.WifiConfiguration;
Isaac Levy654f5092011-07-13 17:41:45 -070038import android.net.wifi.WifiWatchdogStateMachine;
Irfan Sheriff9ab518ad2010-03-12 15:48:17 -080039import android.net.wifi.WifiConfiguration.KeyMgmt;
Irfan Sheriff651cdfc2011-09-07 00:31:20 -070040import android.net.wifi.WpsInfo;
Irfan Sheriffe4c56c92011-01-12 16:33:58 -080041import android.net.wifi.WpsResult;
Irfan Sheriff5321aef2010-02-12 12:35:59 -080042import android.net.ConnectivityManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080043import android.net.DhcpInfo;
Irfan Sheriff0d255342010-07-28 09:35:20 -070044import android.net.NetworkInfo;
45import android.net.NetworkInfo.State;
Irfan Sheriff227bec42011-02-15 19:30:27 -080046import android.net.NetworkInfo.DetailedState;
47import android.net.TrafficStats;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080048import android.os.Binder;
Irfan Sheriff0d255342010-07-28 09:35:20 -070049import android.os.Handler;
Irfan Sheriff227bec42011-02-15 19:30:27 -080050import android.os.Messenger;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080051import android.os.HandlerThread;
52import android.os.IBinder;
Irfan Sheriff5321aef2010-02-12 12:35:59 -080053import android.os.INetworkManagementService;
Irfan Sheriff0d255342010-07-28 09:35:20 -070054import android.os.Message;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080055import android.os.RemoteException;
Amith Yamasani47873e52009-07-02 12:05:32 -070056import android.os.ServiceManager;
Irfan Sheriff227bec42011-02-15 19:30:27 -080057import android.os.SystemProperties;
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -070058import android.os.WorkSource;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080059import android.provider.Settings;
Irfan Sheriff0d255342010-07-28 09:35:20 -070060import android.text.TextUtils;
Joe Onorato8a9b2202010-02-26 18:56:32 -080061import android.util.Slog;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080062
63import java.util.ArrayList;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080064import java.util.List;
Jaikumar Ganesh084c6652009-12-07 10:58:18 -080065import java.util.Set;
Irfan Sheriff658772f2011-03-08 14:52:31 -080066import java.util.concurrent.atomic.AtomicInteger;
Irfan Sheriffa2a1b912010-06-07 09:03:04 -070067import java.util.concurrent.atomic.AtomicBoolean;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080068import java.io.FileDescriptor;
69import java.io.PrintWriter;
70
The Android Open Source Project10592532009-03-18 17:39:46 -070071import com.android.internal.app.IBatteryStats;
Irfan Sheriff616f3172011-09-11 19:59:01 -070072import com.android.internal.telephony.TelephonyIntents;
Wink Saville4b7ba092010-10-20 15:37:41 -070073import com.android.internal.util.AsyncChannel;
The Android Open Source Project10592532009-03-18 17:39:46 -070074import com.android.server.am.BatteryStatsService;
Irfan Sheriff9ab518ad2010-03-12 15:48:17 -080075import com.android.internal.R;
The Android Open Source Project10592532009-03-18 17:39:46 -070076
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080077/**
78 * WifiService handles remote WiFi operation requests by implementing
Irfan Sheriffa2a1b912010-06-07 09:03:04 -070079 * the IWifiManager interface.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080080 *
81 * @hide
82 */
Irfan Sheriffa2a1b912010-06-07 09:03:04 -070083//TODO: Clean up multiple locks and implement WifiService
84// as a SM to track soft AP/client/adhoc bring up based
85// on device idle state, airplane mode and boot.
86
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080087public class WifiService extends IWifiManager.Stub {
88 private static final String TAG = "WifiService";
Dianne Hackborn5fd21692011-06-07 14:09:47 -070089 private static final boolean DBG = false;
Irfan Sheriffa2a1b912010-06-07 09:03:04 -070090
Irfan Sheriff0d255342010-07-28 09:35:20 -070091 private final WifiStateMachine mWifiStateMachine;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080092
93 private Context mContext;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080094
95 private AlarmManager mAlarmManager;
96 private PendingIntent mIdleIntent;
97 private static final int IDLE_REQUEST = 0;
98 private boolean mScreenOff;
99 private boolean mDeviceIdle;
Irfan Sheriff616f3172011-09-11 19:59:01 -0700100 private boolean mEmergencyCallbackMode = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800101 private int mPluggedType;
102
Irfan Sherifffcc08452011-02-17 16:44:54 -0800103 /* Chipset supports background scan */
104 private final boolean mBackgroundScanSupported;
105
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800106 private final LockList mLocks = new LockList();
Eric Shienbrood5711fad2009-03-27 20:25:31 -0700107 // some wifi lock statistics
Irfan Sheriff5876a422010-08-12 20:26:23 -0700108 private int mFullHighPerfLocksAcquired;
109 private int mFullHighPerfLocksReleased;
Eric Shienbrood5711fad2009-03-27 20:25:31 -0700110 private int mFullLocksAcquired;
111 private int mFullLocksReleased;
112 private int mScanLocksAcquired;
113 private int mScanLocksReleased;
The Android Open Source Project10592532009-03-18 17:39:46 -0700114
Robert Greenwalt58ff0212009-05-19 15:53:54 -0700115 private final List<Multicaster> mMulticasters =
116 new ArrayList<Multicaster>();
Robert Greenwalt5347bd42009-05-13 15:10:16 -0700117 private int mMulticastEnabled;
118 private int mMulticastDisabled;
119
The Android Open Source Project10592532009-03-18 17:39:46 -0700120 private final IBatteryStats mBatteryStats;
Jaikumar Ganesh084c6652009-12-07 10:58:18 -0800121
Irfan Sheriff227bec42011-02-15 19:30:27 -0800122 private boolean mEnableTrafficStatsPoll = false;
123 private int mTrafficStatsPollToken = 0;
124 private long mTxPkts;
125 private long mRxPkts;
126 /* Tracks last reported data activity */
127 private int mDataActivity;
128 private String mInterfaceName;
129
130 /**
131 * Interval in milliseconds between polling for traffic
132 * statistics
133 */
134 private static final int POLL_TRAFFIC_STATS_INTERVAL_MSECS = 1000;
135
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800136 /**
Doug Zongker43866e02010-01-07 12:09:54 -0800137 * See {@link Settings.Secure#WIFI_IDLE_MS}. This is the default value if a
138 * Settings.Secure value is not present. This timeout value is chosen as
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800139 * the approximate point at which the battery drain caused by Wi-Fi
140 * being enabled but not active exceeds the battery drain caused by
141 * re-establishing a connection to the mobile data network.
142 */
Irfan Sheriff4f5f7c92010-10-14 17:01:27 -0700143 private static final long DEFAULT_IDLE_MS = 15 * 60 * 1000; /* 15 minutes */
144
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800145 private static final String ACTION_DEVICE_IDLE =
146 "com.android.server.WifiManager.action.DEVICE_IDLE";
147
Irfan Sheriff658772f2011-03-08 14:52:31 -0800148 private static final int WIFI_DISABLED = 0;
149 private static final int WIFI_ENABLED = 1;
150 /* Wifi enabled while in airplane mode */
151 private static final int WIFI_ENABLED_AIRPLANE_OVERRIDE = 2;
152
153 private AtomicInteger mWifiState = new AtomicInteger(WIFI_DISABLED);
154 private AtomicBoolean mAirplaneModeOn = new AtomicBoolean(false);
155
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700156 private boolean mIsReceiverRegistered = false;
157
Irfan Sheriff0d255342010-07-28 09:35:20 -0700158
159 NetworkInfo mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_WIFI, 0, "WIFI", "");
160
161 // Variables relating to the 'available networks' notification
162 /**
163 * The icon to show in the 'available networks' notification. This will also
164 * be the ID of the Notification given to the NotificationManager.
165 */
166 private static final int ICON_NETWORKS_AVAILABLE =
167 com.android.internal.R.drawable.stat_notify_wifi_in_range;
168 /**
169 * When a notification is shown, we wait this amount before possibly showing it again.
170 */
171 private final long NOTIFICATION_REPEAT_DELAY_MS;
172 /**
173 * Whether the user has set the setting to show the 'available networks' notification.
174 */
175 private boolean mNotificationEnabled;
176 /**
177 * Observes the user setting to keep {@link #mNotificationEnabled} in sync.
178 */
179 private NotificationEnabledSettingObserver mNotificationEnabledSettingObserver;
180 /**
181 * The {@link System#currentTimeMillis()} must be at least this value for us
182 * to show the notification again.
183 */
184 private long mNotificationRepeatTime;
185 /**
186 * The Notification object given to the NotificationManager.
187 */
188 private Notification mNotification;
189 /**
190 * Whether the notification is being shown, as set by us. That is, if the
191 * user cancels the notification, we will not receive the callback so this
192 * will still be true. We only guarantee if this is false, then the
193 * notification is not showing.
194 */
195 private boolean mNotificationShown;
196 /**
197 * The number of continuous scans that must occur before consider the
198 * supplicant in a scanning state. This allows supplicant to associate with
199 * remembered networks that are in the scan results.
200 */
201 private static final int NUM_SCANS_BEFORE_ACTUALLY_SCANNING = 3;
202 /**
203 * The number of scans since the last network state change. When this
204 * exceeds {@link #NUM_SCANS_BEFORE_ACTUALLY_SCANNING}, we consider the
205 * supplicant to actually be scanning. When the network state changes to
206 * something other than scanning, we reset this to 0.
207 */
208 private int mNumScansSinceNetworkStateChange;
Jaikumar Ganesh7440fc22010-09-27 17:04:14 -0700209
Dianne Hackborn03f3cb02010-09-17 23:12:26 -0700210 /**
Wink Saville4b7ba092010-10-20 15:37:41 -0700211 * Asynchronous channel to WifiStateMachine
212 */
Irfan Sheriff227bec42011-02-15 19:30:27 -0800213 private AsyncChannel mWifiStateMachineChannel;
Wink Saville4b7ba092010-10-20 15:37:41 -0700214
215 /**
Irfan Sheriff227bec42011-02-15 19:30:27 -0800216 * Clients receiving asynchronous messages
Wink Saville4b7ba092010-10-20 15:37:41 -0700217 */
Irfan Sheriff227bec42011-02-15 19:30:27 -0800218 private List<AsyncChannel> mClients = new ArrayList<AsyncChannel>();
Wink Saville4b7ba092010-10-20 15:37:41 -0700219
Irfan Sheriff227bec42011-02-15 19:30:27 -0800220 /**
221 * Handles client connections
222 */
223 private class AsyncServiceHandler extends Handler {
224
225 AsyncServiceHandler(android.os.Looper looper) {
Wink Saville4b7ba092010-10-20 15:37:41 -0700226 super(looper);
Wink Saville4b7ba092010-10-20 15:37:41 -0700227 }
228
229 @Override
230 public void handleMessage(Message msg) {
231 switch (msg.what) {
232 case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: {
233 if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
Irfan Sheriff227bec42011-02-15 19:30:27 -0800234 Slog.d(TAG, "New client listening to asynchronous messages");
235 mClients.add((AsyncChannel) msg.obj);
Wink Saville4b7ba092010-10-20 15:37:41 -0700236 } else {
Irfan Sheriff227bec42011-02-15 19:30:27 -0800237 Slog.e(TAG, "Client connection failure, error=" + msg.arg1);
238 }
239 break;
240 }
Irfan Sheriffc23971b2011-03-04 17:06:31 -0800241 case AsyncChannel.CMD_CHANNEL_DISCONNECTED: {
242 if (msg.arg1 == AsyncChannel.STATUS_SEND_UNSUCCESSFUL) {
243 Slog.d(TAG, "Send failed, client connection lost");
244 } else {
245 Slog.d(TAG, "Client connection lost with reason: " + msg.arg1);
246 }
247 mClients.remove((AsyncChannel) msg.obj);
248 break;
249 }
Irfan Sheriff227bec42011-02-15 19:30:27 -0800250 case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION: {
251 AsyncChannel ac = new AsyncChannel();
252 ac.connect(mContext, this, msg.replyTo);
253 break;
254 }
Irfan Sheriffebe606f2011-02-24 11:39:15 -0800255 case WifiManager.CMD_ENABLE_TRAFFIC_STATS_POLL: {
Irfan Sheriff227bec42011-02-15 19:30:27 -0800256 mEnableTrafficStatsPoll = (msg.arg1 == 1);
257 mTrafficStatsPollToken++;
258 if (mEnableTrafficStatsPoll) {
259 notifyOnDataActivity();
Irfan Sheriffebe606f2011-02-24 11:39:15 -0800260 sendMessageDelayed(Message.obtain(this, WifiManager.CMD_TRAFFIC_STATS_POLL,
Irfan Sheriff227bec42011-02-15 19:30:27 -0800261 mTrafficStatsPollToken, 0), POLL_TRAFFIC_STATS_INTERVAL_MSECS);
262 }
263 break;
264 }
Irfan Sheriffebe606f2011-02-24 11:39:15 -0800265 case WifiManager.CMD_TRAFFIC_STATS_POLL: {
Irfan Sheriff227bec42011-02-15 19:30:27 -0800266 if (msg.arg1 == mTrafficStatsPollToken) {
267 notifyOnDataActivity();
Irfan Sheriffebe606f2011-02-24 11:39:15 -0800268 sendMessageDelayed(Message.obtain(this, WifiManager.CMD_TRAFFIC_STATS_POLL,
Irfan Sheriff227bec42011-02-15 19:30:27 -0800269 mTrafficStatsPollToken, 0), POLL_TRAFFIC_STATS_INTERVAL_MSECS);
Wink Saville4b7ba092010-10-20 15:37:41 -0700270 }
271 break;
272 }
Irfan Sheriffebe606f2011-02-24 11:39:15 -0800273 case WifiManager.CMD_CONNECT_NETWORK: {
274 if (msg.obj != null) {
275 mWifiStateMachine.connectNetwork((WifiConfiguration)msg.obj);
276 } else {
277 mWifiStateMachine.connectNetwork(msg.arg1);
278 }
279 break;
280 }
281 case WifiManager.CMD_SAVE_NETWORK: {
282 mWifiStateMachine.saveNetwork((WifiConfiguration)msg.obj);
283 break;
284 }
285 case WifiManager.CMD_FORGET_NETWORK: {
286 mWifiStateMachine.forgetNetwork(msg.arg1);
287 break;
288 }
289 case WifiManager.CMD_START_WPS: {
290 //replyTo has the original source
Irfan Sheriff651cdfc2011-09-07 00:31:20 -0700291 mWifiStateMachine.startWps(msg.replyTo, (WpsInfo)msg.obj);
Irfan Sheriffebe606f2011-02-24 11:39:15 -0800292 break;
293 }
Isaac Levy8dc6a1b2011-07-27 08:00:03 -0700294 case WifiManager.CMD_DISABLE_NETWORK: {
295 mWifiStateMachine.disableNetwork(msg.replyTo, msg.arg1, msg.arg2);
296 break;
297 }
Wink Saville4b7ba092010-10-20 15:37:41 -0700298 default: {
299 Slog.d(TAG, "WifiServicehandler.handleMessage ignoring msg=" + msg);
300 break;
301 }
302 }
303 }
304 }
Irfan Sheriff227bec42011-02-15 19:30:27 -0800305 private AsyncServiceHandler mAsyncServiceHandler;
306
307 /**
308 * Handles interaction with WifiStateMachine
309 */
310 private class WifiStateMachineHandler extends Handler {
311 private AsyncChannel mWsmChannel;
312
313 WifiStateMachineHandler(android.os.Looper looper) {
314 super(looper);
315 mWsmChannel = new AsyncChannel();
316 mWsmChannel.connect(mContext, this, mWifiStateMachine.getHandler());
317 }
318
319 @Override
320 public void handleMessage(Message msg) {
321 switch (msg.what) {
322 case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: {
323 if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
324 mWifiStateMachineChannel = mWsmChannel;
325 } else {
326 Slog.e(TAG, "WifiStateMachine connection failure, error=" + msg.arg1);
327 mWifiStateMachineChannel = null;
328 }
329 break;
330 }
Irfan Sheriff6da83d52011-06-06 12:54:06 -0700331 case AsyncChannel.CMD_CHANNEL_DISCONNECTED: {
332 Slog.e(TAG, "WifiStateMachine channel lost, msg.arg1 =" + msg.arg1);
333 mWifiStateMachineChannel = null;
334 //Re-establish connection to state machine
335 mWsmChannel.connect(mContext, this, mWifiStateMachine.getHandler());
336 break;
337 }
Irfan Sheriff227bec42011-02-15 19:30:27 -0800338 default: {
339 Slog.d(TAG, "WifiStateMachineHandler.handleMessage ignoring msg=" + msg);
340 break;
341 }
342 }
343 }
344 }
345 WifiStateMachineHandler mWifiStateMachineHandler;
Wink Saville4b7ba092010-10-20 15:37:41 -0700346
347 /**
Dianne Hackborn03f3cb02010-09-17 23:12:26 -0700348 * Temporary for computing UIDS that are responsible for starting WIFI.
349 * Protected by mWifiStateTracker lock.
350 */
351 private final WorkSource mTmpWorkSource = new WorkSource();
Isaac Levy654f5092011-07-13 17:41:45 -0700352 private WifiWatchdogStateMachine mWifiWatchdogStateMachine;
Irfan Sheriff0d255342010-07-28 09:35:20 -0700353
354 WifiService(Context context) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800355 mContext = context;
Irfan Sheriff227bec42011-02-15 19:30:27 -0800356
357 mInterfaceName = SystemProperties.get("wifi.interface", "wlan0");
358
359 mWifiStateMachine = new WifiStateMachine(mContext, mInterfaceName);
Irfan Sheriff0d255342010-07-28 09:35:20 -0700360 mWifiStateMachine.enableRssiPolling(true);
The Android Open Source Project10592532009-03-18 17:39:46 -0700361 mBatteryStats = BatteryStatsService.getService();
Jaikumar Ganesh084c6652009-12-07 10:58:18 -0800362
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800363 mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
364 Intent idleIntent = new Intent(ACTION_DEVICE_IDLE, null);
365 mIdleIntent = PendingIntent.getBroadcast(mContext, IDLE_REQUEST, idleIntent, 0);
366
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800367 mContext.registerReceiver(
368 new BroadcastReceiver() {
369 @Override
370 public void onReceive(Context context, Intent intent) {
Irfan Sheriff658772f2011-03-08 14:52:31 -0800371 mAirplaneModeOn.set(isAirplaneModeOn());
372 /* On airplane mode disable, restore wifi state if necessary */
373 if (!mAirplaneModeOn.get() && (testAndClearWifiSavedState() ||
374 mWifiState.get() == WIFI_ENABLED_AIRPLANE_OVERRIDE)) {
375 persistWifiEnabled(true);
Irfan Sheriffb2e6c012010-04-05 11:57:56 -0700376 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800377 updateWifiState();
378 }
379 },
380 new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED));
381
Irfan Sheriff0d255342010-07-28 09:35:20 -0700382 IntentFilter filter = new IntentFilter();
383 filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
384 filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
385 filter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
386
387 mContext.registerReceiver(
388 new BroadcastReceiver() {
389 @Override
390 public void onReceive(Context context, Intent intent) {
391 if (intent.getAction().equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) {
392 // reset & clear notification on any wifi state change
393 resetNotification();
394 } else if (intent.getAction().equals(
395 WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
396 mNetworkInfo = (NetworkInfo) intent.getParcelableExtra(
397 WifiManager.EXTRA_NETWORK_INFO);
398 // reset & clear notification on a network connect & disconnect
399 switch(mNetworkInfo.getDetailedState()) {
400 case CONNECTED:
401 case DISCONNECTED:
Irfan Sheriff227bec42011-02-15 19:30:27 -0800402 evaluateTrafficStatsPolling();
Irfan Sheriff0d255342010-07-28 09:35:20 -0700403 resetNotification();
404 break;
405 }
406 } else if (intent.getAction().equals(
407 WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) {
408 checkAndSetNotification();
409 }
410 }
411 }, filter);
412
Irfan Sheriff227bec42011-02-15 19:30:27 -0800413 HandlerThread wifiThread = new HandlerThread("WifiService");
414 wifiThread.start();
415 mAsyncServiceHandler = new AsyncServiceHandler(wifiThread.getLooper());
416 mWifiStateMachineHandler = new WifiStateMachineHandler(wifiThread.getLooper());
417
Irfan Sheriff0d255342010-07-28 09:35:20 -0700418 // Setting is in seconds
419 NOTIFICATION_REPEAT_DELAY_MS = Settings.Secure.getInt(context.getContentResolver(),
420 Settings.Secure.WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY, 900) * 1000l;
421 mNotificationEnabledSettingObserver = new NotificationEnabledSettingObserver(new Handler());
422 mNotificationEnabledSettingObserver.register();
Irfan Sherifffcc08452011-02-17 16:44:54 -0800423
424 mBackgroundScanSupported = mContext.getResources().getBoolean(
425 com.android.internal.R.bool.config_wifi_background_scan_support);
Irfan Sheriff7b009782010-03-11 16:37:45 -0800426 }
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800427
Irfan Sheriff7b009782010-03-11 16:37:45 -0800428 /**
429 * Check if Wi-Fi needs to be enabled and start
430 * if needed
Irfan Sheriff60e3ba02010-04-02 12:18:45 -0700431 *
432 * This function is used only at boot time
Irfan Sheriff7b009782010-03-11 16:37:45 -0800433 */
Irfan Sheriff0d255342010-07-28 09:35:20 -0700434 public void checkAndStartWifi() {
Irfan Sheriff658772f2011-03-08 14:52:31 -0800435 mAirplaneModeOn.set(isAirplaneModeOn());
436 mWifiState.set(getPersistedWifiState());
437 /* Start if Wi-Fi should be enabled or the saved state indicates Wi-Fi was on */
438 boolean wifiEnabled = shouldWifiBeEnabled() || testAndClearWifiSavedState();
Irfan Sheriff7b009782010-03-11 16:37:45 -0800439 Slog.i(TAG, "WifiService starting up with Wi-Fi " +
440 (wifiEnabled ? "enabled" : "disabled"));
Irfan Sheriffb99fe5e2010-03-26 14:56:07 -0700441 setWifiEnabled(wifiEnabled);
Isaac Levybc7dfb52011-06-06 15:34:01 -0700442
Isaac Levy654f5092011-07-13 17:41:45 -0700443 mWifiWatchdogStateMachine = WifiWatchdogStateMachine.
444 makeWifiWatchdogStateMachine(mContext);
445
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800446 }
447
Irfan Sheriffa3bd4092010-03-24 17:58:59 -0700448 private boolean testAndClearWifiSavedState() {
449 final ContentResolver cr = mContext.getContentResolver();
450 int wifiSavedState = 0;
451 try {
452 wifiSavedState = Settings.Secure.getInt(cr, Settings.Secure.WIFI_SAVED_STATE);
453 if(wifiSavedState == 1)
454 Settings.Secure.putInt(cr, Settings.Secure.WIFI_SAVED_STATE, 0);
455 } catch (Settings.SettingNotFoundException e) {
456 ;
457 }
458 return (wifiSavedState == 1);
459 }
460
Irfan Sheriff658772f2011-03-08 14:52:31 -0800461 private int getPersistedWifiState() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800462 final ContentResolver cr = mContext.getContentResolver();
463 try {
Irfan Sheriff658772f2011-03-08 14:52:31 -0800464 return Settings.Secure.getInt(cr, Settings.Secure.WIFI_ON);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800465 } catch (Settings.SettingNotFoundException e) {
Irfan Sheriff658772f2011-03-08 14:52:31 -0800466 Settings.Secure.putInt(cr, Settings.Secure.WIFI_ON, WIFI_DISABLED);
467 return WIFI_DISABLED;
468 }
469 }
470
471 private boolean shouldWifiBeEnabled() {
472 if (mAirplaneModeOn.get()) {
473 return mWifiState.get() == WIFI_ENABLED_AIRPLANE_OVERRIDE;
474 } else {
475 return mWifiState.get() != WIFI_DISABLED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800476 }
477 }
478
479 private void persistWifiEnabled(boolean enabled) {
480 final ContentResolver cr = mContext.getContentResolver();
Irfan Sheriff658772f2011-03-08 14:52:31 -0800481 if (enabled) {
482 if (isAirplaneModeOn() && isAirplaneToggleable()) {
483 mWifiState.set(WIFI_ENABLED_AIRPLANE_OVERRIDE);
484 } else {
485 mWifiState.set(WIFI_ENABLED);
486 }
487 } else {
488 mWifiState.set(WIFI_DISABLED);
489 }
490 Settings.Secure.putInt(cr, Settings.Secure.WIFI_ON, mWifiState.get());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800491 }
492
Irfan Sheriff658772f2011-03-08 14:52:31 -0800493
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800494 /**
495 * see {@link android.net.wifi.WifiManager#pingSupplicant()}
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700496 * @return {@code true} if the operation succeeds, {@code false} otherwise
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800497 */
498 public boolean pingSupplicant() {
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700499 enforceAccessPermission();
Irfan Sheriff227bec42011-02-15 19:30:27 -0800500 if (mWifiStateMachineChannel != null) {
501 return mWifiStateMachine.syncPingSupplicant(mWifiStateMachineChannel);
Irfan Sheriff1406bcb2010-10-28 14:41:39 -0700502 } else {
Irfan Sheriff227bec42011-02-15 19:30:27 -0800503 Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
Irfan Sheriff1406bcb2010-10-28 14:41:39 -0700504 return false;
505 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800506 }
507
508 /**
509 * see {@link android.net.wifi.WifiManager#startScan()}
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800510 */
Irfan Sheriffe4984752010-08-19 11:29:22 -0700511 public void startScan(boolean forceActive) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800512 enforceChangePermission();
Irfan Sheriffe4984752010-08-19 11:29:22 -0700513 mWifiStateMachine.startScan(forceActive);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800514 }
515
516 private void enforceAccessPermission() {
517 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_WIFI_STATE,
518 "WifiService");
519 }
520
521 private void enforceChangePermission() {
522 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CHANGE_WIFI_STATE,
523 "WifiService");
524
525 }
526
Robert Greenwaltfc1b15c2009-05-22 15:09:51 -0700527 private void enforceMulticastChangePermission() {
528 mContext.enforceCallingOrSelfPermission(
529 android.Manifest.permission.CHANGE_WIFI_MULTICAST_STATE,
530 "WifiService");
531 }
532
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800533 /**
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700534 * see {@link android.net.wifi.WifiManager#setWifiEnabled(boolean)}
535 * @param enable {@code true} to enable, {@code false} to disable.
536 * @return {@code true} if the enable/disable operation was
537 * started or is already in the queue.
538 */
539 public synchronized boolean setWifiEnabled(boolean enable) {
540 enforceChangePermission();
541
542 if (DBG) {
Irfan Sheriff0d255342010-07-28 09:35:20 -0700543 Slog.e(TAG, "Invoking mWifiStateMachine.setWifiEnabled\n");
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700544 }
545
Dianne Hackborn03f3cb02010-09-17 23:12:26 -0700546 if (enable) {
547 reportStartWorkSource();
548 }
Irfan Sheriff0d255342010-07-28 09:35:20 -0700549 mWifiStateMachine.setWifiEnabled(enable);
Irfan Sheriff61180692010-08-18 16:07:39 -0700550
551 /*
552 * Caller might not have WRITE_SECURE_SETTINGS,
553 * only CHANGE_WIFI_STATE is enforced
554 */
555 long ident = Binder.clearCallingIdentity();
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700556 persistWifiEnabled(enable);
Irfan Sheriff61180692010-08-18 16:07:39 -0700557 Binder.restoreCallingIdentity(ident);
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700558
559 if (enable) {
560 if (!mIsReceiverRegistered) {
561 registerForBroadcasts();
562 mIsReceiverRegistered = true;
563 }
564 } else if (mIsReceiverRegistered){
565 mContext.unregisterReceiver(mReceiver);
566 mIsReceiverRegistered = false;
567 }
568
569 return true;
570 }
571
572 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800573 * see {@link WifiManager#getWifiState()}
574 * @return One of {@link WifiManager#WIFI_STATE_DISABLED},
575 * {@link WifiManager#WIFI_STATE_DISABLING},
576 * {@link WifiManager#WIFI_STATE_ENABLED},
577 * {@link WifiManager#WIFI_STATE_ENABLING},
578 * {@link WifiManager#WIFI_STATE_UNKNOWN}
579 */
580 public int getWifiEnabledState() {
581 enforceAccessPermission();
Irfan Sheriffd8134ff2010-08-22 17:06:34 -0700582 return mWifiStateMachine.syncGetWifiState();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800583 }
584
585 /**
Irfan Sheriffc2f54c22010-03-18 14:02:22 -0700586 * see {@link android.net.wifi.WifiManager#setWifiApEnabled(WifiConfiguration, boolean)}
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800587 * @param wifiConfig SSID, security and channel details as
588 * part of WifiConfiguration
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700589 * @param enabled true to enable and false to disable
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800590 */
Irfan Sheriffffcea7a2011-05-10 16:26:06 -0700591 public void setWifiApEnabled(WifiConfiguration wifiConfig, boolean enabled) {
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800592 enforceChangePermission();
Irfan Sheriff0d255342010-07-28 09:35:20 -0700593 mWifiStateMachine.setWifiApEnabled(wifiConfig, enabled);
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800594 }
595
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700596 /**
597 * see {@link WifiManager#getWifiApState()}
598 * @return One of {@link WifiManager#WIFI_AP_STATE_DISABLED},
599 * {@link WifiManager#WIFI_AP_STATE_DISABLING},
600 * {@link WifiManager#WIFI_AP_STATE_ENABLED},
601 * {@link WifiManager#WIFI_AP_STATE_ENABLING},
602 * {@link WifiManager#WIFI_AP_STATE_FAILED}
603 */
604 public int getWifiApEnabledState() {
Irfan Sheriff17b232b2010-06-24 11:32:26 -0700605 enforceAccessPermission();
Irfan Sheriffd8134ff2010-08-22 17:06:34 -0700606 return mWifiStateMachine.syncGetWifiApState();
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700607 }
608
609 /**
610 * see {@link WifiManager#getWifiApConfiguration()}
611 * @return soft access point configuration
612 */
Irfan Sheriffffcea7a2011-05-10 16:26:06 -0700613 public WifiConfiguration getWifiApConfiguration() {
614 enforceAccessPermission();
Irfan Sheriff6da83d52011-06-06 12:54:06 -0700615 if (mWifiStateMachineChannel != null) {
616 return mWifiStateMachine.syncGetWifiApConfiguration(mWifiStateMachineChannel);
617 } else {
618 Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
619 return null;
620 }
Irfan Sheriff9ab518ad2010-03-12 15:48:17 -0800621 }
622
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700623 /**
624 * see {@link WifiManager#setWifiApConfiguration(WifiConfiguration)}
625 * @param wifiConfig WifiConfiguration details for soft access point
626 */
Irfan Sheriffffcea7a2011-05-10 16:26:06 -0700627 public void setWifiApConfiguration(WifiConfiguration wifiConfig) {
Irfan Sheriff17b232b2010-06-24 11:32:26 -0700628 enforceChangePermission();
Irfan Sheriff9ab518ad2010-03-12 15:48:17 -0800629 if (wifiConfig == null)
630 return;
Irfan Sheriffffcea7a2011-05-10 16:26:06 -0700631 mWifiStateMachine.setWifiApConfiguration(wifiConfig);
Irfan Sheriff9ab518ad2010-03-12 15:48:17 -0800632 }
633
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800634 /**
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700635 * see {@link android.net.wifi.WifiManager#disconnect()}
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800636 */
Irfan Sheriffe4984752010-08-19 11:29:22 -0700637 public void disconnect() {
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700638 enforceChangePermission();
Irfan Sheriffe4984752010-08-19 11:29:22 -0700639 mWifiStateMachine.disconnectCommand();
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800640 }
641
642 /**
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700643 * see {@link android.net.wifi.WifiManager#reconnect()}
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800644 */
Irfan Sheriffe4984752010-08-19 11:29:22 -0700645 public void reconnect() {
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700646 enforceChangePermission();
Irfan Sheriffe4984752010-08-19 11:29:22 -0700647 mWifiStateMachine.reconnectCommand();
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800648 }
649
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700650 /**
651 * see {@link android.net.wifi.WifiManager#reassociate()}
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700652 */
Irfan Sheriffe4984752010-08-19 11:29:22 -0700653 public void reassociate() {
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700654 enforceChangePermission();
Irfan Sheriffe4984752010-08-19 11:29:22 -0700655 mWifiStateMachine.reassociateCommand();
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800656 }
657
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800658 /**
659 * see {@link android.net.wifi.WifiManager#getConfiguredNetworks()}
660 * @return the list of configured networks
661 */
662 public List<WifiConfiguration> getConfiguredNetworks() {
663 enforceAccessPermission();
Irfan Sheriffd8134ff2010-08-22 17:06:34 -0700664 return mWifiStateMachine.syncGetConfiguredNetworks();
Chung-yih Wanga8d15942009-10-09 11:01:49 +0800665 }
666
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800667 /**
668 * see {@link android.net.wifi.WifiManager#addOrUpdateNetwork(WifiConfiguration)}
669 * @return the supplicant-assigned identifier for the new or updated
670 * network if the operation succeeds, or {@code -1} if it fails
671 */
Irfan Sheriff7aac5542009-12-22 21:42:17 -0800672 public int addOrUpdateNetwork(WifiConfiguration config) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800673 enforceChangePermission();
Irfan Sheriff227bec42011-02-15 19:30:27 -0800674 if (mWifiStateMachineChannel != null) {
675 return mWifiStateMachine.syncAddOrUpdateNetwork(mWifiStateMachineChannel, config);
Irfan Sheriff1406bcb2010-10-28 14:41:39 -0700676 } else {
Irfan Sheriff227bec42011-02-15 19:30:27 -0800677 Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
Irfan Sheriff1406bcb2010-10-28 14:41:39 -0700678 return -1;
679 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800680 }
681
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700682 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800683 * See {@link android.net.wifi.WifiManager#removeNetwork(int)}
684 * @param netId the integer that identifies the network configuration
685 * to the supplicant
686 * @return {@code true} if the operation succeeded
687 */
688 public boolean removeNetwork(int netId) {
689 enforceChangePermission();
Irfan Sheriff227bec42011-02-15 19:30:27 -0800690 if (mWifiStateMachineChannel != null) {
691 return mWifiStateMachine.syncRemoveNetwork(mWifiStateMachineChannel, netId);
Wink Saville4b7ba092010-10-20 15:37:41 -0700692 } else {
Irfan Sheriff227bec42011-02-15 19:30:27 -0800693 Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
Wink Saville4b7ba092010-10-20 15:37:41 -0700694 return false;
695 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800696 }
697
698 /**
699 * See {@link android.net.wifi.WifiManager#enableNetwork(int, boolean)}
700 * @param netId the integer that identifies the network configuration
701 * to the supplicant
702 * @param disableOthers if true, disable all other networks.
703 * @return {@code true} if the operation succeeded
704 */
705 public boolean enableNetwork(int netId, boolean disableOthers) {
706 enforceChangePermission();
Irfan Sheriff227bec42011-02-15 19:30:27 -0800707 if (mWifiStateMachineChannel != null) {
708 return mWifiStateMachine.syncEnableNetwork(mWifiStateMachineChannel, netId,
709 disableOthers);
Irfan Sheriff1406bcb2010-10-28 14:41:39 -0700710 } else {
Irfan Sheriff227bec42011-02-15 19:30:27 -0800711 Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
Irfan Sheriff1406bcb2010-10-28 14:41:39 -0700712 return false;
713 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800714 }
715
716 /**
717 * See {@link android.net.wifi.WifiManager#disableNetwork(int)}
718 * @param netId the integer that identifies the network configuration
719 * to the supplicant
720 * @return {@code true} if the operation succeeded
721 */
722 public boolean disableNetwork(int netId) {
723 enforceChangePermission();
Irfan Sheriff227bec42011-02-15 19:30:27 -0800724 if (mWifiStateMachineChannel != null) {
725 return mWifiStateMachine.syncDisableNetwork(mWifiStateMachineChannel, netId);
Irfan Sheriff1406bcb2010-10-28 14:41:39 -0700726 } else {
Irfan Sheriff227bec42011-02-15 19:30:27 -0800727 Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
Irfan Sheriff1406bcb2010-10-28 14:41:39 -0700728 return false;
729 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800730 }
731
732 /**
733 * See {@link android.net.wifi.WifiManager#getConnectionInfo()}
734 * @return the Wi-Fi information, contained in {@link WifiInfo}.
735 */
736 public WifiInfo getConnectionInfo() {
737 enforceAccessPermission();
738 /*
739 * Make sure we have the latest information, by sending
740 * a status request to the supplicant.
741 */
Irfan Sheriffd8134ff2010-08-22 17:06:34 -0700742 return mWifiStateMachine.syncRequestConnectionInfo();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800743 }
744
745 /**
746 * Return the results of the most recent access point scan, in the form of
747 * a list of {@link ScanResult} objects.
748 * @return the list of results
749 */
750 public List<ScanResult> getScanResults() {
751 enforceAccessPermission();
Irfan Sheriffd8134ff2010-08-22 17:06:34 -0700752 return mWifiStateMachine.syncGetScanResultsList();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800753 }
754
755 /**
756 * Tell the supplicant to persist the current list of configured networks.
757 * @return {@code true} if the operation succeeded
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700758 *
759 * TODO: deprecate this
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800760 */
761 public boolean saveConfiguration() {
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700762 boolean result = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800763 enforceChangePermission();
Irfan Sheriff227bec42011-02-15 19:30:27 -0800764 if (mWifiStateMachineChannel != null) {
765 return mWifiStateMachine.syncSaveConfig(mWifiStateMachineChannel);
Irfan Sheriff1406bcb2010-10-28 14:41:39 -0700766 } else {
Irfan Sheriff227bec42011-02-15 19:30:27 -0800767 Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
Irfan Sheriff1406bcb2010-10-28 14:41:39 -0700768 return false;
769 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800770 }
771
772 /**
Irfan Sheriffed4f28b2010-10-29 15:32:10 -0700773 * Set the country code
774 * @param countryCode ISO 3166 country code.
Robert Greenwaltb5010cc2009-05-21 15:11:40 -0700775 * @param persist {@code true} if the setting should be remembered.
Irfan Sheriffed4f28b2010-10-29 15:32:10 -0700776 *
777 * The persist behavior exists so that wifi can fall back to the last
778 * persisted country code on a restart, when the locale information is
779 * not available from telephony.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800780 */
Irfan Sheriffed4f28b2010-10-29 15:32:10 -0700781 public void setCountryCode(String countryCode, boolean persist) {
782 Slog.i(TAG, "WifiService trying to set country code to " + countryCode +
783 " with persist set to " + persist);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800784 enforceChangePermission();
Irfan Sheriffed4f28b2010-10-29 15:32:10 -0700785 mWifiStateMachine.setCountryCode(countryCode, persist);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800786 }
787
788 /**
Irfan Sheriff36f74132010-11-04 16:57:37 -0700789 * Set the operational frequency band
790 * @param band One of
791 * {@link WifiManager#WIFI_FREQUENCY_BAND_AUTO},
792 * {@link WifiManager#WIFI_FREQUENCY_BAND_5GHZ},
793 * {@link WifiManager#WIFI_FREQUENCY_BAND_2GHZ},
794 * @param persist {@code true} if the setting should be remembered.
795 *
796 */
797 public void setFrequencyBand(int band, boolean persist) {
798 enforceChangePermission();
799 if (!isDualBandSupported()) return;
800 Slog.i(TAG, "WifiService trying to set frequency band to " + band +
801 " with persist set to " + persist);
802 mWifiStateMachine.setFrequencyBand(band, persist);
803 }
804
805
806 /**
807 * Get the operational frequency band
808 */
809 public int getFrequencyBand() {
810 enforceAccessPermission();
811 return mWifiStateMachine.getFrequencyBand();
812 }
813
814 public boolean isDualBandSupported() {
815 //TODO: Should move towards adding a driver API that checks at runtime
816 return mContext.getResources().getBoolean(
817 com.android.internal.R.bool.config_wifi_dual_band_support);
818 }
819
820 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800821 * Return the DHCP-assigned addresses from the last successful DHCP request,
822 * if any.
823 * @return the DHCP information
824 */
825 public DhcpInfo getDhcpInfo() {
826 enforceAccessPermission();
Irfan Sheriffd8134ff2010-08-22 17:06:34 -0700827 return mWifiStateMachine.syncGetDhcpInfo();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800828 }
829
Irfan Sheriff0d255342010-07-28 09:35:20 -0700830 /**
831 * see {@link android.net.wifi.WifiManager#startWifi}
832 *
833 */
834 public void startWifi() {
835 enforceChangePermission();
836 /* TODO: may be add permissions for access only to connectivity service
837 * TODO: if a start issued, keep wifi alive until a stop issued irrespective
838 * of WifiLock & device idle status unless wifi enabled status is toggled
839 */
840
841 mWifiStateMachine.setDriverStart(true);
842 mWifiStateMachine.reconnectCommand();
843 }
844
845 /**
846 * see {@link android.net.wifi.WifiManager#stopWifi}
847 *
848 */
849 public void stopWifi() {
850 enforceChangePermission();
851 /* TODO: may be add permissions for access only to connectivity service
852 * TODO: if a stop is issued, wifi is brought up only by startWifi
853 * unless wifi enabled status is toggled
854 */
855 mWifiStateMachine.setDriverStart(false);
856 }
857
858
859 /**
860 * see {@link android.net.wifi.WifiManager#addToBlacklist}
861 *
862 */
863 public void addToBlacklist(String bssid) {
864 enforceChangePermission();
865
866 mWifiStateMachine.addToBlacklist(bssid);
867 }
868
869 /**
870 * see {@link android.net.wifi.WifiManager#clearBlacklist}
871 *
872 */
873 public void clearBlacklist() {
874 enforceChangePermission();
875
876 mWifiStateMachine.clearBlacklist();
877 }
878
Irfan Sheriff227bec42011-02-15 19:30:27 -0800879 /**
880 * Get a reference to handler. This is used by a client to establish
881 * an AsyncChannel communication with WifiService
882 */
883 public Messenger getMessenger() {
Irfan Sheriffebe606f2011-02-24 11:39:15 -0800884 /* Enforce the highest permissions
885 TODO: when we consider exposing the asynchronous API, think about
886 how to provide both access and change permissions seperately
887 */
Irfan Sheriff227bec42011-02-15 19:30:27 -0800888 enforceAccessPermission();
Irfan Sheriffebe606f2011-02-24 11:39:15 -0800889 enforceChangePermission();
Irfan Sheriff227bec42011-02-15 19:30:27 -0800890 return new Messenger(mAsyncServiceHandler);
891 }
892
Irfan Sheriff4aeca7c52011-03-10 16:53:33 -0800893 /**
894 * Get the IP and proxy configuration file
895 */
896 public String getConfigFile() {
897 enforceAccessPermission();
898 return mWifiStateMachine.getConfigFile();
899 }
900
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800901 private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
902 @Override
903 public void onReceive(Context context, Intent intent) {
904 String action = intent.getAction();
905
Doug Zongker43866e02010-01-07 12:09:54 -0800906 long idleMillis =
907 Settings.Secure.getLong(mContext.getContentResolver(),
Irfan Sheriff4f5f7c92010-10-14 17:01:27 -0700908 Settings.Secure.WIFI_IDLE_MS, DEFAULT_IDLE_MS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800909 int stayAwakeConditions =
Doug Zongker43866e02010-01-07 12:09:54 -0800910 Settings.System.getInt(mContext.getContentResolver(),
911 Settings.System.STAY_ON_WHILE_PLUGGED_IN, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800912 if (action.equals(Intent.ACTION_SCREEN_ON)) {
Joe Onorato431bb222010-10-18 19:13:23 -0400913 if (DBG) {
914 Slog.d(TAG, "ACTION_SCREEN_ON");
915 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800916 mAlarmManager.cancel(mIdleIntent);
917 mDeviceIdle = false;
918 mScreenOff = false;
Dianne Hackborn58e0eef2010-09-16 01:22:10 -0700919 // Once the screen is on, we are not keeping WIFI running
920 // because of any locks so clear that tracking immediately.
921 reportStartWorkSource();
Irfan Sheriff227bec42011-02-15 19:30:27 -0800922 evaluateTrafficStatsPolling();
Irfan Sheriff0d255342010-07-28 09:35:20 -0700923 mWifiStateMachine.enableRssiPolling(true);
Irfan Sherifffcc08452011-02-17 16:44:54 -0800924 if (mBackgroundScanSupported) {
Irfan Sheriff2b7f6382011-03-25 14:29:19 -0700925 mWifiStateMachine.enableBackgroundScanCommand(false);
Irfan Sherifffcc08452011-02-17 16:44:54 -0800926 }
Irfan Sheriff8e86b892010-12-22 11:02:20 -0800927 mWifiStateMachine.enableAllNetworks();
Irfan Sheriff4f5f7c92010-10-14 17:01:27 -0700928 updateWifiState();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800929 } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
Joe Onorato431bb222010-10-18 19:13:23 -0400930 if (DBG) {
931 Slog.d(TAG, "ACTION_SCREEN_OFF");
932 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800933 mScreenOff = true;
Irfan Sheriff227bec42011-02-15 19:30:27 -0800934 evaluateTrafficStatsPolling();
Irfan Sheriff0d255342010-07-28 09:35:20 -0700935 mWifiStateMachine.enableRssiPolling(false);
Irfan Sherifffcc08452011-02-17 16:44:54 -0800936 if (mBackgroundScanSupported) {
Irfan Sheriff2b7f6382011-03-25 14:29:19 -0700937 mWifiStateMachine.enableBackgroundScanCommand(true);
Irfan Sherifffcc08452011-02-17 16:44:54 -0800938 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800939 /*
940 * Set a timer to put Wi-Fi to sleep, but only if the screen is off
941 * AND the "stay on while plugged in" setting doesn't match the
942 * current power conditions (i.e, not plugged in, plugged in to USB,
943 * or plugged in to AC).
944 */
945 if (!shouldWifiStayAwake(stayAwakeConditions, mPluggedType)) {
Irfan Sheriffd8134ff2010-08-22 17:06:34 -0700946 WifiInfo info = mWifiStateMachine.syncRequestConnectionInfo();
San Mehatfa6c7112009-07-07 09:34:44 -0700947 if (info.getSupplicantState() != SupplicantState.COMPLETED) {
Robert Greenwalt84612ea62009-09-30 09:04:22 -0700948 // we used to go to sleep immediately, but this caused some race conditions
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700949 // we don't have time to track down for this release. Delay instead,
950 // but not as long as we would if connected (below)
Robert Greenwalt84612ea62009-09-30 09:04:22 -0700951 // TODO - fix the race conditions and switch back to the immediate turn-off
952 long triggerTime = System.currentTimeMillis() + (2*60*1000); // 2 min
Joe Onorato431bb222010-10-18 19:13:23 -0400953 if (DBG) {
954 Slog.d(TAG, "setting ACTION_DEVICE_IDLE timer for 120,000 ms");
955 }
Robert Greenwalt84612ea62009-09-30 09:04:22 -0700956 mAlarmManager.set(AlarmManager.RTC_WAKEUP, triggerTime, mIdleIntent);
957 // // do not keep Wifi awake when screen is off if Wifi is not associated
958 // mDeviceIdle = true;
959 // updateWifiState();
Mike Lockwoodd9c32bc2009-05-18 14:14:15 -0400960 } else {
961 long triggerTime = System.currentTimeMillis() + idleMillis;
Joe Onorato431bb222010-10-18 19:13:23 -0400962 if (DBG) {
963 Slog.d(TAG, "setting ACTION_DEVICE_IDLE timer for " + idleMillis
964 + "ms");
965 }
Mike Lockwoodd9c32bc2009-05-18 14:14:15 -0400966 mAlarmManager.set(AlarmManager.RTC_WAKEUP, triggerTime, mIdleIntent);
967 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800968 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800969 } else if (action.equals(ACTION_DEVICE_IDLE)) {
Joe Onorato431bb222010-10-18 19:13:23 -0400970 if (DBG) {
971 Slog.d(TAG, "got ACTION_DEVICE_IDLE");
972 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800973 mDeviceIdle = true;
Dianne Hackborn58e0eef2010-09-16 01:22:10 -0700974 reportStartWorkSource();
Irfan Sheriff4f5f7c92010-10-14 17:01:27 -0700975 updateWifiState();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800976 } else if (action.equals(Intent.ACTION_BATTERY_CHANGED)) {
977 /*
978 * Set a timer to put Wi-Fi to sleep, but only if the screen is off
979 * AND we are transitioning from a state in which the device was supposed
980 * to stay awake to a state in which it is not supposed to stay awake.
981 * If "stay awake" state is not changing, we do nothing, to avoid resetting
982 * the already-set timer.
983 */
984 int pluggedType = intent.getIntExtra("plugged", 0);
Joe Onorato431bb222010-10-18 19:13:23 -0400985 if (DBG) {
986 Slog.d(TAG, "ACTION_BATTERY_CHANGED pluggedType: " + pluggedType);
987 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800988 if (mScreenOff && shouldWifiStayAwake(stayAwakeConditions, mPluggedType) &&
989 !shouldWifiStayAwake(stayAwakeConditions, pluggedType)) {
990 long triggerTime = System.currentTimeMillis() + idleMillis;
Joe Onorato431bb222010-10-18 19:13:23 -0400991 if (DBG) {
992 Slog.d(TAG, "setting ACTION_DEVICE_IDLE timer for " + idleMillis + "ms");
993 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800994 mAlarmManager.set(AlarmManager.RTC_WAKEUP, triggerTime, mIdleIntent);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800995 }
996 mPluggedType = pluggedType;
Irfan Sheriff65eaec82011-01-05 22:00:16 -0800997 } else if (action.equals(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED)) {
998 int state = intent.getIntExtra(BluetoothAdapter.EXTRA_CONNECTION_STATE,
999 BluetoothAdapter.STATE_DISCONNECTED);
1000 mWifiStateMachine.sendBluetoothAdapterStateChange(state);
Irfan Sheriff616f3172011-09-11 19:59:01 -07001001 } else if (action.equals(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED)) {
1002 mEmergencyCallbackMode = intent.getBooleanExtra("phoneinECMState", false);
1003 updateWifiState();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001004 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001005 }
1006
1007 /**
1008 * Determines whether the Wi-Fi chipset should stay awake or be put to
1009 * sleep. Looks at the setting for the sleep policy and the current
1010 * conditions.
Jaikumar Ganesh084c6652009-12-07 10:58:18 -08001011 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001012 * @see #shouldDeviceStayAwake(int, int)
1013 */
1014 private boolean shouldWifiStayAwake(int stayAwakeConditions, int pluggedType) {
Irfan Sheriff739f6bc2011-01-28 16:43:12 -08001015 //Never sleep as long as the user has not changed the settings
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001016 int wifiSleepPolicy = Settings.System.getInt(mContext.getContentResolver(),
Irfan Sheriff96b10d62011-01-11 15:40:35 -08001017 Settings.System.WIFI_SLEEP_POLICY,
Irfan Sheriff739f6bc2011-01-28 16:43:12 -08001018 Settings.System.WIFI_SLEEP_POLICY_NEVER);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001019
1020 if (wifiSleepPolicy == Settings.System.WIFI_SLEEP_POLICY_NEVER) {
1021 // Never sleep
1022 return true;
1023 } else if ((wifiSleepPolicy == Settings.System.WIFI_SLEEP_POLICY_NEVER_WHILE_PLUGGED) &&
1024 (pluggedType != 0)) {
1025 // Never sleep while plugged, and we're plugged
1026 return true;
1027 } else {
1028 // Default
1029 return shouldDeviceStayAwake(stayAwakeConditions, pluggedType);
1030 }
1031 }
Jaikumar Ganesh084c6652009-12-07 10:58:18 -08001032
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001033 /**
1034 * Determine whether the bit value corresponding to {@code pluggedType} is set in
1035 * the bit string {@code stayAwakeConditions}. Because a {@code pluggedType} value
1036 * of {@code 0} isn't really a plugged type, but rather an indication that the
1037 * device isn't plugged in at all, there is no bit value corresponding to a
1038 * {@code pluggedType} value of {@code 0}. That is why we shift by
Ben Dodson4e8620f2010-08-25 10:55:47 -07001039 * {@code pluggedType - 1} instead of by {@code pluggedType}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001040 * @param stayAwakeConditions a bit string specifying which "plugged types" should
1041 * keep the device (and hence Wi-Fi) awake.
1042 * @param pluggedType the type of plug (USB, AC, or none) for which the check is
1043 * being made
1044 * @return {@code true} if {@code pluggedType} indicates that the device is
1045 * supposed to stay awake, {@code false} otherwise.
1046 */
1047 private boolean shouldDeviceStayAwake(int stayAwakeConditions, int pluggedType) {
1048 return (stayAwakeConditions & pluggedType) != 0;
1049 }
1050 };
1051
Dianne Hackborn03f3cb02010-09-17 23:12:26 -07001052 private synchronized void reportStartWorkSource() {
1053 mTmpWorkSource.clear();
1054 if (mDeviceIdle) {
1055 for (int i=0; i<mLocks.mList.size(); i++) {
1056 mTmpWorkSource.add(mLocks.mList.get(i).mWorkSource);
Dianne Hackborn58e0eef2010-09-16 01:22:10 -07001057 }
Dianne Hackborn58e0eef2010-09-16 01:22:10 -07001058 }
Dianne Hackborn03f3cb02010-09-17 23:12:26 -07001059 mWifiStateMachine.updateBatteryWorkSource(mTmpWorkSource);
Dianne Hackborn58e0eef2010-09-16 01:22:10 -07001060 }
Jaikumar Ganesh7440fc22010-09-27 17:04:14 -07001061
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001062 private void updateWifiState() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001063 boolean lockHeld = mLocks.hasLocks();
Irfan Sheriff5876a422010-08-12 20:26:23 -07001064 int strongestLockMode = WifiManager.WIFI_MODE_FULL;
Irfan Sheriff616f3172011-09-11 19:59:01 -07001065 boolean wifiShouldBeStarted;
1066
1067 if (mEmergencyCallbackMode) {
1068 wifiShouldBeStarted = false;
1069 } else {
1070 wifiShouldBeStarted = !mDeviceIdle || lockHeld;
1071 }
Irfan Sheriff5876a422010-08-12 20:26:23 -07001072
1073 if (lockHeld) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001074 strongestLockMode = mLocks.getStrongestLockMode();
Irfan Sheriff5876a422010-08-12 20:26:23 -07001075 }
1076 /* If device is not idle, lockmode cannot be scan only */
1077 if (!mDeviceIdle && strongestLockMode == WifiManager.WIFI_MODE_SCAN_ONLY) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001078 strongestLockMode = WifiManager.WIFI_MODE_FULL;
1079 }
1080
Irfan Sheriffa2a1b912010-06-07 09:03:04 -07001081 /* Disable tethering when airplane mode is enabled */
Irfan Sheriff658772f2011-03-08 14:52:31 -08001082 if (mAirplaneModeOn.get()) {
Irfan Sheriff0d255342010-07-28 09:35:20 -07001083 mWifiStateMachine.setWifiApEnabled(null, false);
Irfan Sheriffa2a1b912010-06-07 09:03:04 -07001084 }
Irfan Sheriffb2e6c012010-04-05 11:57:56 -07001085
Irfan Sheriff658772f2011-03-08 14:52:31 -08001086 if (shouldWifiBeEnabled()) {
Irfan Sheriffa2a1b912010-06-07 09:03:04 -07001087 if (wifiShouldBeStarted) {
Dianne Hackborn03f3cb02010-09-17 23:12:26 -07001088 reportStartWorkSource();
Irfan Sheriff0d255342010-07-28 09:35:20 -07001089 mWifiStateMachine.setWifiEnabled(true);
1090 mWifiStateMachine.setScanOnlyMode(
Irfan Sheriffa2a1b912010-06-07 09:03:04 -07001091 strongestLockMode == WifiManager.WIFI_MODE_SCAN_ONLY);
Irfan Sheriff0d255342010-07-28 09:35:20 -07001092 mWifiStateMachine.setDriverStart(true);
Irfan Sheriff5876a422010-08-12 20:26:23 -07001093 mWifiStateMachine.setHighPerfModeEnabled(strongestLockMode
1094 == WifiManager.WIFI_MODE_FULL_HIGH_PERF);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001095 } else {
Irfan Sheriff0d255342010-07-28 09:35:20 -07001096 mWifiStateMachine.requestCmWakeLock();
1097 mWifiStateMachine.setDriverStart(false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001098 }
Irfan Sheriffa2a1b912010-06-07 09:03:04 -07001099 } else {
Irfan Sheriff0d255342010-07-28 09:35:20 -07001100 mWifiStateMachine.setWifiEnabled(false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001101 }
1102 }
1103
1104 private void registerForBroadcasts() {
1105 IntentFilter intentFilter = new IntentFilter();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001106 intentFilter.addAction(Intent.ACTION_SCREEN_ON);
1107 intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
1108 intentFilter.addAction(Intent.ACTION_BATTERY_CHANGED);
1109 intentFilter.addAction(ACTION_DEVICE_IDLE);
Irfan Sheriff65eaec82011-01-05 22:00:16 -08001110 intentFilter.addAction(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED);
Irfan Sheriff616f3172011-09-11 19:59:01 -07001111 intentFilter.addAction(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001112 mContext.registerReceiver(mReceiver, intentFilter);
1113 }
Jaikumar Ganesh084c6652009-12-07 10:58:18 -08001114
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001115 private boolean isAirplaneSensitive() {
1116 String airplaneModeRadios = Settings.System.getString(mContext.getContentResolver(),
1117 Settings.System.AIRPLANE_MODE_RADIOS);
1118 return airplaneModeRadios == null
1119 || airplaneModeRadios.contains(Settings.System.RADIO_WIFI);
1120 }
1121
Mike Lockwoodbd5ddf02009-07-29 21:37:14 -07001122 private boolean isAirplaneToggleable() {
1123 String toggleableRadios = Settings.System.getString(mContext.getContentResolver(),
1124 Settings.System.AIRPLANE_MODE_TOGGLEABLE_RADIOS);
1125 return toggleableRadios != null
1126 && toggleableRadios.contains(Settings.System.RADIO_WIFI);
1127 }
1128
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001129 /**
1130 * Returns true if Wi-Fi is sensitive to airplane mode, and airplane mode is
1131 * currently on.
1132 * @return {@code true} if airplane mode is on.
1133 */
1134 private boolean isAirplaneModeOn() {
1135 return isAirplaneSensitive() && Settings.System.getInt(mContext.getContentResolver(),
1136 Settings.System.AIRPLANE_MODE_ON, 0) == 1;
1137 }
1138
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001139 @Override
1140 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1141 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
1142 != PackageManager.PERMISSION_GRANTED) {
1143 pw.println("Permission Denial: can't dump WifiService from from pid="
1144 + Binder.getCallingPid()
1145 + ", uid=" + Binder.getCallingUid());
1146 return;
1147 }
Irfan Sheriffd8134ff2010-08-22 17:06:34 -07001148 pw.println("Wi-Fi is " + mWifiStateMachine.syncGetWifiStateByName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001149 pw.println("Stay-awake conditions: " +
1150 Settings.System.getInt(mContext.getContentResolver(),
1151 Settings.System.STAY_ON_WHILE_PLUGGED_IN, 0));
1152 pw.println();
1153
1154 pw.println("Internal state:");
Irfan Sheriff0d255342010-07-28 09:35:20 -07001155 pw.println(mWifiStateMachine);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001156 pw.println();
1157 pw.println("Latest scan results:");
Irfan Sheriffd8134ff2010-08-22 17:06:34 -07001158 List<ScanResult> scanResults = mWifiStateMachine.syncGetScanResultsList();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001159 if (scanResults != null && scanResults.size() != 0) {
1160 pw.println(" BSSID Frequency RSSI Flags SSID");
1161 for (ScanResult r : scanResults) {
1162 pw.printf(" %17s %9d %5d %-16s %s%n",
1163 r.BSSID,
1164 r.frequency,
1165 r.level,
1166 r.capabilities,
1167 r.SSID == null ? "" : r.SSID);
1168 }
1169 }
1170 pw.println();
Eric Shienbrood5711fad2009-03-27 20:25:31 -07001171 pw.println("Locks acquired: " + mFullLocksAcquired + " full, " +
Irfan Sheriff5876a422010-08-12 20:26:23 -07001172 mFullHighPerfLocksAcquired + " full high perf, " +
Eric Shienbrood5711fad2009-03-27 20:25:31 -07001173 mScanLocksAcquired + " scan");
1174 pw.println("Locks released: " + mFullLocksReleased + " full, " +
Irfan Sheriff5876a422010-08-12 20:26:23 -07001175 mFullHighPerfLocksReleased + " full high perf, " +
Eric Shienbrood5711fad2009-03-27 20:25:31 -07001176 mScanLocksReleased + " scan");
1177 pw.println();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001178 pw.println("Locks held:");
1179 mLocks.dump(pw);
Isaac Levybc7dfb52011-06-06 15:34:01 -07001180
1181 pw.println();
Isaac Levy654f5092011-07-13 17:41:45 -07001182 pw.println("WifiWatchdogStateMachine dump");
1183 mWifiWatchdogStateMachine.dump(pw);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001184 }
1185
Robert Greenwalt58ff0212009-05-19 15:53:54 -07001186 private class WifiLock extends DeathRecipient {
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001187 WifiLock(int lockMode, String tag, IBinder binder, WorkSource ws) {
1188 super(lockMode, tag, binder, ws);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001189 }
1190
1191 public void binderDied() {
1192 synchronized (mLocks) {
1193 releaseWifiLockLocked(mBinder);
1194 }
1195 }
1196
1197 public String toString() {
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001198 return "WifiLock{" + mTag + " type=" + mMode + " binder=" + mBinder + "}";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001199 }
1200 }
1201
1202 private class LockList {
1203 private List<WifiLock> mList;
1204
1205 private LockList() {
1206 mList = new ArrayList<WifiLock>();
1207 }
1208
1209 private synchronized boolean hasLocks() {
1210 return !mList.isEmpty();
1211 }
1212
1213 private synchronized int getStrongestLockMode() {
1214 if (mList.isEmpty()) {
1215 return WifiManager.WIFI_MODE_FULL;
1216 }
Irfan Sheriff5876a422010-08-12 20:26:23 -07001217
1218 if (mFullHighPerfLocksAcquired > mFullHighPerfLocksReleased) {
1219 return WifiManager.WIFI_MODE_FULL_HIGH_PERF;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001220 }
Irfan Sheriff5876a422010-08-12 20:26:23 -07001221
1222 if (mFullLocksAcquired > mFullLocksReleased) {
1223 return WifiManager.WIFI_MODE_FULL;
1224 }
1225
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001226 return WifiManager.WIFI_MODE_SCAN_ONLY;
1227 }
1228
1229 private void addLock(WifiLock lock) {
1230 if (findLockByBinder(lock.mBinder) < 0) {
1231 mList.add(lock);
1232 }
1233 }
1234
1235 private WifiLock removeLock(IBinder binder) {
1236 int index = findLockByBinder(binder);
1237 if (index >= 0) {
Suchi Amalapurapufff2fda2009-06-30 21:36:16 -07001238 WifiLock ret = mList.remove(index);
1239 ret.unlinkDeathRecipient();
1240 return ret;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001241 } else {
1242 return null;
1243 }
1244 }
1245
1246 private int findLockByBinder(IBinder binder) {
1247 int size = mList.size();
1248 for (int i = size - 1; i >= 0; i--)
1249 if (mList.get(i).mBinder == binder)
1250 return i;
1251 return -1;
1252 }
1253
1254 private void dump(PrintWriter pw) {
1255 for (WifiLock l : mList) {
1256 pw.print(" ");
1257 pw.println(l);
1258 }
1259 }
1260 }
1261
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001262 void enforceWakeSourcePermission(int uid, int pid) {
Dianne Hackborne746f032010-09-13 16:02:57 -07001263 if (uid == android.os.Process.myUid()) {
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001264 return;
1265 }
1266 mContext.enforcePermission(android.Manifest.permission.UPDATE_DEVICE_STATS,
1267 pid, uid, null);
1268 }
1269
1270 public boolean acquireWifiLock(IBinder binder, int lockMode, String tag, WorkSource ws) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001271 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WAKE_LOCK, null);
Irfan Sheriff5876a422010-08-12 20:26:23 -07001272 if (lockMode != WifiManager.WIFI_MODE_FULL &&
1273 lockMode != WifiManager.WIFI_MODE_SCAN_ONLY &&
1274 lockMode != WifiManager.WIFI_MODE_FULL_HIGH_PERF) {
1275 Slog.e(TAG, "Illegal argument, lockMode= " + lockMode);
1276 if (DBG) throw new IllegalArgumentException("lockMode=" + lockMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001277 return false;
1278 }
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001279 if (ws != null && ws.size() == 0) {
1280 ws = null;
1281 }
Dianne Hackbornecfd7f72010-10-08 14:23:40 -07001282 if (ws != null) {
1283 enforceWakeSourcePermission(Binder.getCallingUid(), Binder.getCallingPid());
1284 }
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001285 if (ws == null) {
1286 ws = new WorkSource(Binder.getCallingUid());
1287 }
1288 WifiLock wifiLock = new WifiLock(lockMode, tag, binder, ws);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001289 synchronized (mLocks) {
1290 return acquireWifiLockLocked(wifiLock);
1291 }
1292 }
1293
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001294 private void noteAcquireWifiLock(WifiLock wifiLock) throws RemoteException {
1295 switch(wifiLock.mMode) {
1296 case WifiManager.WIFI_MODE_FULL:
Irfan Sheriff5876a422010-08-12 20:26:23 -07001297 case WifiManager.WIFI_MODE_FULL_HIGH_PERF:
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001298 mBatteryStats.noteFullWifiLockAcquiredFromSource(wifiLock.mWorkSource);
1299 break;
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001300 case WifiManager.WIFI_MODE_SCAN_ONLY:
1301 mBatteryStats.noteScanWifiLockAcquiredFromSource(wifiLock.mWorkSource);
1302 break;
1303 }
1304 }
1305
1306 private void noteReleaseWifiLock(WifiLock wifiLock) throws RemoteException {
1307 switch(wifiLock.mMode) {
1308 case WifiManager.WIFI_MODE_FULL:
Irfan Sheriff5876a422010-08-12 20:26:23 -07001309 case WifiManager.WIFI_MODE_FULL_HIGH_PERF:
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001310 mBatteryStats.noteFullWifiLockReleasedFromSource(wifiLock.mWorkSource);
1311 break;
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001312 case WifiManager.WIFI_MODE_SCAN_ONLY:
1313 mBatteryStats.noteScanWifiLockReleasedFromSource(wifiLock.mWorkSource);
1314 break;
1315 }
1316 }
1317
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001318 private boolean acquireWifiLockLocked(WifiLock wifiLock) {
Irfan Sheriffc89dd542010-09-28 08:40:54 -07001319 if (DBG) Slog.d(TAG, "acquireWifiLockLocked: " + wifiLock);
Robert Greenwaltf1acb2d2009-10-13 08:20:55 -07001320
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001321 mLocks.addLock(wifiLock);
Robert Greenwaltf1acb2d2009-10-13 08:20:55 -07001322
The Android Open Source Project10592532009-03-18 17:39:46 -07001323 long ident = Binder.clearCallingIdentity();
1324 try {
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001325 noteAcquireWifiLock(wifiLock);
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001326 switch(wifiLock.mMode) {
Eric Shienbrood5711fad2009-03-27 20:25:31 -07001327 case WifiManager.WIFI_MODE_FULL:
1328 ++mFullLocksAcquired;
Eric Shienbrood5711fad2009-03-27 20:25:31 -07001329 break;
Irfan Sheriff5876a422010-08-12 20:26:23 -07001330 case WifiManager.WIFI_MODE_FULL_HIGH_PERF:
1331 ++mFullHighPerfLocksAcquired;
1332 break;
1333
Eric Shienbrood5711fad2009-03-27 20:25:31 -07001334 case WifiManager.WIFI_MODE_SCAN_ONLY:
1335 ++mScanLocksAcquired;
Eric Shienbrood5711fad2009-03-27 20:25:31 -07001336 break;
The Android Open Source Project10592532009-03-18 17:39:46 -07001337 }
Dianne Hackbornecfd7f72010-10-08 14:23:40 -07001338
1339 // Be aggressive about adding new locks into the accounted state...
1340 // we want to over-report rather than under-report.
1341 reportStartWorkSource();
1342
1343 updateWifiState();
1344 return true;
The Android Open Source Project10592532009-03-18 17:39:46 -07001345 } catch (RemoteException e) {
Dianne Hackbornecfd7f72010-10-08 14:23:40 -07001346 return false;
The Android Open Source Project10592532009-03-18 17:39:46 -07001347 } finally {
1348 Binder.restoreCallingIdentity(ident);
1349 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001350 }
1351
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001352 public void updateWifiLockWorkSource(IBinder lock, WorkSource ws) {
1353 int uid = Binder.getCallingUid();
1354 int pid = Binder.getCallingPid();
1355 if (ws != null && ws.size() == 0) {
1356 ws = null;
1357 }
1358 if (ws != null) {
1359 enforceWakeSourcePermission(uid, pid);
1360 }
1361 long ident = Binder.clearCallingIdentity();
1362 try {
1363 synchronized (mLocks) {
1364 int index = mLocks.findLockByBinder(lock);
1365 if (index < 0) {
1366 throw new IllegalArgumentException("Wifi lock not active");
1367 }
1368 WifiLock wl = mLocks.mList.get(index);
1369 noteReleaseWifiLock(wl);
1370 wl.mWorkSource = ws != null ? new WorkSource(ws) : new WorkSource(uid);
1371 noteAcquireWifiLock(wl);
1372 }
1373 } catch (RemoteException e) {
1374 } finally {
1375 Binder.restoreCallingIdentity(ident);
1376 }
1377 }
1378
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001379 public boolean releaseWifiLock(IBinder lock) {
1380 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WAKE_LOCK, null);
1381 synchronized (mLocks) {
1382 return releaseWifiLockLocked(lock);
1383 }
1384 }
1385
1386 private boolean releaseWifiLockLocked(IBinder lock) {
Eric Shienbroodd4c5f892009-03-24 18:13:20 -07001387 boolean hadLock;
Robert Greenwaltf1acb2d2009-10-13 08:20:55 -07001388
The Android Open Source Project10592532009-03-18 17:39:46 -07001389 WifiLock wifiLock = mLocks.removeLock(lock);
Robert Greenwaltf1acb2d2009-10-13 08:20:55 -07001390
Irfan Sheriffc89dd542010-09-28 08:40:54 -07001391 if (DBG) Slog.d(TAG, "releaseWifiLockLocked: " + wifiLock);
Robert Greenwaltf1acb2d2009-10-13 08:20:55 -07001392
Eric Shienbroodd4c5f892009-03-24 18:13:20 -07001393 hadLock = (wifiLock != null);
1394
Dianne Hackbornecfd7f72010-10-08 14:23:40 -07001395 long ident = Binder.clearCallingIdentity();
1396 try {
1397 if (hadLock) {
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001398 noteAcquireWifiLock(wifiLock);
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001399 switch(wifiLock.mMode) {
Eric Shienbrood5711fad2009-03-27 20:25:31 -07001400 case WifiManager.WIFI_MODE_FULL:
1401 ++mFullLocksReleased;
Eric Shienbrood5711fad2009-03-27 20:25:31 -07001402 break;
Irfan Sheriff5876a422010-08-12 20:26:23 -07001403 case WifiManager.WIFI_MODE_FULL_HIGH_PERF:
1404 ++mFullHighPerfLocksReleased;
1405 break;
Eric Shienbrood5711fad2009-03-27 20:25:31 -07001406 case WifiManager.WIFI_MODE_SCAN_ONLY:
1407 ++mScanLocksReleased;
Eric Shienbrood5711fad2009-03-27 20:25:31 -07001408 break;
Eric Shienbroodd4c5f892009-03-24 18:13:20 -07001409 }
The Android Open Source Project10592532009-03-18 17:39:46 -07001410 }
Dianne Hackbornecfd7f72010-10-08 14:23:40 -07001411
1412 // TODO - should this only happen if you hadLock?
1413 updateWifiState();
1414
1415 } catch (RemoteException e) {
1416 } finally {
1417 Binder.restoreCallingIdentity(ident);
The Android Open Source Project10592532009-03-18 17:39:46 -07001418 }
Dianne Hackbornecfd7f72010-10-08 14:23:40 -07001419
Eric Shienbroodd4c5f892009-03-24 18:13:20 -07001420 return hadLock;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001421 }
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001422
Robert Greenwalt58ff0212009-05-19 15:53:54 -07001423 private abstract class DeathRecipient
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001424 implements IBinder.DeathRecipient {
1425 String mTag;
1426 int mMode;
1427 IBinder mBinder;
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001428 WorkSource mWorkSource;
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001429
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001430 DeathRecipient(int mode, String tag, IBinder binder, WorkSource ws) {
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001431 super();
1432 mTag = tag;
1433 mMode = mode;
1434 mBinder = binder;
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001435 mWorkSource = ws;
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001436 try {
1437 mBinder.linkToDeath(this, 0);
1438 } catch (RemoteException e) {
1439 binderDied();
1440 }
1441 }
Suchi Amalapurapufff2fda2009-06-30 21:36:16 -07001442
1443 void unlinkDeathRecipient() {
1444 mBinder.unlinkToDeath(this, 0);
1445 }
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001446 }
1447
Robert Greenwalt58ff0212009-05-19 15:53:54 -07001448 private class Multicaster extends DeathRecipient {
1449 Multicaster(String tag, IBinder binder) {
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001450 super(Binder.getCallingUid(), tag, binder, null);
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001451 }
1452
1453 public void binderDied() {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001454 Slog.e(TAG, "Multicaster binderDied");
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001455 synchronized (mMulticasters) {
1456 int i = mMulticasters.indexOf(this);
1457 if (i != -1) {
1458 removeMulticasterLocked(i, mMode);
1459 }
1460 }
1461 }
1462
1463 public String toString() {
Robert Greenwalt58ff0212009-05-19 15:53:54 -07001464 return "Multicaster{" + mTag + " binder=" + mBinder + "}";
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001465 }
1466
1467 public int getUid() {
1468 return mMode;
1469 }
1470 }
1471
Robert Greenwalte2d155a2009-10-21 14:58:34 -07001472 public void initializeMulticastFiltering() {
1473 enforceMulticastChangePermission();
Irfan Sheriffa8fbe1f2010-03-09 09:13:58 -08001474
Robert Greenwalte2d155a2009-10-21 14:58:34 -07001475 synchronized (mMulticasters) {
1476 // if anybody had requested filters be off, leave off
1477 if (mMulticasters.size() != 0) {
1478 return;
1479 } else {
Irfan Sheriffb0c1b80f2011-07-19 15:44:25 -07001480 mWifiStateMachine.startFilteringMulticastV4Packets();
Robert Greenwalte2d155a2009-10-21 14:58:34 -07001481 }
1482 }
1483 }
1484
Robert Greenwaltfc1b15c2009-05-22 15:09:51 -07001485 public void acquireMulticastLock(IBinder binder, String tag) {
1486 enforceMulticastChangePermission();
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001487
1488 synchronized (mMulticasters) {
1489 mMulticastEnabled++;
Robert Greenwalt58ff0212009-05-19 15:53:54 -07001490 mMulticasters.add(new Multicaster(tag, binder));
Irfan Sheriffb0c1b80f2011-07-19 15:44:25 -07001491 // Note that we could call stopFilteringMulticastV4Packets only when
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001492 // our new size == 1 (first call), but this function won't
1493 // be called often and by making the stopPacket call each
1494 // time we're less fragile and self-healing.
Irfan Sheriffb0c1b80f2011-07-19 15:44:25 -07001495 mWifiStateMachine.stopFilteringMulticastV4Packets();
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001496 }
1497
1498 int uid = Binder.getCallingUid();
1499 Long ident = Binder.clearCallingIdentity();
1500 try {
1501 mBatteryStats.noteWifiMulticastEnabled(uid);
1502 } catch (RemoteException e) {
1503 } finally {
1504 Binder.restoreCallingIdentity(ident);
1505 }
1506 }
1507
Robert Greenwaltfc1b15c2009-05-22 15:09:51 -07001508 public void releaseMulticastLock() {
1509 enforceMulticastChangePermission();
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001510
1511 int uid = Binder.getCallingUid();
1512 synchronized (mMulticasters) {
1513 mMulticastDisabled++;
1514 int size = mMulticasters.size();
1515 for (int i = size - 1; i >= 0; i--) {
Robert Greenwalt58ff0212009-05-19 15:53:54 -07001516 Multicaster m = mMulticasters.get(i);
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001517 if ((m != null) && (m.getUid() == uid)) {
1518 removeMulticasterLocked(i, uid);
1519 }
1520 }
1521 }
1522 }
1523
1524 private void removeMulticasterLocked(int i, int uid)
1525 {
Suchi Amalapurapufff2fda2009-06-30 21:36:16 -07001526 Multicaster removed = mMulticasters.remove(i);
Irfan Sheriffa8fbe1f2010-03-09 09:13:58 -08001527
Suchi Amalapurapufff2fda2009-06-30 21:36:16 -07001528 if (removed != null) {
1529 removed.unlinkDeathRecipient();
1530 }
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001531 if (mMulticasters.size() == 0) {
Irfan Sheriffb0c1b80f2011-07-19 15:44:25 -07001532 mWifiStateMachine.startFilteringMulticastV4Packets();
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001533 }
1534
1535 Long ident = Binder.clearCallingIdentity();
1536 try {
1537 mBatteryStats.noteWifiMulticastDisabled(uid);
1538 } catch (RemoteException e) {
1539 } finally {
1540 Binder.restoreCallingIdentity(ident);
1541 }
1542 }
1543
Robert Greenwalt58ff0212009-05-19 15:53:54 -07001544 public boolean isMulticastEnabled() {
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001545 enforceAccessPermission();
1546
1547 synchronized (mMulticasters) {
1548 return (mMulticasters.size() > 0);
1549 }
1550 }
Irfan Sheriff0d255342010-07-28 09:35:20 -07001551
Irfan Sheriff227bec42011-02-15 19:30:27 -08001552 /**
1553 * Evaluate if traffic stats polling is needed based on
1554 * connection and screen on status
1555 */
1556 private void evaluateTrafficStatsPolling() {
1557 Message msg;
1558 if (mNetworkInfo.getDetailedState() == DetailedState.CONNECTED && !mScreenOff) {
Irfan Sheriffebe606f2011-02-24 11:39:15 -08001559 msg = Message.obtain(mAsyncServiceHandler,
1560 WifiManager.CMD_ENABLE_TRAFFIC_STATS_POLL, 1, 0);
Irfan Sheriff227bec42011-02-15 19:30:27 -08001561 } else {
Irfan Sheriffebe606f2011-02-24 11:39:15 -08001562 msg = Message.obtain(mAsyncServiceHandler,
1563 WifiManager.CMD_ENABLE_TRAFFIC_STATS_POLL, 0, 0);
Irfan Sheriff227bec42011-02-15 19:30:27 -08001564 }
1565 msg.sendToTarget();
1566 }
1567
1568 private void notifyOnDataActivity() {
1569 long sent, received;
1570 long preTxPkts = mTxPkts, preRxPkts = mRxPkts;
1571 int dataActivity = WifiManager.DATA_ACTIVITY_NONE;
1572
1573 mTxPkts = TrafficStats.getTxPackets(mInterfaceName);
1574 mRxPkts = TrafficStats.getRxPackets(mInterfaceName);
1575
1576 if (preTxPkts > 0 || preRxPkts > 0) {
1577 sent = mTxPkts - preTxPkts;
1578 received = mRxPkts - preRxPkts;
1579 if (sent > 0) {
1580 dataActivity |= WifiManager.DATA_ACTIVITY_OUT;
1581 }
1582 if (received > 0) {
1583 dataActivity |= WifiManager.DATA_ACTIVITY_IN;
1584 }
1585
1586 if (dataActivity != mDataActivity && !mScreenOff) {
1587 mDataActivity = dataActivity;
1588 for (AsyncChannel client : mClients) {
1589 client.sendMessage(WifiManager.DATA_ACTIVITY_NOTIFICATION, mDataActivity);
1590 }
1591 }
1592 }
1593 }
1594
1595
Irfan Sheriff0d255342010-07-28 09:35:20 -07001596 private void checkAndSetNotification() {
1597 // If we shouldn't place a notification on available networks, then
1598 // don't bother doing any of the following
1599 if (!mNotificationEnabled) return;
1600
1601 State state = mNetworkInfo.getState();
1602 if ((state == NetworkInfo.State.DISCONNECTED)
1603 || (state == NetworkInfo.State.UNKNOWN)) {
1604 // Look for an open network
Irfan Sheriffd8134ff2010-08-22 17:06:34 -07001605 List<ScanResult> scanResults = mWifiStateMachine.syncGetScanResultsList();
Irfan Sheriff0d255342010-07-28 09:35:20 -07001606 if (scanResults != null) {
1607 int numOpenNetworks = 0;
1608 for (int i = scanResults.size() - 1; i >= 0; i--) {
1609 ScanResult scanResult = scanResults.get(i);
1610
Irfan Sherifffdd5f952011-08-04 16:55:54 -07001611 //A capability of [ESS] represents an open access point
1612 //that is available for an STA to connect
1613 if (scanResult.capabilities != null &&
1614 scanResult.capabilities.equals("[ESS]")) {
Irfan Sheriff0d255342010-07-28 09:35:20 -07001615 numOpenNetworks++;
1616 }
1617 }
1618
1619 if (numOpenNetworks > 0) {
1620 if (++mNumScansSinceNetworkStateChange >= NUM_SCANS_BEFORE_ACTUALLY_SCANNING) {
1621 /*
1622 * We've scanned continuously at least
1623 * NUM_SCANS_BEFORE_NOTIFICATION times. The user
1624 * probably does not have a remembered network in range,
1625 * since otherwise supplicant would have tried to
1626 * associate and thus resetting this counter.
1627 */
1628 setNotificationVisible(true, numOpenNetworks, false, 0);
1629 }
1630 return;
1631 }
1632 }
1633 }
1634
1635 // No open networks in range, remove the notification
1636 setNotificationVisible(false, 0, false, 0);
1637 }
1638
1639 /**
1640 * Clears variables related to tracking whether a notification has been
1641 * shown recently and clears the current notification.
1642 */
1643 private void resetNotification() {
1644 mNotificationRepeatTime = 0;
1645 mNumScansSinceNetworkStateChange = 0;
1646 setNotificationVisible(false, 0, false, 0);
1647 }
1648
1649 /**
1650 * Display or don't display a notification that there are open Wi-Fi networks.
1651 * @param visible {@code true} if notification should be visible, {@code false} otherwise
1652 * @param numNetworks the number networks seen
1653 * @param force {@code true} to force notification to be shown/not-shown,
1654 * even if it is already shown/not-shown.
1655 * @param delay time in milliseconds after which the notification should be made
1656 * visible or invisible.
1657 */
1658 private void setNotificationVisible(boolean visible, int numNetworks, boolean force,
1659 int delay) {
1660
1661 // Since we use auto cancel on the notification, when the
1662 // mNetworksAvailableNotificationShown is true, the notification may
1663 // have actually been canceled. However, when it is false we know
1664 // for sure that it is not being shown (it will not be shown any other
1665 // place than here)
1666
1667 // If it should be hidden and it is already hidden, then noop
1668 if (!visible && !mNotificationShown && !force) {
1669 return;
1670 }
1671
1672 NotificationManager notificationManager = (NotificationManager) mContext
1673 .getSystemService(Context.NOTIFICATION_SERVICE);
1674
1675 Message message;
1676 if (visible) {
1677
1678 // Not enough time has passed to show the notification again
1679 if (System.currentTimeMillis() < mNotificationRepeatTime) {
1680 return;
1681 }
1682
1683 if (mNotification == null) {
Wink Savillec7a98342010-08-13 16:11:42 -07001684 // Cache the Notification object.
Irfan Sheriff0d255342010-07-28 09:35:20 -07001685 mNotification = new Notification();
1686 mNotification.when = 0;
1687 mNotification.icon = ICON_NETWORKS_AVAILABLE;
1688 mNotification.flags = Notification.FLAG_AUTO_CANCEL;
1689 mNotification.contentIntent = PendingIntent.getActivity(mContext, 0,
1690 new Intent(WifiManager.ACTION_PICK_WIFI_NETWORK), 0);
1691 }
1692
1693 CharSequence title = mContext.getResources().getQuantityText(
1694 com.android.internal.R.plurals.wifi_available, numNetworks);
1695 CharSequence details = mContext.getResources().getQuantityText(
1696 com.android.internal.R.plurals.wifi_available_detailed, numNetworks);
1697 mNotification.tickerText = title;
1698 mNotification.setLatestEventInfo(mContext, title, details, mNotification.contentIntent);
1699
1700 mNotificationRepeatTime = System.currentTimeMillis() + NOTIFICATION_REPEAT_DELAY_MS;
1701
1702 notificationManager.notify(ICON_NETWORKS_AVAILABLE, mNotification);
Irfan Sheriff0d255342010-07-28 09:35:20 -07001703 } else {
Irfan Sheriff0d255342010-07-28 09:35:20 -07001704 notificationManager.cancel(ICON_NETWORKS_AVAILABLE);
Irfan Sheriff0d255342010-07-28 09:35:20 -07001705 }
1706
Irfan Sheriff0d255342010-07-28 09:35:20 -07001707 mNotificationShown = visible;
1708 }
1709
1710 private class NotificationEnabledSettingObserver extends ContentObserver {
1711
1712 public NotificationEnabledSettingObserver(Handler handler) {
1713 super(handler);
1714 }
1715
1716 public void register() {
1717 ContentResolver cr = mContext.getContentResolver();
1718 cr.registerContentObserver(Settings.Secure.getUriFor(
1719 Settings.Secure.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON), true, this);
1720 mNotificationEnabled = getValue();
1721 }
1722
1723 @Override
1724 public void onChange(boolean selfChange) {
1725 super.onChange(selfChange);
1726
1727 mNotificationEnabled = getValue();
1728 resetNotification();
1729 }
1730
1731 private boolean getValue() {
1732 return Settings.Secure.getInt(mContext.getContentResolver(),
1733 Settings.Secure.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON, 1) == 1;
1734 }
1735 }
1736
1737
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001738}