blob: f9f63b1d1bd66ad9c2dc6546c8a1bf000377c8a5 [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 Sheriff02fb46a2010-12-08 11:27:37 -080040import android.net.wifi.WpsConfiguration;
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;
Wink Saville4b7ba092010-10-20 15:37:41 -070072import com.android.internal.util.AsyncChannel;
The Android Open Source Project10592532009-03-18 17:39:46 -070073import com.android.server.am.BatteryStatsService;
Irfan Sheriff9ab518ad2010-03-12 15:48:17 -080074import com.android.internal.R;
The Android Open Source Project10592532009-03-18 17:39:46 -070075
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080076/**
77 * WifiService handles remote WiFi operation requests by implementing
Irfan Sheriffa2a1b912010-06-07 09:03:04 -070078 * the IWifiManager interface.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080079 *
80 * @hide
81 */
Irfan Sheriffa2a1b912010-06-07 09:03:04 -070082//TODO: Clean up multiple locks and implement WifiService
83// as a SM to track soft AP/client/adhoc bring up based
84// on device idle state, airplane mode and boot.
85
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080086public class WifiService extends IWifiManager.Stub {
87 private static final String TAG = "WifiService";
Dianne Hackborn5fd21692011-06-07 14:09:47 -070088 private static final boolean DBG = false;
Irfan Sheriffa2a1b912010-06-07 09:03:04 -070089
Irfan Sheriff0d255342010-07-28 09:35:20 -070090 private final WifiStateMachine mWifiStateMachine;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080091
92 private Context mContext;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080093
94 private AlarmManager mAlarmManager;
95 private PendingIntent mIdleIntent;
96 private static final int IDLE_REQUEST = 0;
97 private boolean mScreenOff;
98 private boolean mDeviceIdle;
99 private int mPluggedType;
100
Irfan Sherifffcc08452011-02-17 16:44:54 -0800101 /* Chipset supports background scan */
102 private final boolean mBackgroundScanSupported;
103
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800104 private final LockList mLocks = new LockList();
Eric Shienbrood5711fad2009-03-27 20:25:31 -0700105 // some wifi lock statistics
Irfan Sheriff5876a422010-08-12 20:26:23 -0700106 private int mFullHighPerfLocksAcquired;
107 private int mFullHighPerfLocksReleased;
Eric Shienbrood5711fad2009-03-27 20:25:31 -0700108 private int mFullLocksAcquired;
109 private int mFullLocksReleased;
110 private int mScanLocksAcquired;
111 private int mScanLocksReleased;
The Android Open Source Project10592532009-03-18 17:39:46 -0700112
Robert Greenwalt58ff0212009-05-19 15:53:54 -0700113 private final List<Multicaster> mMulticasters =
114 new ArrayList<Multicaster>();
Robert Greenwalt5347bd42009-05-13 15:10:16 -0700115 private int mMulticastEnabled;
116 private int mMulticastDisabled;
117
The Android Open Source Project10592532009-03-18 17:39:46 -0700118 private final IBatteryStats mBatteryStats;
Jaikumar Ganesh084c6652009-12-07 10:58:18 -0800119
Irfan Sheriff227bec42011-02-15 19:30:27 -0800120 private boolean mEnableTrafficStatsPoll = false;
121 private int mTrafficStatsPollToken = 0;
122 private long mTxPkts;
123 private long mRxPkts;
124 /* Tracks last reported data activity */
125 private int mDataActivity;
126 private String mInterfaceName;
127
128 /**
129 * Interval in milliseconds between polling for traffic
130 * statistics
131 */
132 private static final int POLL_TRAFFIC_STATS_INTERVAL_MSECS = 1000;
133
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800134 /**
Doug Zongker43866e02010-01-07 12:09:54 -0800135 * See {@link Settings.Secure#WIFI_IDLE_MS}. This is the default value if a
136 * Settings.Secure value is not present. This timeout value is chosen as
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800137 * the approximate point at which the battery drain caused by Wi-Fi
138 * being enabled but not active exceeds the battery drain caused by
139 * re-establishing a connection to the mobile data network.
140 */
Irfan Sheriff4f5f7c92010-10-14 17:01:27 -0700141 private static final long DEFAULT_IDLE_MS = 15 * 60 * 1000; /* 15 minutes */
142
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800143 private static final String ACTION_DEVICE_IDLE =
144 "com.android.server.WifiManager.action.DEVICE_IDLE";
145
Irfan Sheriff658772f2011-03-08 14:52:31 -0800146 private static final int WIFI_DISABLED = 0;
147 private static final int WIFI_ENABLED = 1;
148 /* Wifi enabled while in airplane mode */
149 private static final int WIFI_ENABLED_AIRPLANE_OVERRIDE = 2;
150
151 private AtomicInteger mWifiState = new AtomicInteger(WIFI_DISABLED);
152 private AtomicBoolean mAirplaneModeOn = new AtomicBoolean(false);
153
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700154 private boolean mIsReceiverRegistered = false;
155
Irfan Sheriff0d255342010-07-28 09:35:20 -0700156
157 NetworkInfo mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_WIFI, 0, "WIFI", "");
158
159 // Variables relating to the 'available networks' notification
160 /**
161 * The icon to show in the 'available networks' notification. This will also
162 * be the ID of the Notification given to the NotificationManager.
163 */
164 private static final int ICON_NETWORKS_AVAILABLE =
165 com.android.internal.R.drawable.stat_notify_wifi_in_range;
166 /**
167 * When a notification is shown, we wait this amount before possibly showing it again.
168 */
169 private final long NOTIFICATION_REPEAT_DELAY_MS;
170 /**
171 * Whether the user has set the setting to show the 'available networks' notification.
172 */
173 private boolean mNotificationEnabled;
174 /**
175 * Observes the user setting to keep {@link #mNotificationEnabled} in sync.
176 */
177 private NotificationEnabledSettingObserver mNotificationEnabledSettingObserver;
178 /**
179 * The {@link System#currentTimeMillis()} must be at least this value for us
180 * to show the notification again.
181 */
182 private long mNotificationRepeatTime;
183 /**
184 * The Notification object given to the NotificationManager.
185 */
186 private Notification mNotification;
187 /**
188 * Whether the notification is being shown, as set by us. That is, if the
189 * user cancels the notification, we will not receive the callback so this
190 * will still be true. We only guarantee if this is false, then the
191 * notification is not showing.
192 */
193 private boolean mNotificationShown;
194 /**
195 * The number of continuous scans that must occur before consider the
196 * supplicant in a scanning state. This allows supplicant to associate with
197 * remembered networks that are in the scan results.
198 */
199 private static final int NUM_SCANS_BEFORE_ACTUALLY_SCANNING = 3;
200 /**
201 * The number of scans since the last network state change. When this
202 * exceeds {@link #NUM_SCANS_BEFORE_ACTUALLY_SCANNING}, we consider the
203 * supplicant to actually be scanning. When the network state changes to
204 * something other than scanning, we reset this to 0.
205 */
206 private int mNumScansSinceNetworkStateChange;
Jaikumar Ganesh7440fc22010-09-27 17:04:14 -0700207
Dianne Hackborn03f3cb02010-09-17 23:12:26 -0700208 /**
Wink Saville4b7ba092010-10-20 15:37:41 -0700209 * Asynchronous channel to WifiStateMachine
210 */
Irfan Sheriff227bec42011-02-15 19:30:27 -0800211 private AsyncChannel mWifiStateMachineChannel;
Wink Saville4b7ba092010-10-20 15:37:41 -0700212
213 /**
Irfan Sheriff227bec42011-02-15 19:30:27 -0800214 * Clients receiving asynchronous messages
Wink Saville4b7ba092010-10-20 15:37:41 -0700215 */
Irfan Sheriff227bec42011-02-15 19:30:27 -0800216 private List<AsyncChannel> mClients = new ArrayList<AsyncChannel>();
Wink Saville4b7ba092010-10-20 15:37:41 -0700217
Irfan Sheriff227bec42011-02-15 19:30:27 -0800218 /**
219 * Handles client connections
220 */
221 private class AsyncServiceHandler extends Handler {
222
223 AsyncServiceHandler(android.os.Looper looper) {
Wink Saville4b7ba092010-10-20 15:37:41 -0700224 super(looper);
Wink Saville4b7ba092010-10-20 15:37:41 -0700225 }
226
227 @Override
228 public void handleMessage(Message msg) {
229 switch (msg.what) {
230 case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: {
231 if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
Irfan Sheriff227bec42011-02-15 19:30:27 -0800232 Slog.d(TAG, "New client listening to asynchronous messages");
233 mClients.add((AsyncChannel) msg.obj);
Wink Saville4b7ba092010-10-20 15:37:41 -0700234 } else {
Irfan Sheriff227bec42011-02-15 19:30:27 -0800235 Slog.e(TAG, "Client connection failure, error=" + msg.arg1);
236 }
237 break;
238 }
Irfan Sheriffc23971b2011-03-04 17:06:31 -0800239 case AsyncChannel.CMD_CHANNEL_DISCONNECTED: {
240 if (msg.arg1 == AsyncChannel.STATUS_SEND_UNSUCCESSFUL) {
241 Slog.d(TAG, "Send failed, client connection lost");
242 } else {
243 Slog.d(TAG, "Client connection lost with reason: " + msg.arg1);
244 }
245 mClients.remove((AsyncChannel) msg.obj);
246 break;
247 }
Irfan Sheriff227bec42011-02-15 19:30:27 -0800248 case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION: {
249 AsyncChannel ac = new AsyncChannel();
250 ac.connect(mContext, this, msg.replyTo);
251 break;
252 }
Irfan Sheriffebe606f2011-02-24 11:39:15 -0800253 case WifiManager.CMD_ENABLE_TRAFFIC_STATS_POLL: {
Irfan Sheriff227bec42011-02-15 19:30:27 -0800254 mEnableTrafficStatsPoll = (msg.arg1 == 1);
255 mTrafficStatsPollToken++;
256 if (mEnableTrafficStatsPoll) {
257 notifyOnDataActivity();
Irfan Sheriffebe606f2011-02-24 11:39:15 -0800258 sendMessageDelayed(Message.obtain(this, WifiManager.CMD_TRAFFIC_STATS_POLL,
Irfan Sheriff227bec42011-02-15 19:30:27 -0800259 mTrafficStatsPollToken, 0), POLL_TRAFFIC_STATS_INTERVAL_MSECS);
260 }
261 break;
262 }
Irfan Sheriffebe606f2011-02-24 11:39:15 -0800263 case WifiManager.CMD_TRAFFIC_STATS_POLL: {
Irfan Sheriff227bec42011-02-15 19:30:27 -0800264 if (msg.arg1 == mTrafficStatsPollToken) {
265 notifyOnDataActivity();
Irfan Sheriffebe606f2011-02-24 11:39:15 -0800266 sendMessageDelayed(Message.obtain(this, WifiManager.CMD_TRAFFIC_STATS_POLL,
Irfan Sheriff227bec42011-02-15 19:30:27 -0800267 mTrafficStatsPollToken, 0), POLL_TRAFFIC_STATS_INTERVAL_MSECS);
Wink Saville4b7ba092010-10-20 15:37:41 -0700268 }
269 break;
270 }
Irfan Sheriffebe606f2011-02-24 11:39:15 -0800271 case WifiManager.CMD_CONNECT_NETWORK: {
272 if (msg.obj != null) {
273 mWifiStateMachine.connectNetwork((WifiConfiguration)msg.obj);
274 } else {
275 mWifiStateMachine.connectNetwork(msg.arg1);
276 }
277 break;
278 }
279 case WifiManager.CMD_SAVE_NETWORK: {
280 mWifiStateMachine.saveNetwork((WifiConfiguration)msg.obj);
281 break;
282 }
283 case WifiManager.CMD_FORGET_NETWORK: {
284 mWifiStateMachine.forgetNetwork(msg.arg1);
285 break;
286 }
287 case WifiManager.CMD_START_WPS: {
288 //replyTo has the original source
289 mWifiStateMachine.startWps(msg.replyTo, (WpsConfiguration)msg.obj);
290 break;
291 }
Wink Saville4b7ba092010-10-20 15:37:41 -0700292 default: {
293 Slog.d(TAG, "WifiServicehandler.handleMessage ignoring msg=" + msg);
294 break;
295 }
296 }
297 }
298 }
Irfan Sheriff227bec42011-02-15 19:30:27 -0800299 private AsyncServiceHandler mAsyncServiceHandler;
300
301 /**
302 * Handles interaction with WifiStateMachine
303 */
304 private class WifiStateMachineHandler extends Handler {
305 private AsyncChannel mWsmChannel;
306
307 WifiStateMachineHandler(android.os.Looper looper) {
308 super(looper);
309 mWsmChannel = new AsyncChannel();
310 mWsmChannel.connect(mContext, this, mWifiStateMachine.getHandler());
311 }
312
313 @Override
314 public void handleMessage(Message msg) {
315 switch (msg.what) {
316 case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: {
317 if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
318 mWifiStateMachineChannel = mWsmChannel;
319 } else {
320 Slog.e(TAG, "WifiStateMachine connection failure, error=" + msg.arg1);
321 mWifiStateMachineChannel = null;
322 }
323 break;
324 }
Irfan Sheriff6da83d52011-06-06 12:54:06 -0700325 case AsyncChannel.CMD_CHANNEL_DISCONNECTED: {
326 Slog.e(TAG, "WifiStateMachine channel lost, msg.arg1 =" + msg.arg1);
327 mWifiStateMachineChannel = null;
328 //Re-establish connection to state machine
329 mWsmChannel.connect(mContext, this, mWifiStateMachine.getHandler());
330 break;
331 }
Irfan Sheriff227bec42011-02-15 19:30:27 -0800332 default: {
333 Slog.d(TAG, "WifiStateMachineHandler.handleMessage ignoring msg=" + msg);
334 break;
335 }
336 }
337 }
338 }
339 WifiStateMachineHandler mWifiStateMachineHandler;
Wink Saville4b7ba092010-10-20 15:37:41 -0700340
341 /**
Dianne Hackborn03f3cb02010-09-17 23:12:26 -0700342 * Temporary for computing UIDS that are responsible for starting WIFI.
343 * Protected by mWifiStateTracker lock.
344 */
345 private final WorkSource mTmpWorkSource = new WorkSource();
Isaac Levy654f5092011-07-13 17:41:45 -0700346 private WifiWatchdogStateMachine mWifiWatchdogStateMachine;
Irfan Sheriff0d255342010-07-28 09:35:20 -0700347
348 WifiService(Context context) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800349 mContext = context;
Irfan Sheriff227bec42011-02-15 19:30:27 -0800350
351 mInterfaceName = SystemProperties.get("wifi.interface", "wlan0");
352
353 mWifiStateMachine = new WifiStateMachine(mContext, mInterfaceName);
Irfan Sheriff0d255342010-07-28 09:35:20 -0700354 mWifiStateMachine.enableRssiPolling(true);
The Android Open Source Project10592532009-03-18 17:39:46 -0700355 mBatteryStats = BatteryStatsService.getService();
Jaikumar Ganesh084c6652009-12-07 10:58:18 -0800356
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800357 mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
358 Intent idleIntent = new Intent(ACTION_DEVICE_IDLE, null);
359 mIdleIntent = PendingIntent.getBroadcast(mContext, IDLE_REQUEST, idleIntent, 0);
360
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800361 mContext.registerReceiver(
362 new BroadcastReceiver() {
363 @Override
364 public void onReceive(Context context, Intent intent) {
Irfan Sheriff658772f2011-03-08 14:52:31 -0800365 mAirplaneModeOn.set(isAirplaneModeOn());
366 /* On airplane mode disable, restore wifi state if necessary */
367 if (!mAirplaneModeOn.get() && (testAndClearWifiSavedState() ||
368 mWifiState.get() == WIFI_ENABLED_AIRPLANE_OVERRIDE)) {
369 persistWifiEnabled(true);
Irfan Sheriffb2e6c012010-04-05 11:57:56 -0700370 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800371 updateWifiState();
372 }
373 },
374 new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED));
375
Irfan Sheriff0d255342010-07-28 09:35:20 -0700376 IntentFilter filter = new IntentFilter();
377 filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
378 filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
379 filter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
380
381 mContext.registerReceiver(
382 new BroadcastReceiver() {
383 @Override
384 public void onReceive(Context context, Intent intent) {
385 if (intent.getAction().equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) {
386 // reset & clear notification on any wifi state change
387 resetNotification();
388 } else if (intent.getAction().equals(
389 WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
390 mNetworkInfo = (NetworkInfo) intent.getParcelableExtra(
391 WifiManager.EXTRA_NETWORK_INFO);
392 // reset & clear notification on a network connect & disconnect
393 switch(mNetworkInfo.getDetailedState()) {
394 case CONNECTED:
395 case DISCONNECTED:
Irfan Sheriff227bec42011-02-15 19:30:27 -0800396 evaluateTrafficStatsPolling();
Irfan Sheriff0d255342010-07-28 09:35:20 -0700397 resetNotification();
398 break;
399 }
400 } else if (intent.getAction().equals(
401 WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) {
402 checkAndSetNotification();
403 }
404 }
405 }, filter);
406
Irfan Sheriff227bec42011-02-15 19:30:27 -0800407 HandlerThread wifiThread = new HandlerThread("WifiService");
408 wifiThread.start();
409 mAsyncServiceHandler = new AsyncServiceHandler(wifiThread.getLooper());
410 mWifiStateMachineHandler = new WifiStateMachineHandler(wifiThread.getLooper());
411
Irfan Sheriff0d255342010-07-28 09:35:20 -0700412 // Setting is in seconds
413 NOTIFICATION_REPEAT_DELAY_MS = Settings.Secure.getInt(context.getContentResolver(),
414 Settings.Secure.WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY, 900) * 1000l;
415 mNotificationEnabledSettingObserver = new NotificationEnabledSettingObserver(new Handler());
416 mNotificationEnabledSettingObserver.register();
Irfan Sherifffcc08452011-02-17 16:44:54 -0800417
418 mBackgroundScanSupported = mContext.getResources().getBoolean(
419 com.android.internal.R.bool.config_wifi_background_scan_support);
Irfan Sheriff7b009782010-03-11 16:37:45 -0800420 }
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800421
Irfan Sheriff7b009782010-03-11 16:37:45 -0800422 /**
423 * Check if Wi-Fi needs to be enabled and start
424 * if needed
Irfan Sheriff60e3ba02010-04-02 12:18:45 -0700425 *
426 * This function is used only at boot time
Irfan Sheriff7b009782010-03-11 16:37:45 -0800427 */
Irfan Sheriff0d255342010-07-28 09:35:20 -0700428 public void checkAndStartWifi() {
Irfan Sheriff658772f2011-03-08 14:52:31 -0800429 mAirplaneModeOn.set(isAirplaneModeOn());
430 mWifiState.set(getPersistedWifiState());
431 /* Start if Wi-Fi should be enabled or the saved state indicates Wi-Fi was on */
432 boolean wifiEnabled = shouldWifiBeEnabled() || testAndClearWifiSavedState();
Irfan Sheriff7b009782010-03-11 16:37:45 -0800433 Slog.i(TAG, "WifiService starting up with Wi-Fi " +
434 (wifiEnabled ? "enabled" : "disabled"));
Irfan Sheriffb99fe5e2010-03-26 14:56:07 -0700435 setWifiEnabled(wifiEnabled);
Isaac Levybc7dfb52011-06-06 15:34:01 -0700436
Isaac Levy654f5092011-07-13 17:41:45 -0700437 mWifiWatchdogStateMachine = WifiWatchdogStateMachine.
438 makeWifiWatchdogStateMachine(mContext);
439
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800440 }
441
Irfan Sheriffa3bd4092010-03-24 17:58:59 -0700442 private boolean testAndClearWifiSavedState() {
443 final ContentResolver cr = mContext.getContentResolver();
444 int wifiSavedState = 0;
445 try {
446 wifiSavedState = Settings.Secure.getInt(cr, Settings.Secure.WIFI_SAVED_STATE);
447 if(wifiSavedState == 1)
448 Settings.Secure.putInt(cr, Settings.Secure.WIFI_SAVED_STATE, 0);
449 } catch (Settings.SettingNotFoundException e) {
450 ;
451 }
452 return (wifiSavedState == 1);
453 }
454
Irfan Sheriff658772f2011-03-08 14:52:31 -0800455 private int getPersistedWifiState() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800456 final ContentResolver cr = mContext.getContentResolver();
457 try {
Irfan Sheriff658772f2011-03-08 14:52:31 -0800458 return Settings.Secure.getInt(cr, Settings.Secure.WIFI_ON);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800459 } catch (Settings.SettingNotFoundException e) {
Irfan Sheriff658772f2011-03-08 14:52:31 -0800460 Settings.Secure.putInt(cr, Settings.Secure.WIFI_ON, WIFI_DISABLED);
461 return WIFI_DISABLED;
462 }
463 }
464
465 private boolean shouldWifiBeEnabled() {
466 if (mAirplaneModeOn.get()) {
467 return mWifiState.get() == WIFI_ENABLED_AIRPLANE_OVERRIDE;
468 } else {
469 return mWifiState.get() != WIFI_DISABLED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800470 }
471 }
472
473 private void persistWifiEnabled(boolean enabled) {
474 final ContentResolver cr = mContext.getContentResolver();
Irfan Sheriff658772f2011-03-08 14:52:31 -0800475 if (enabled) {
476 if (isAirplaneModeOn() && isAirplaneToggleable()) {
477 mWifiState.set(WIFI_ENABLED_AIRPLANE_OVERRIDE);
478 } else {
479 mWifiState.set(WIFI_ENABLED);
480 }
481 } else {
482 mWifiState.set(WIFI_DISABLED);
483 }
484 Settings.Secure.putInt(cr, Settings.Secure.WIFI_ON, mWifiState.get());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800485 }
486
Irfan Sheriff658772f2011-03-08 14:52:31 -0800487
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800488 /**
489 * see {@link android.net.wifi.WifiManager#pingSupplicant()}
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700490 * @return {@code true} if the operation succeeds, {@code false} otherwise
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800491 */
492 public boolean pingSupplicant() {
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700493 enforceAccessPermission();
Irfan Sheriff227bec42011-02-15 19:30:27 -0800494 if (mWifiStateMachineChannel != null) {
495 return mWifiStateMachine.syncPingSupplicant(mWifiStateMachineChannel);
Irfan Sheriff1406bcb2010-10-28 14:41:39 -0700496 } else {
Irfan Sheriff227bec42011-02-15 19:30:27 -0800497 Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
Irfan Sheriff1406bcb2010-10-28 14:41:39 -0700498 return false;
499 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800500 }
501
502 /**
503 * see {@link android.net.wifi.WifiManager#startScan()}
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800504 */
Irfan Sheriffe4984752010-08-19 11:29:22 -0700505 public void startScan(boolean forceActive) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800506 enforceChangePermission();
Irfan Sheriffe4984752010-08-19 11:29:22 -0700507 mWifiStateMachine.startScan(forceActive);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800508 }
509
510 private void enforceAccessPermission() {
511 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_WIFI_STATE,
512 "WifiService");
513 }
514
515 private void enforceChangePermission() {
516 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CHANGE_WIFI_STATE,
517 "WifiService");
518
519 }
520
Robert Greenwaltfc1b15c2009-05-22 15:09:51 -0700521 private void enforceMulticastChangePermission() {
522 mContext.enforceCallingOrSelfPermission(
523 android.Manifest.permission.CHANGE_WIFI_MULTICAST_STATE,
524 "WifiService");
525 }
526
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800527 /**
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700528 * see {@link android.net.wifi.WifiManager#setWifiEnabled(boolean)}
529 * @param enable {@code true} to enable, {@code false} to disable.
530 * @return {@code true} if the enable/disable operation was
531 * started or is already in the queue.
532 */
533 public synchronized boolean setWifiEnabled(boolean enable) {
534 enforceChangePermission();
535
536 if (DBG) {
Irfan Sheriff0d255342010-07-28 09:35:20 -0700537 Slog.e(TAG, "Invoking mWifiStateMachine.setWifiEnabled\n");
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700538 }
539
Dianne Hackborn03f3cb02010-09-17 23:12:26 -0700540 if (enable) {
541 reportStartWorkSource();
542 }
Irfan Sheriff0d255342010-07-28 09:35:20 -0700543 mWifiStateMachine.setWifiEnabled(enable);
Irfan Sheriff61180692010-08-18 16:07:39 -0700544
545 /*
546 * Caller might not have WRITE_SECURE_SETTINGS,
547 * only CHANGE_WIFI_STATE is enforced
548 */
549 long ident = Binder.clearCallingIdentity();
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700550 persistWifiEnabled(enable);
Irfan Sheriff61180692010-08-18 16:07:39 -0700551 Binder.restoreCallingIdentity(ident);
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700552
553 if (enable) {
554 if (!mIsReceiverRegistered) {
555 registerForBroadcasts();
556 mIsReceiverRegistered = true;
557 }
558 } else if (mIsReceiverRegistered){
559 mContext.unregisterReceiver(mReceiver);
560 mIsReceiverRegistered = false;
561 }
562
563 return true;
564 }
565
566 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800567 * see {@link WifiManager#getWifiState()}
568 * @return One of {@link WifiManager#WIFI_STATE_DISABLED},
569 * {@link WifiManager#WIFI_STATE_DISABLING},
570 * {@link WifiManager#WIFI_STATE_ENABLED},
571 * {@link WifiManager#WIFI_STATE_ENABLING},
572 * {@link WifiManager#WIFI_STATE_UNKNOWN}
573 */
574 public int getWifiEnabledState() {
575 enforceAccessPermission();
Irfan Sheriffd8134ff2010-08-22 17:06:34 -0700576 return mWifiStateMachine.syncGetWifiState();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800577 }
578
579 /**
Irfan Sheriffc2f54c22010-03-18 14:02:22 -0700580 * see {@link android.net.wifi.WifiManager#setWifiApEnabled(WifiConfiguration, boolean)}
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800581 * @param wifiConfig SSID, security and channel details as
582 * part of WifiConfiguration
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700583 * @param enabled true to enable and false to disable
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800584 */
Irfan Sheriffffcea7a2011-05-10 16:26:06 -0700585 public void setWifiApEnabled(WifiConfiguration wifiConfig, boolean enabled) {
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800586 enforceChangePermission();
Irfan Sheriff0d255342010-07-28 09:35:20 -0700587 mWifiStateMachine.setWifiApEnabled(wifiConfig, enabled);
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800588 }
589
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700590 /**
591 * see {@link WifiManager#getWifiApState()}
592 * @return One of {@link WifiManager#WIFI_AP_STATE_DISABLED},
593 * {@link WifiManager#WIFI_AP_STATE_DISABLING},
594 * {@link WifiManager#WIFI_AP_STATE_ENABLED},
595 * {@link WifiManager#WIFI_AP_STATE_ENABLING},
596 * {@link WifiManager#WIFI_AP_STATE_FAILED}
597 */
598 public int getWifiApEnabledState() {
Irfan Sheriff17b232b2010-06-24 11:32:26 -0700599 enforceAccessPermission();
Irfan Sheriffd8134ff2010-08-22 17:06:34 -0700600 return mWifiStateMachine.syncGetWifiApState();
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700601 }
602
603 /**
604 * see {@link WifiManager#getWifiApConfiguration()}
605 * @return soft access point configuration
606 */
Irfan Sheriffffcea7a2011-05-10 16:26:06 -0700607 public WifiConfiguration getWifiApConfiguration() {
608 enforceAccessPermission();
Irfan Sheriff6da83d52011-06-06 12:54:06 -0700609 if (mWifiStateMachineChannel != null) {
610 return mWifiStateMachine.syncGetWifiApConfiguration(mWifiStateMachineChannel);
611 } else {
612 Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
613 return null;
614 }
Irfan Sheriff9ab518ad2010-03-12 15:48:17 -0800615 }
616
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700617 /**
618 * see {@link WifiManager#setWifiApConfiguration(WifiConfiguration)}
619 * @param wifiConfig WifiConfiguration details for soft access point
620 */
Irfan Sheriffffcea7a2011-05-10 16:26:06 -0700621 public void setWifiApConfiguration(WifiConfiguration wifiConfig) {
Irfan Sheriff17b232b2010-06-24 11:32:26 -0700622 enforceChangePermission();
Irfan Sheriff9ab518ad2010-03-12 15:48:17 -0800623 if (wifiConfig == null)
624 return;
Irfan Sheriffffcea7a2011-05-10 16:26:06 -0700625 mWifiStateMachine.setWifiApConfiguration(wifiConfig);
Irfan Sheriff9ab518ad2010-03-12 15:48:17 -0800626 }
627
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800628 /**
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700629 * see {@link android.net.wifi.WifiManager#disconnect()}
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800630 */
Irfan Sheriffe4984752010-08-19 11:29:22 -0700631 public void disconnect() {
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700632 enforceChangePermission();
Irfan Sheriffe4984752010-08-19 11:29:22 -0700633 mWifiStateMachine.disconnectCommand();
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800634 }
635
636 /**
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700637 * see {@link android.net.wifi.WifiManager#reconnect()}
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800638 */
Irfan Sheriffe4984752010-08-19 11:29:22 -0700639 public void reconnect() {
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700640 enforceChangePermission();
Irfan Sheriffe4984752010-08-19 11:29:22 -0700641 mWifiStateMachine.reconnectCommand();
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800642 }
643
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700644 /**
645 * see {@link android.net.wifi.WifiManager#reassociate()}
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700646 */
Irfan Sheriffe4984752010-08-19 11:29:22 -0700647 public void reassociate() {
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700648 enforceChangePermission();
Irfan Sheriffe4984752010-08-19 11:29:22 -0700649 mWifiStateMachine.reassociateCommand();
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800650 }
651
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800652 /**
653 * see {@link android.net.wifi.WifiManager#getConfiguredNetworks()}
654 * @return the list of configured networks
655 */
656 public List<WifiConfiguration> getConfiguredNetworks() {
657 enforceAccessPermission();
Irfan Sheriffd8134ff2010-08-22 17:06:34 -0700658 return mWifiStateMachine.syncGetConfiguredNetworks();
Chung-yih Wanga8d15942009-10-09 11:01:49 +0800659 }
660
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800661 /**
662 * see {@link android.net.wifi.WifiManager#addOrUpdateNetwork(WifiConfiguration)}
663 * @return the supplicant-assigned identifier for the new or updated
664 * network if the operation succeeds, or {@code -1} if it fails
665 */
Irfan Sheriff7aac5542009-12-22 21:42:17 -0800666 public int addOrUpdateNetwork(WifiConfiguration config) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800667 enforceChangePermission();
Irfan Sheriff227bec42011-02-15 19:30:27 -0800668 if (mWifiStateMachineChannel != null) {
669 return mWifiStateMachine.syncAddOrUpdateNetwork(mWifiStateMachineChannel, config);
Irfan Sheriff1406bcb2010-10-28 14:41:39 -0700670 } else {
Irfan Sheriff227bec42011-02-15 19:30:27 -0800671 Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
Irfan Sheriff1406bcb2010-10-28 14:41:39 -0700672 return -1;
673 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800674 }
675
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700676 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800677 * See {@link android.net.wifi.WifiManager#removeNetwork(int)}
678 * @param netId the integer that identifies the network configuration
679 * to the supplicant
680 * @return {@code true} if the operation succeeded
681 */
682 public boolean removeNetwork(int netId) {
683 enforceChangePermission();
Irfan Sheriff227bec42011-02-15 19:30:27 -0800684 if (mWifiStateMachineChannel != null) {
685 return mWifiStateMachine.syncRemoveNetwork(mWifiStateMachineChannel, netId);
Wink Saville4b7ba092010-10-20 15:37:41 -0700686 } else {
Irfan Sheriff227bec42011-02-15 19:30:27 -0800687 Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
Wink Saville4b7ba092010-10-20 15:37:41 -0700688 return false;
689 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800690 }
691
692 /**
693 * See {@link android.net.wifi.WifiManager#enableNetwork(int, boolean)}
694 * @param netId the integer that identifies the network configuration
695 * to the supplicant
696 * @param disableOthers if true, disable all other networks.
697 * @return {@code true} if the operation succeeded
698 */
699 public boolean enableNetwork(int netId, boolean disableOthers) {
700 enforceChangePermission();
Irfan Sheriff227bec42011-02-15 19:30:27 -0800701 if (mWifiStateMachineChannel != null) {
702 return mWifiStateMachine.syncEnableNetwork(mWifiStateMachineChannel, netId,
703 disableOthers);
Irfan Sheriff1406bcb2010-10-28 14:41:39 -0700704 } else {
Irfan Sheriff227bec42011-02-15 19:30:27 -0800705 Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
Irfan Sheriff1406bcb2010-10-28 14:41:39 -0700706 return false;
707 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800708 }
709
710 /**
711 * See {@link android.net.wifi.WifiManager#disableNetwork(int)}
712 * @param netId the integer that identifies the network configuration
713 * to the supplicant
714 * @return {@code true} if the operation succeeded
715 */
716 public boolean disableNetwork(int netId) {
717 enforceChangePermission();
Irfan Sheriff227bec42011-02-15 19:30:27 -0800718 if (mWifiStateMachineChannel != null) {
719 return mWifiStateMachine.syncDisableNetwork(mWifiStateMachineChannel, netId);
Irfan Sheriff1406bcb2010-10-28 14:41:39 -0700720 } else {
Irfan Sheriff227bec42011-02-15 19:30:27 -0800721 Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
Irfan Sheriff1406bcb2010-10-28 14:41:39 -0700722 return false;
723 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800724 }
725
726 /**
727 * See {@link android.net.wifi.WifiManager#getConnectionInfo()}
728 * @return the Wi-Fi information, contained in {@link WifiInfo}.
729 */
730 public WifiInfo getConnectionInfo() {
731 enforceAccessPermission();
732 /*
733 * Make sure we have the latest information, by sending
734 * a status request to the supplicant.
735 */
Irfan Sheriffd8134ff2010-08-22 17:06:34 -0700736 return mWifiStateMachine.syncRequestConnectionInfo();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800737 }
738
739 /**
740 * Return the results of the most recent access point scan, in the form of
741 * a list of {@link ScanResult} objects.
742 * @return the list of results
743 */
744 public List<ScanResult> getScanResults() {
745 enforceAccessPermission();
Irfan Sheriffd8134ff2010-08-22 17:06:34 -0700746 return mWifiStateMachine.syncGetScanResultsList();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800747 }
748
749 /**
750 * Tell the supplicant to persist the current list of configured networks.
751 * @return {@code true} if the operation succeeded
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700752 *
753 * TODO: deprecate this
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800754 */
755 public boolean saveConfiguration() {
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700756 boolean result = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800757 enforceChangePermission();
Irfan Sheriff227bec42011-02-15 19:30:27 -0800758 if (mWifiStateMachineChannel != null) {
759 return mWifiStateMachine.syncSaveConfig(mWifiStateMachineChannel);
Irfan Sheriff1406bcb2010-10-28 14:41:39 -0700760 } else {
Irfan Sheriff227bec42011-02-15 19:30:27 -0800761 Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
Irfan Sheriff1406bcb2010-10-28 14:41:39 -0700762 return false;
763 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800764 }
765
766 /**
Irfan Sheriffed4f28b2010-10-29 15:32:10 -0700767 * Set the country code
768 * @param countryCode ISO 3166 country code.
Robert Greenwaltb5010cc2009-05-21 15:11:40 -0700769 * @param persist {@code true} if the setting should be remembered.
Irfan Sheriffed4f28b2010-10-29 15:32:10 -0700770 *
771 * The persist behavior exists so that wifi can fall back to the last
772 * persisted country code on a restart, when the locale information is
773 * not available from telephony.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800774 */
Irfan Sheriffed4f28b2010-10-29 15:32:10 -0700775 public void setCountryCode(String countryCode, boolean persist) {
776 Slog.i(TAG, "WifiService trying to set country code to " + countryCode +
777 " with persist set to " + persist);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800778 enforceChangePermission();
Irfan Sheriffed4f28b2010-10-29 15:32:10 -0700779 mWifiStateMachine.setCountryCode(countryCode, persist);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800780 }
781
782 /**
Irfan Sheriff36f74132010-11-04 16:57:37 -0700783 * Set the operational frequency band
784 * @param band One of
785 * {@link WifiManager#WIFI_FREQUENCY_BAND_AUTO},
786 * {@link WifiManager#WIFI_FREQUENCY_BAND_5GHZ},
787 * {@link WifiManager#WIFI_FREQUENCY_BAND_2GHZ},
788 * @param persist {@code true} if the setting should be remembered.
789 *
790 */
791 public void setFrequencyBand(int band, boolean persist) {
792 enforceChangePermission();
793 if (!isDualBandSupported()) return;
794 Slog.i(TAG, "WifiService trying to set frequency band to " + band +
795 " with persist set to " + persist);
796 mWifiStateMachine.setFrequencyBand(band, persist);
797 }
798
799
800 /**
801 * Get the operational frequency band
802 */
803 public int getFrequencyBand() {
804 enforceAccessPermission();
805 return mWifiStateMachine.getFrequencyBand();
806 }
807
808 public boolean isDualBandSupported() {
809 //TODO: Should move towards adding a driver API that checks at runtime
810 return mContext.getResources().getBoolean(
811 com.android.internal.R.bool.config_wifi_dual_band_support);
812 }
813
814 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800815 * Return the DHCP-assigned addresses from the last successful DHCP request,
816 * if any.
817 * @return the DHCP information
818 */
819 public DhcpInfo getDhcpInfo() {
820 enforceAccessPermission();
Irfan Sheriffd8134ff2010-08-22 17:06:34 -0700821 return mWifiStateMachine.syncGetDhcpInfo();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800822 }
823
Irfan Sheriff0d255342010-07-28 09:35:20 -0700824 /**
825 * see {@link android.net.wifi.WifiManager#startWifi}
826 *
827 */
828 public void startWifi() {
829 enforceChangePermission();
830 /* TODO: may be add permissions for access only to connectivity service
831 * TODO: if a start issued, keep wifi alive until a stop issued irrespective
832 * of WifiLock & device idle status unless wifi enabled status is toggled
833 */
834
835 mWifiStateMachine.setDriverStart(true);
836 mWifiStateMachine.reconnectCommand();
837 }
838
839 /**
840 * see {@link android.net.wifi.WifiManager#stopWifi}
841 *
842 */
843 public void stopWifi() {
844 enforceChangePermission();
845 /* TODO: may be add permissions for access only to connectivity service
846 * TODO: if a stop is issued, wifi is brought up only by startWifi
847 * unless wifi enabled status is toggled
848 */
849 mWifiStateMachine.setDriverStart(false);
850 }
851
852
853 /**
854 * see {@link android.net.wifi.WifiManager#addToBlacklist}
855 *
856 */
857 public void addToBlacklist(String bssid) {
858 enforceChangePermission();
859
860 mWifiStateMachine.addToBlacklist(bssid);
861 }
862
863 /**
864 * see {@link android.net.wifi.WifiManager#clearBlacklist}
865 *
866 */
867 public void clearBlacklist() {
868 enforceChangePermission();
869
870 mWifiStateMachine.clearBlacklist();
871 }
872
Irfan Sheriff227bec42011-02-15 19:30:27 -0800873 /**
874 * Get a reference to handler. This is used by a client to establish
875 * an AsyncChannel communication with WifiService
876 */
877 public Messenger getMessenger() {
Irfan Sheriffebe606f2011-02-24 11:39:15 -0800878 /* Enforce the highest permissions
879 TODO: when we consider exposing the asynchronous API, think about
880 how to provide both access and change permissions seperately
881 */
Irfan Sheriff227bec42011-02-15 19:30:27 -0800882 enforceAccessPermission();
Irfan Sheriffebe606f2011-02-24 11:39:15 -0800883 enforceChangePermission();
Irfan Sheriff227bec42011-02-15 19:30:27 -0800884 return new Messenger(mAsyncServiceHandler);
885 }
886
Irfan Sheriff4aeca7c52011-03-10 16:53:33 -0800887 /**
888 * Get the IP and proxy configuration file
889 */
890 public String getConfigFile() {
891 enforceAccessPermission();
892 return mWifiStateMachine.getConfigFile();
893 }
894
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800895 private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
896 @Override
897 public void onReceive(Context context, Intent intent) {
898 String action = intent.getAction();
899
Doug Zongker43866e02010-01-07 12:09:54 -0800900 long idleMillis =
901 Settings.Secure.getLong(mContext.getContentResolver(),
Irfan Sheriff4f5f7c92010-10-14 17:01:27 -0700902 Settings.Secure.WIFI_IDLE_MS, DEFAULT_IDLE_MS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800903 int stayAwakeConditions =
Doug Zongker43866e02010-01-07 12:09:54 -0800904 Settings.System.getInt(mContext.getContentResolver(),
905 Settings.System.STAY_ON_WHILE_PLUGGED_IN, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800906 if (action.equals(Intent.ACTION_SCREEN_ON)) {
Joe Onorato431bb222010-10-18 19:13:23 -0400907 if (DBG) {
908 Slog.d(TAG, "ACTION_SCREEN_ON");
909 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800910 mAlarmManager.cancel(mIdleIntent);
911 mDeviceIdle = false;
912 mScreenOff = false;
Dianne Hackborn58e0eef2010-09-16 01:22:10 -0700913 // Once the screen is on, we are not keeping WIFI running
914 // because of any locks so clear that tracking immediately.
915 reportStartWorkSource();
Irfan Sheriff227bec42011-02-15 19:30:27 -0800916 evaluateTrafficStatsPolling();
Irfan Sheriff0d255342010-07-28 09:35:20 -0700917 mWifiStateMachine.enableRssiPolling(true);
Irfan Sherifffcc08452011-02-17 16:44:54 -0800918 if (mBackgroundScanSupported) {
Irfan Sheriff2b7f6382011-03-25 14:29:19 -0700919 mWifiStateMachine.enableBackgroundScanCommand(false);
Irfan Sherifffcc08452011-02-17 16:44:54 -0800920 }
Irfan Sheriff8e86b892010-12-22 11:02:20 -0800921 mWifiStateMachine.enableAllNetworks();
Irfan Sheriff4f5f7c92010-10-14 17:01:27 -0700922 updateWifiState();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800923 } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
Joe Onorato431bb222010-10-18 19:13:23 -0400924 if (DBG) {
925 Slog.d(TAG, "ACTION_SCREEN_OFF");
926 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800927 mScreenOff = true;
Irfan Sheriff227bec42011-02-15 19:30:27 -0800928 evaluateTrafficStatsPolling();
Irfan Sheriff0d255342010-07-28 09:35:20 -0700929 mWifiStateMachine.enableRssiPolling(false);
Irfan Sherifffcc08452011-02-17 16:44:54 -0800930 if (mBackgroundScanSupported) {
Irfan Sheriff2b7f6382011-03-25 14:29:19 -0700931 mWifiStateMachine.enableBackgroundScanCommand(true);
Irfan Sherifffcc08452011-02-17 16:44:54 -0800932 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800933 /*
934 * Set a timer to put Wi-Fi to sleep, but only if the screen is off
935 * AND the "stay on while plugged in" setting doesn't match the
936 * current power conditions (i.e, not plugged in, plugged in to USB,
937 * or plugged in to AC).
938 */
939 if (!shouldWifiStayAwake(stayAwakeConditions, mPluggedType)) {
Irfan Sheriffd8134ff2010-08-22 17:06:34 -0700940 WifiInfo info = mWifiStateMachine.syncRequestConnectionInfo();
San Mehatfa6c7112009-07-07 09:34:44 -0700941 if (info.getSupplicantState() != SupplicantState.COMPLETED) {
Robert Greenwalt84612ea62009-09-30 09:04:22 -0700942 // we used to go to sleep immediately, but this caused some race conditions
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700943 // we don't have time to track down for this release. Delay instead,
944 // but not as long as we would if connected (below)
Robert Greenwalt84612ea62009-09-30 09:04:22 -0700945 // TODO - fix the race conditions and switch back to the immediate turn-off
946 long triggerTime = System.currentTimeMillis() + (2*60*1000); // 2 min
Joe Onorato431bb222010-10-18 19:13:23 -0400947 if (DBG) {
948 Slog.d(TAG, "setting ACTION_DEVICE_IDLE timer for 120,000 ms");
949 }
Robert Greenwalt84612ea62009-09-30 09:04:22 -0700950 mAlarmManager.set(AlarmManager.RTC_WAKEUP, triggerTime, mIdleIntent);
951 // // do not keep Wifi awake when screen is off if Wifi is not associated
952 // mDeviceIdle = true;
953 // updateWifiState();
Mike Lockwoodd9c32bc2009-05-18 14:14:15 -0400954 } else {
955 long triggerTime = System.currentTimeMillis() + idleMillis;
Joe Onorato431bb222010-10-18 19:13:23 -0400956 if (DBG) {
957 Slog.d(TAG, "setting ACTION_DEVICE_IDLE timer for " + idleMillis
958 + "ms");
959 }
Mike Lockwoodd9c32bc2009-05-18 14:14:15 -0400960 mAlarmManager.set(AlarmManager.RTC_WAKEUP, triggerTime, mIdleIntent);
961 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800962 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800963 } else if (action.equals(ACTION_DEVICE_IDLE)) {
Joe Onorato431bb222010-10-18 19:13:23 -0400964 if (DBG) {
965 Slog.d(TAG, "got ACTION_DEVICE_IDLE");
966 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800967 mDeviceIdle = true;
Dianne Hackborn58e0eef2010-09-16 01:22:10 -0700968 reportStartWorkSource();
Irfan Sheriff4f5f7c92010-10-14 17:01:27 -0700969 updateWifiState();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800970 } else if (action.equals(Intent.ACTION_BATTERY_CHANGED)) {
971 /*
972 * Set a timer to put Wi-Fi to sleep, but only if the screen is off
973 * AND we are transitioning from a state in which the device was supposed
974 * to stay awake to a state in which it is not supposed to stay awake.
975 * If "stay awake" state is not changing, we do nothing, to avoid resetting
976 * the already-set timer.
977 */
978 int pluggedType = intent.getIntExtra("plugged", 0);
Joe Onorato431bb222010-10-18 19:13:23 -0400979 if (DBG) {
980 Slog.d(TAG, "ACTION_BATTERY_CHANGED pluggedType: " + pluggedType);
981 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800982 if (mScreenOff && shouldWifiStayAwake(stayAwakeConditions, mPluggedType) &&
983 !shouldWifiStayAwake(stayAwakeConditions, pluggedType)) {
984 long triggerTime = System.currentTimeMillis() + idleMillis;
Joe Onorato431bb222010-10-18 19:13:23 -0400985 if (DBG) {
986 Slog.d(TAG, "setting ACTION_DEVICE_IDLE timer for " + idleMillis + "ms");
987 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800988 mAlarmManager.set(AlarmManager.RTC_WAKEUP, triggerTime, mIdleIntent);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800989 }
990 mPluggedType = pluggedType;
Irfan Sheriff65eaec82011-01-05 22:00:16 -0800991 } else if (action.equals(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED)) {
992 int state = intent.getIntExtra(BluetoothAdapter.EXTRA_CONNECTION_STATE,
993 BluetoothAdapter.STATE_DISCONNECTED);
994 mWifiStateMachine.sendBluetoothAdapterStateChange(state);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800995 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800996 }
997
998 /**
999 * Determines whether the Wi-Fi chipset should stay awake or be put to
1000 * sleep. Looks at the setting for the sleep policy and the current
1001 * conditions.
Jaikumar Ganesh084c6652009-12-07 10:58:18 -08001002 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001003 * @see #shouldDeviceStayAwake(int, int)
1004 */
1005 private boolean shouldWifiStayAwake(int stayAwakeConditions, int pluggedType) {
Irfan Sheriff739f6bc2011-01-28 16:43:12 -08001006 //Never sleep as long as the user has not changed the settings
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001007 int wifiSleepPolicy = Settings.System.getInt(mContext.getContentResolver(),
Irfan Sheriff96b10d62011-01-11 15:40:35 -08001008 Settings.System.WIFI_SLEEP_POLICY,
Irfan Sheriff739f6bc2011-01-28 16:43:12 -08001009 Settings.System.WIFI_SLEEP_POLICY_NEVER);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001010
1011 if (wifiSleepPolicy == Settings.System.WIFI_SLEEP_POLICY_NEVER) {
1012 // Never sleep
1013 return true;
1014 } else if ((wifiSleepPolicy == Settings.System.WIFI_SLEEP_POLICY_NEVER_WHILE_PLUGGED) &&
1015 (pluggedType != 0)) {
1016 // Never sleep while plugged, and we're plugged
1017 return true;
1018 } else {
1019 // Default
1020 return shouldDeviceStayAwake(stayAwakeConditions, pluggedType);
1021 }
1022 }
Jaikumar Ganesh084c6652009-12-07 10:58:18 -08001023
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001024 /**
1025 * Determine whether the bit value corresponding to {@code pluggedType} is set in
1026 * the bit string {@code stayAwakeConditions}. Because a {@code pluggedType} value
1027 * of {@code 0} isn't really a plugged type, but rather an indication that the
1028 * device isn't plugged in at all, there is no bit value corresponding to a
1029 * {@code pluggedType} value of {@code 0}. That is why we shift by
Ben Dodson4e8620f2010-08-25 10:55:47 -07001030 * {@code pluggedType - 1} instead of by {@code pluggedType}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001031 * @param stayAwakeConditions a bit string specifying which "plugged types" should
1032 * keep the device (and hence Wi-Fi) awake.
1033 * @param pluggedType the type of plug (USB, AC, or none) for which the check is
1034 * being made
1035 * @return {@code true} if {@code pluggedType} indicates that the device is
1036 * supposed to stay awake, {@code false} otherwise.
1037 */
1038 private boolean shouldDeviceStayAwake(int stayAwakeConditions, int pluggedType) {
1039 return (stayAwakeConditions & pluggedType) != 0;
1040 }
1041 };
1042
Dianne Hackborn03f3cb02010-09-17 23:12:26 -07001043 private synchronized void reportStartWorkSource() {
1044 mTmpWorkSource.clear();
1045 if (mDeviceIdle) {
1046 for (int i=0; i<mLocks.mList.size(); i++) {
1047 mTmpWorkSource.add(mLocks.mList.get(i).mWorkSource);
Dianne Hackborn58e0eef2010-09-16 01:22:10 -07001048 }
Dianne Hackborn58e0eef2010-09-16 01:22:10 -07001049 }
Dianne Hackborn03f3cb02010-09-17 23:12:26 -07001050 mWifiStateMachine.updateBatteryWorkSource(mTmpWorkSource);
Dianne Hackborn58e0eef2010-09-16 01:22:10 -07001051 }
Jaikumar Ganesh7440fc22010-09-27 17:04:14 -07001052
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001053 private void updateWifiState() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001054 boolean lockHeld = mLocks.hasLocks();
Irfan Sheriff5876a422010-08-12 20:26:23 -07001055 int strongestLockMode = WifiManager.WIFI_MODE_FULL;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001056 boolean wifiShouldBeStarted = !mDeviceIdle || lockHeld;
Irfan Sheriff5876a422010-08-12 20:26:23 -07001057
1058 if (lockHeld) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001059 strongestLockMode = mLocks.getStrongestLockMode();
Irfan Sheriff5876a422010-08-12 20:26:23 -07001060 }
1061 /* If device is not idle, lockmode cannot be scan only */
1062 if (!mDeviceIdle && strongestLockMode == WifiManager.WIFI_MODE_SCAN_ONLY) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001063 strongestLockMode = WifiManager.WIFI_MODE_FULL;
1064 }
1065
Irfan Sheriffa2a1b912010-06-07 09:03:04 -07001066 /* Disable tethering when airplane mode is enabled */
Irfan Sheriff658772f2011-03-08 14:52:31 -08001067 if (mAirplaneModeOn.get()) {
Irfan Sheriff0d255342010-07-28 09:35:20 -07001068 mWifiStateMachine.setWifiApEnabled(null, false);
Irfan Sheriffa2a1b912010-06-07 09:03:04 -07001069 }
Irfan Sheriffb2e6c012010-04-05 11:57:56 -07001070
Irfan Sheriff658772f2011-03-08 14:52:31 -08001071 if (shouldWifiBeEnabled()) {
Irfan Sheriffa2a1b912010-06-07 09:03:04 -07001072 if (wifiShouldBeStarted) {
Dianne Hackborn03f3cb02010-09-17 23:12:26 -07001073 reportStartWorkSource();
Irfan Sheriff0d255342010-07-28 09:35:20 -07001074 mWifiStateMachine.setWifiEnabled(true);
1075 mWifiStateMachine.setScanOnlyMode(
Irfan Sheriffa2a1b912010-06-07 09:03:04 -07001076 strongestLockMode == WifiManager.WIFI_MODE_SCAN_ONLY);
Irfan Sheriff0d255342010-07-28 09:35:20 -07001077 mWifiStateMachine.setDriverStart(true);
Irfan Sheriff5876a422010-08-12 20:26:23 -07001078 mWifiStateMachine.setHighPerfModeEnabled(strongestLockMode
1079 == WifiManager.WIFI_MODE_FULL_HIGH_PERF);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001080 } else {
Irfan Sheriff0d255342010-07-28 09:35:20 -07001081 mWifiStateMachine.requestCmWakeLock();
1082 mWifiStateMachine.setDriverStart(false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001083 }
Irfan Sheriffa2a1b912010-06-07 09:03:04 -07001084 } else {
Irfan Sheriff0d255342010-07-28 09:35:20 -07001085 mWifiStateMachine.setWifiEnabled(false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001086 }
1087 }
1088
1089 private void registerForBroadcasts() {
1090 IntentFilter intentFilter = new IntentFilter();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001091 intentFilter.addAction(Intent.ACTION_SCREEN_ON);
1092 intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
1093 intentFilter.addAction(Intent.ACTION_BATTERY_CHANGED);
1094 intentFilter.addAction(ACTION_DEVICE_IDLE);
Irfan Sheriff65eaec82011-01-05 22:00:16 -08001095 intentFilter.addAction(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001096 mContext.registerReceiver(mReceiver, intentFilter);
1097 }
Jaikumar Ganesh084c6652009-12-07 10:58:18 -08001098
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001099 private boolean isAirplaneSensitive() {
1100 String airplaneModeRadios = Settings.System.getString(mContext.getContentResolver(),
1101 Settings.System.AIRPLANE_MODE_RADIOS);
1102 return airplaneModeRadios == null
1103 || airplaneModeRadios.contains(Settings.System.RADIO_WIFI);
1104 }
1105
Mike Lockwoodbd5ddf02009-07-29 21:37:14 -07001106 private boolean isAirplaneToggleable() {
1107 String toggleableRadios = Settings.System.getString(mContext.getContentResolver(),
1108 Settings.System.AIRPLANE_MODE_TOGGLEABLE_RADIOS);
1109 return toggleableRadios != null
1110 && toggleableRadios.contains(Settings.System.RADIO_WIFI);
1111 }
1112
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001113 /**
1114 * Returns true if Wi-Fi is sensitive to airplane mode, and airplane mode is
1115 * currently on.
1116 * @return {@code true} if airplane mode is on.
1117 */
1118 private boolean isAirplaneModeOn() {
1119 return isAirplaneSensitive() && Settings.System.getInt(mContext.getContentResolver(),
1120 Settings.System.AIRPLANE_MODE_ON, 0) == 1;
1121 }
1122
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001123 @Override
1124 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1125 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
1126 != PackageManager.PERMISSION_GRANTED) {
1127 pw.println("Permission Denial: can't dump WifiService from from pid="
1128 + Binder.getCallingPid()
1129 + ", uid=" + Binder.getCallingUid());
1130 return;
1131 }
Irfan Sheriffd8134ff2010-08-22 17:06:34 -07001132 pw.println("Wi-Fi is " + mWifiStateMachine.syncGetWifiStateByName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001133 pw.println("Stay-awake conditions: " +
1134 Settings.System.getInt(mContext.getContentResolver(),
1135 Settings.System.STAY_ON_WHILE_PLUGGED_IN, 0));
1136 pw.println();
1137
1138 pw.println("Internal state:");
Irfan Sheriff0d255342010-07-28 09:35:20 -07001139 pw.println(mWifiStateMachine);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001140 pw.println();
1141 pw.println("Latest scan results:");
Irfan Sheriffd8134ff2010-08-22 17:06:34 -07001142 List<ScanResult> scanResults = mWifiStateMachine.syncGetScanResultsList();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001143 if (scanResults != null && scanResults.size() != 0) {
1144 pw.println(" BSSID Frequency RSSI Flags SSID");
1145 for (ScanResult r : scanResults) {
1146 pw.printf(" %17s %9d %5d %-16s %s%n",
1147 r.BSSID,
1148 r.frequency,
1149 r.level,
1150 r.capabilities,
1151 r.SSID == null ? "" : r.SSID);
1152 }
1153 }
1154 pw.println();
Eric Shienbrood5711fad2009-03-27 20:25:31 -07001155 pw.println("Locks acquired: " + mFullLocksAcquired + " full, " +
Irfan Sheriff5876a422010-08-12 20:26:23 -07001156 mFullHighPerfLocksAcquired + " full high perf, " +
Eric Shienbrood5711fad2009-03-27 20:25:31 -07001157 mScanLocksAcquired + " scan");
1158 pw.println("Locks released: " + mFullLocksReleased + " full, " +
Irfan Sheriff5876a422010-08-12 20:26:23 -07001159 mFullHighPerfLocksReleased + " full high perf, " +
Eric Shienbrood5711fad2009-03-27 20:25:31 -07001160 mScanLocksReleased + " scan");
1161 pw.println();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001162 pw.println("Locks held:");
1163 mLocks.dump(pw);
Isaac Levybc7dfb52011-06-06 15:34:01 -07001164
1165 pw.println();
Isaac Levy654f5092011-07-13 17:41:45 -07001166 pw.println("WifiWatchdogStateMachine dump");
1167 mWifiWatchdogStateMachine.dump(pw);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001168 }
1169
Robert Greenwalt58ff0212009-05-19 15:53:54 -07001170 private class WifiLock extends DeathRecipient {
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001171 WifiLock(int lockMode, String tag, IBinder binder, WorkSource ws) {
1172 super(lockMode, tag, binder, ws);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001173 }
1174
1175 public void binderDied() {
1176 synchronized (mLocks) {
1177 releaseWifiLockLocked(mBinder);
1178 }
1179 }
1180
1181 public String toString() {
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001182 return "WifiLock{" + mTag + " type=" + mMode + " binder=" + mBinder + "}";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001183 }
1184 }
1185
1186 private class LockList {
1187 private List<WifiLock> mList;
1188
1189 private LockList() {
1190 mList = new ArrayList<WifiLock>();
1191 }
1192
1193 private synchronized boolean hasLocks() {
1194 return !mList.isEmpty();
1195 }
1196
1197 private synchronized int getStrongestLockMode() {
1198 if (mList.isEmpty()) {
1199 return WifiManager.WIFI_MODE_FULL;
1200 }
Irfan Sheriff5876a422010-08-12 20:26:23 -07001201
1202 if (mFullHighPerfLocksAcquired > mFullHighPerfLocksReleased) {
1203 return WifiManager.WIFI_MODE_FULL_HIGH_PERF;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001204 }
Irfan Sheriff5876a422010-08-12 20:26:23 -07001205
1206 if (mFullLocksAcquired > mFullLocksReleased) {
1207 return WifiManager.WIFI_MODE_FULL;
1208 }
1209
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001210 return WifiManager.WIFI_MODE_SCAN_ONLY;
1211 }
1212
1213 private void addLock(WifiLock lock) {
1214 if (findLockByBinder(lock.mBinder) < 0) {
1215 mList.add(lock);
1216 }
1217 }
1218
1219 private WifiLock removeLock(IBinder binder) {
1220 int index = findLockByBinder(binder);
1221 if (index >= 0) {
Suchi Amalapurapufff2fda2009-06-30 21:36:16 -07001222 WifiLock ret = mList.remove(index);
1223 ret.unlinkDeathRecipient();
1224 return ret;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001225 } else {
1226 return null;
1227 }
1228 }
1229
1230 private int findLockByBinder(IBinder binder) {
1231 int size = mList.size();
1232 for (int i = size - 1; i >= 0; i--)
1233 if (mList.get(i).mBinder == binder)
1234 return i;
1235 return -1;
1236 }
1237
1238 private void dump(PrintWriter pw) {
1239 for (WifiLock l : mList) {
1240 pw.print(" ");
1241 pw.println(l);
1242 }
1243 }
1244 }
1245
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001246 void enforceWakeSourcePermission(int uid, int pid) {
Dianne Hackborne746f032010-09-13 16:02:57 -07001247 if (uid == android.os.Process.myUid()) {
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001248 return;
1249 }
1250 mContext.enforcePermission(android.Manifest.permission.UPDATE_DEVICE_STATS,
1251 pid, uid, null);
1252 }
1253
1254 public boolean acquireWifiLock(IBinder binder, int lockMode, String tag, WorkSource ws) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001255 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WAKE_LOCK, null);
Irfan Sheriff5876a422010-08-12 20:26:23 -07001256 if (lockMode != WifiManager.WIFI_MODE_FULL &&
1257 lockMode != WifiManager.WIFI_MODE_SCAN_ONLY &&
1258 lockMode != WifiManager.WIFI_MODE_FULL_HIGH_PERF) {
1259 Slog.e(TAG, "Illegal argument, lockMode= " + lockMode);
1260 if (DBG) throw new IllegalArgumentException("lockMode=" + lockMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001261 return false;
1262 }
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001263 if (ws != null && ws.size() == 0) {
1264 ws = null;
1265 }
Dianne Hackbornecfd7f72010-10-08 14:23:40 -07001266 if (ws != null) {
1267 enforceWakeSourcePermission(Binder.getCallingUid(), Binder.getCallingPid());
1268 }
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001269 if (ws == null) {
1270 ws = new WorkSource(Binder.getCallingUid());
1271 }
1272 WifiLock wifiLock = new WifiLock(lockMode, tag, binder, ws);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001273 synchronized (mLocks) {
1274 return acquireWifiLockLocked(wifiLock);
1275 }
1276 }
1277
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001278 private void noteAcquireWifiLock(WifiLock wifiLock) throws RemoteException {
1279 switch(wifiLock.mMode) {
1280 case WifiManager.WIFI_MODE_FULL:
Irfan Sheriff5876a422010-08-12 20:26:23 -07001281 case WifiManager.WIFI_MODE_FULL_HIGH_PERF:
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001282 mBatteryStats.noteFullWifiLockAcquiredFromSource(wifiLock.mWorkSource);
1283 break;
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001284 case WifiManager.WIFI_MODE_SCAN_ONLY:
1285 mBatteryStats.noteScanWifiLockAcquiredFromSource(wifiLock.mWorkSource);
1286 break;
1287 }
1288 }
1289
1290 private void noteReleaseWifiLock(WifiLock wifiLock) throws RemoteException {
1291 switch(wifiLock.mMode) {
1292 case WifiManager.WIFI_MODE_FULL:
Irfan Sheriff5876a422010-08-12 20:26:23 -07001293 case WifiManager.WIFI_MODE_FULL_HIGH_PERF:
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001294 mBatteryStats.noteFullWifiLockReleasedFromSource(wifiLock.mWorkSource);
1295 break;
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001296 case WifiManager.WIFI_MODE_SCAN_ONLY:
1297 mBatteryStats.noteScanWifiLockReleasedFromSource(wifiLock.mWorkSource);
1298 break;
1299 }
1300 }
1301
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001302 private boolean acquireWifiLockLocked(WifiLock wifiLock) {
Irfan Sheriffc89dd542010-09-28 08:40:54 -07001303 if (DBG) Slog.d(TAG, "acquireWifiLockLocked: " + wifiLock);
Robert Greenwaltf1acb2d2009-10-13 08:20:55 -07001304
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001305 mLocks.addLock(wifiLock);
Robert Greenwaltf1acb2d2009-10-13 08:20:55 -07001306
The Android Open Source Project10592532009-03-18 17:39:46 -07001307 long ident = Binder.clearCallingIdentity();
1308 try {
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001309 noteAcquireWifiLock(wifiLock);
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001310 switch(wifiLock.mMode) {
Eric Shienbrood5711fad2009-03-27 20:25:31 -07001311 case WifiManager.WIFI_MODE_FULL:
1312 ++mFullLocksAcquired;
Eric Shienbrood5711fad2009-03-27 20:25:31 -07001313 break;
Irfan Sheriff5876a422010-08-12 20:26:23 -07001314 case WifiManager.WIFI_MODE_FULL_HIGH_PERF:
1315 ++mFullHighPerfLocksAcquired;
1316 break;
1317
Eric Shienbrood5711fad2009-03-27 20:25:31 -07001318 case WifiManager.WIFI_MODE_SCAN_ONLY:
1319 ++mScanLocksAcquired;
Eric Shienbrood5711fad2009-03-27 20:25:31 -07001320 break;
The Android Open Source Project10592532009-03-18 17:39:46 -07001321 }
Dianne Hackbornecfd7f72010-10-08 14:23:40 -07001322
1323 // Be aggressive about adding new locks into the accounted state...
1324 // we want to over-report rather than under-report.
1325 reportStartWorkSource();
1326
1327 updateWifiState();
1328 return true;
The Android Open Source Project10592532009-03-18 17:39:46 -07001329 } catch (RemoteException e) {
Dianne Hackbornecfd7f72010-10-08 14:23:40 -07001330 return false;
The Android Open Source Project10592532009-03-18 17:39:46 -07001331 } finally {
1332 Binder.restoreCallingIdentity(ident);
1333 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001334 }
1335
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001336 public void updateWifiLockWorkSource(IBinder lock, WorkSource ws) {
1337 int uid = Binder.getCallingUid();
1338 int pid = Binder.getCallingPid();
1339 if (ws != null && ws.size() == 0) {
1340 ws = null;
1341 }
1342 if (ws != null) {
1343 enforceWakeSourcePermission(uid, pid);
1344 }
1345 long ident = Binder.clearCallingIdentity();
1346 try {
1347 synchronized (mLocks) {
1348 int index = mLocks.findLockByBinder(lock);
1349 if (index < 0) {
1350 throw new IllegalArgumentException("Wifi lock not active");
1351 }
1352 WifiLock wl = mLocks.mList.get(index);
1353 noteReleaseWifiLock(wl);
1354 wl.mWorkSource = ws != null ? new WorkSource(ws) : new WorkSource(uid);
1355 noteAcquireWifiLock(wl);
1356 }
1357 } catch (RemoteException e) {
1358 } finally {
1359 Binder.restoreCallingIdentity(ident);
1360 }
1361 }
1362
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001363 public boolean releaseWifiLock(IBinder lock) {
1364 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WAKE_LOCK, null);
1365 synchronized (mLocks) {
1366 return releaseWifiLockLocked(lock);
1367 }
1368 }
1369
1370 private boolean releaseWifiLockLocked(IBinder lock) {
Eric Shienbroodd4c5f892009-03-24 18:13:20 -07001371 boolean hadLock;
Robert Greenwaltf1acb2d2009-10-13 08:20:55 -07001372
The Android Open Source Project10592532009-03-18 17:39:46 -07001373 WifiLock wifiLock = mLocks.removeLock(lock);
Robert Greenwaltf1acb2d2009-10-13 08:20:55 -07001374
Irfan Sheriffc89dd542010-09-28 08:40:54 -07001375 if (DBG) Slog.d(TAG, "releaseWifiLockLocked: " + wifiLock);
Robert Greenwaltf1acb2d2009-10-13 08:20:55 -07001376
Eric Shienbroodd4c5f892009-03-24 18:13:20 -07001377 hadLock = (wifiLock != null);
1378
Dianne Hackbornecfd7f72010-10-08 14:23:40 -07001379 long ident = Binder.clearCallingIdentity();
1380 try {
1381 if (hadLock) {
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001382 noteAcquireWifiLock(wifiLock);
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001383 switch(wifiLock.mMode) {
Eric Shienbrood5711fad2009-03-27 20:25:31 -07001384 case WifiManager.WIFI_MODE_FULL:
1385 ++mFullLocksReleased;
Eric Shienbrood5711fad2009-03-27 20:25:31 -07001386 break;
Irfan Sheriff5876a422010-08-12 20:26:23 -07001387 case WifiManager.WIFI_MODE_FULL_HIGH_PERF:
1388 ++mFullHighPerfLocksReleased;
1389 break;
Eric Shienbrood5711fad2009-03-27 20:25:31 -07001390 case WifiManager.WIFI_MODE_SCAN_ONLY:
1391 ++mScanLocksReleased;
Eric Shienbrood5711fad2009-03-27 20:25:31 -07001392 break;
Eric Shienbroodd4c5f892009-03-24 18:13:20 -07001393 }
The Android Open Source Project10592532009-03-18 17:39:46 -07001394 }
Dianne Hackbornecfd7f72010-10-08 14:23:40 -07001395
1396 // TODO - should this only happen if you hadLock?
1397 updateWifiState();
1398
1399 } catch (RemoteException e) {
1400 } finally {
1401 Binder.restoreCallingIdentity(ident);
The Android Open Source Project10592532009-03-18 17:39:46 -07001402 }
Dianne Hackbornecfd7f72010-10-08 14:23:40 -07001403
Eric Shienbroodd4c5f892009-03-24 18:13:20 -07001404 return hadLock;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001405 }
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001406
Robert Greenwalt58ff0212009-05-19 15:53:54 -07001407 private abstract class DeathRecipient
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001408 implements IBinder.DeathRecipient {
1409 String mTag;
1410 int mMode;
1411 IBinder mBinder;
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001412 WorkSource mWorkSource;
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001413
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001414 DeathRecipient(int mode, String tag, IBinder binder, WorkSource ws) {
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001415 super();
1416 mTag = tag;
1417 mMode = mode;
1418 mBinder = binder;
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001419 mWorkSource = ws;
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001420 try {
1421 mBinder.linkToDeath(this, 0);
1422 } catch (RemoteException e) {
1423 binderDied();
1424 }
1425 }
Suchi Amalapurapufff2fda2009-06-30 21:36:16 -07001426
1427 void unlinkDeathRecipient() {
1428 mBinder.unlinkToDeath(this, 0);
1429 }
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001430 }
1431
Robert Greenwalt58ff0212009-05-19 15:53:54 -07001432 private class Multicaster extends DeathRecipient {
1433 Multicaster(String tag, IBinder binder) {
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001434 super(Binder.getCallingUid(), tag, binder, null);
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001435 }
1436
1437 public void binderDied() {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001438 Slog.e(TAG, "Multicaster binderDied");
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001439 synchronized (mMulticasters) {
1440 int i = mMulticasters.indexOf(this);
1441 if (i != -1) {
1442 removeMulticasterLocked(i, mMode);
1443 }
1444 }
1445 }
1446
1447 public String toString() {
Robert Greenwalt58ff0212009-05-19 15:53:54 -07001448 return "Multicaster{" + mTag + " binder=" + mBinder + "}";
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001449 }
1450
1451 public int getUid() {
1452 return mMode;
1453 }
1454 }
1455
Robert Greenwalte2d155a2009-10-21 14:58:34 -07001456 public void initializeMulticastFiltering() {
1457 enforceMulticastChangePermission();
Irfan Sheriffa8fbe1f2010-03-09 09:13:58 -08001458
Robert Greenwalte2d155a2009-10-21 14:58:34 -07001459 synchronized (mMulticasters) {
1460 // if anybody had requested filters be off, leave off
1461 if (mMulticasters.size() != 0) {
1462 return;
1463 } else {
Irfan Sheriffb0c1b80f2011-07-19 15:44:25 -07001464 mWifiStateMachine.startFilteringMulticastV4Packets();
Robert Greenwalte2d155a2009-10-21 14:58:34 -07001465 }
1466 }
1467 }
1468
Robert Greenwaltfc1b15c2009-05-22 15:09:51 -07001469 public void acquireMulticastLock(IBinder binder, String tag) {
1470 enforceMulticastChangePermission();
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001471
1472 synchronized (mMulticasters) {
1473 mMulticastEnabled++;
Robert Greenwalt58ff0212009-05-19 15:53:54 -07001474 mMulticasters.add(new Multicaster(tag, binder));
Irfan Sheriffb0c1b80f2011-07-19 15:44:25 -07001475 // Note that we could call stopFilteringMulticastV4Packets only when
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001476 // our new size == 1 (first call), but this function won't
1477 // be called often and by making the stopPacket call each
1478 // time we're less fragile and self-healing.
Irfan Sheriffb0c1b80f2011-07-19 15:44:25 -07001479 mWifiStateMachine.stopFilteringMulticastV4Packets();
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001480 }
1481
1482 int uid = Binder.getCallingUid();
1483 Long ident = Binder.clearCallingIdentity();
1484 try {
1485 mBatteryStats.noteWifiMulticastEnabled(uid);
1486 } catch (RemoteException e) {
1487 } finally {
1488 Binder.restoreCallingIdentity(ident);
1489 }
1490 }
1491
Robert Greenwaltfc1b15c2009-05-22 15:09:51 -07001492 public void releaseMulticastLock() {
1493 enforceMulticastChangePermission();
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001494
1495 int uid = Binder.getCallingUid();
1496 synchronized (mMulticasters) {
1497 mMulticastDisabled++;
1498 int size = mMulticasters.size();
1499 for (int i = size - 1; i >= 0; i--) {
Robert Greenwalt58ff0212009-05-19 15:53:54 -07001500 Multicaster m = mMulticasters.get(i);
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001501 if ((m != null) && (m.getUid() == uid)) {
1502 removeMulticasterLocked(i, uid);
1503 }
1504 }
1505 }
1506 }
1507
1508 private void removeMulticasterLocked(int i, int uid)
1509 {
Suchi Amalapurapufff2fda2009-06-30 21:36:16 -07001510 Multicaster removed = mMulticasters.remove(i);
Irfan Sheriffa8fbe1f2010-03-09 09:13:58 -08001511
Suchi Amalapurapufff2fda2009-06-30 21:36:16 -07001512 if (removed != null) {
1513 removed.unlinkDeathRecipient();
1514 }
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001515 if (mMulticasters.size() == 0) {
Irfan Sheriffb0c1b80f2011-07-19 15:44:25 -07001516 mWifiStateMachine.startFilteringMulticastV4Packets();
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001517 }
1518
1519 Long ident = Binder.clearCallingIdentity();
1520 try {
1521 mBatteryStats.noteWifiMulticastDisabled(uid);
1522 } catch (RemoteException e) {
1523 } finally {
1524 Binder.restoreCallingIdentity(ident);
1525 }
1526 }
1527
Robert Greenwalt58ff0212009-05-19 15:53:54 -07001528 public boolean isMulticastEnabled() {
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001529 enforceAccessPermission();
1530
1531 synchronized (mMulticasters) {
1532 return (mMulticasters.size() > 0);
1533 }
1534 }
Irfan Sheriff0d255342010-07-28 09:35:20 -07001535
Irfan Sheriff227bec42011-02-15 19:30:27 -08001536 /**
1537 * Evaluate if traffic stats polling is needed based on
1538 * connection and screen on status
1539 */
1540 private void evaluateTrafficStatsPolling() {
1541 Message msg;
1542 if (mNetworkInfo.getDetailedState() == DetailedState.CONNECTED && !mScreenOff) {
Irfan Sheriffebe606f2011-02-24 11:39:15 -08001543 msg = Message.obtain(mAsyncServiceHandler,
1544 WifiManager.CMD_ENABLE_TRAFFIC_STATS_POLL, 1, 0);
Irfan Sheriff227bec42011-02-15 19:30:27 -08001545 } else {
Irfan Sheriffebe606f2011-02-24 11:39:15 -08001546 msg = Message.obtain(mAsyncServiceHandler,
1547 WifiManager.CMD_ENABLE_TRAFFIC_STATS_POLL, 0, 0);
Irfan Sheriff227bec42011-02-15 19:30:27 -08001548 }
1549 msg.sendToTarget();
1550 }
1551
1552 private void notifyOnDataActivity() {
1553 long sent, received;
1554 long preTxPkts = mTxPkts, preRxPkts = mRxPkts;
1555 int dataActivity = WifiManager.DATA_ACTIVITY_NONE;
1556
1557 mTxPkts = TrafficStats.getTxPackets(mInterfaceName);
1558 mRxPkts = TrafficStats.getRxPackets(mInterfaceName);
1559
1560 if (preTxPkts > 0 || preRxPkts > 0) {
1561 sent = mTxPkts - preTxPkts;
1562 received = mRxPkts - preRxPkts;
1563 if (sent > 0) {
1564 dataActivity |= WifiManager.DATA_ACTIVITY_OUT;
1565 }
1566 if (received > 0) {
1567 dataActivity |= WifiManager.DATA_ACTIVITY_IN;
1568 }
1569
1570 if (dataActivity != mDataActivity && !mScreenOff) {
1571 mDataActivity = dataActivity;
1572 for (AsyncChannel client : mClients) {
1573 client.sendMessage(WifiManager.DATA_ACTIVITY_NOTIFICATION, mDataActivity);
1574 }
1575 }
1576 }
1577 }
1578
1579
Irfan Sheriff0d255342010-07-28 09:35:20 -07001580 private void checkAndSetNotification() {
1581 // If we shouldn't place a notification on available networks, then
1582 // don't bother doing any of the following
1583 if (!mNotificationEnabled) return;
1584
1585 State state = mNetworkInfo.getState();
1586 if ((state == NetworkInfo.State.DISCONNECTED)
1587 || (state == NetworkInfo.State.UNKNOWN)) {
1588 // Look for an open network
Irfan Sheriffd8134ff2010-08-22 17:06:34 -07001589 List<ScanResult> scanResults = mWifiStateMachine.syncGetScanResultsList();
Irfan Sheriff0d255342010-07-28 09:35:20 -07001590 if (scanResults != null) {
1591 int numOpenNetworks = 0;
1592 for (int i = scanResults.size() - 1; i >= 0; i--) {
1593 ScanResult scanResult = scanResults.get(i);
1594
1595 if (TextUtils.isEmpty(scanResult.capabilities)) {
1596 numOpenNetworks++;
1597 }
1598 }
1599
1600 if (numOpenNetworks > 0) {
1601 if (++mNumScansSinceNetworkStateChange >= NUM_SCANS_BEFORE_ACTUALLY_SCANNING) {
1602 /*
1603 * We've scanned continuously at least
1604 * NUM_SCANS_BEFORE_NOTIFICATION times. The user
1605 * probably does not have a remembered network in range,
1606 * since otherwise supplicant would have tried to
1607 * associate and thus resetting this counter.
1608 */
1609 setNotificationVisible(true, numOpenNetworks, false, 0);
1610 }
1611 return;
1612 }
1613 }
1614 }
1615
1616 // No open networks in range, remove the notification
1617 setNotificationVisible(false, 0, false, 0);
1618 }
1619
1620 /**
1621 * Clears variables related to tracking whether a notification has been
1622 * shown recently and clears the current notification.
1623 */
1624 private void resetNotification() {
1625 mNotificationRepeatTime = 0;
1626 mNumScansSinceNetworkStateChange = 0;
1627 setNotificationVisible(false, 0, false, 0);
1628 }
1629
1630 /**
1631 * Display or don't display a notification that there are open Wi-Fi networks.
1632 * @param visible {@code true} if notification should be visible, {@code false} otherwise
1633 * @param numNetworks the number networks seen
1634 * @param force {@code true} to force notification to be shown/not-shown,
1635 * even if it is already shown/not-shown.
1636 * @param delay time in milliseconds after which the notification should be made
1637 * visible or invisible.
1638 */
1639 private void setNotificationVisible(boolean visible, int numNetworks, boolean force,
1640 int delay) {
1641
1642 // Since we use auto cancel on the notification, when the
1643 // mNetworksAvailableNotificationShown is true, the notification may
1644 // have actually been canceled. However, when it is false we know
1645 // for sure that it is not being shown (it will not be shown any other
1646 // place than here)
1647
1648 // If it should be hidden and it is already hidden, then noop
1649 if (!visible && !mNotificationShown && !force) {
1650 return;
1651 }
1652
1653 NotificationManager notificationManager = (NotificationManager) mContext
1654 .getSystemService(Context.NOTIFICATION_SERVICE);
1655
1656 Message message;
1657 if (visible) {
1658
1659 // Not enough time has passed to show the notification again
1660 if (System.currentTimeMillis() < mNotificationRepeatTime) {
1661 return;
1662 }
1663
1664 if (mNotification == null) {
Wink Savillec7a98342010-08-13 16:11:42 -07001665 // Cache the Notification object.
Irfan Sheriff0d255342010-07-28 09:35:20 -07001666 mNotification = new Notification();
1667 mNotification.when = 0;
1668 mNotification.icon = ICON_NETWORKS_AVAILABLE;
1669 mNotification.flags = Notification.FLAG_AUTO_CANCEL;
1670 mNotification.contentIntent = PendingIntent.getActivity(mContext, 0,
1671 new Intent(WifiManager.ACTION_PICK_WIFI_NETWORK), 0);
1672 }
1673
1674 CharSequence title = mContext.getResources().getQuantityText(
1675 com.android.internal.R.plurals.wifi_available, numNetworks);
1676 CharSequence details = mContext.getResources().getQuantityText(
1677 com.android.internal.R.plurals.wifi_available_detailed, numNetworks);
1678 mNotification.tickerText = title;
1679 mNotification.setLatestEventInfo(mContext, title, details, mNotification.contentIntent);
1680
1681 mNotificationRepeatTime = System.currentTimeMillis() + NOTIFICATION_REPEAT_DELAY_MS;
1682
1683 notificationManager.notify(ICON_NETWORKS_AVAILABLE, mNotification);
Irfan Sheriff0d255342010-07-28 09:35:20 -07001684 } else {
Irfan Sheriff0d255342010-07-28 09:35:20 -07001685 notificationManager.cancel(ICON_NETWORKS_AVAILABLE);
Irfan Sheriff0d255342010-07-28 09:35:20 -07001686 }
1687
Irfan Sheriff0d255342010-07-28 09:35:20 -07001688 mNotificationShown = visible;
1689 }
1690
1691 private class NotificationEnabledSettingObserver extends ContentObserver {
1692
1693 public NotificationEnabledSettingObserver(Handler handler) {
1694 super(handler);
1695 }
1696
1697 public void register() {
1698 ContentResolver cr = mContext.getContentResolver();
1699 cr.registerContentObserver(Settings.Secure.getUriFor(
1700 Settings.Secure.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON), true, this);
1701 mNotificationEnabled = getValue();
1702 }
1703
1704 @Override
1705 public void onChange(boolean selfChange) {
1706 super.onChange(selfChange);
1707
1708 mNotificationEnabled = getValue();
1709 resetNotification();
1710 }
1711
1712 private boolean getValue() {
1713 return Settings.Secure.getInt(mContext.getContentResolver(),
1714 Settings.Secure.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON, 1) == 1;
1715 }
1716 }
1717
1718
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001719}