blob: 0000237875484a683db8123e1ee2cae32bee62ff [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;
Irfan Sheriff9ab518ad2010-03-12 15:48:17 -080038import android.net.wifi.WifiConfiguration.KeyMgmt;
Irfan Sheriff02fb46a2010-12-08 11:27:37 -080039import android.net.wifi.WpsConfiguration;
Irfan Sheriffe4c56c92011-01-12 16:33:58 -080040import android.net.wifi.WpsResult;
Irfan Sheriff5321aef2010-02-12 12:35:59 -080041import android.net.ConnectivityManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080042import android.net.DhcpInfo;
Irfan Sheriff0d255342010-07-28 09:35:20 -070043import android.net.NetworkInfo;
44import android.net.NetworkInfo.State;
Irfan Sheriff227bec42011-02-15 19:30:27 -080045import android.net.NetworkInfo.DetailedState;
46import android.net.TrafficStats;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080047import android.os.Binder;
Irfan Sheriff0d255342010-07-28 09:35:20 -070048import android.os.Handler;
Irfan Sheriff227bec42011-02-15 19:30:27 -080049import android.os.Messenger;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080050import android.os.HandlerThread;
51import android.os.IBinder;
Irfan Sheriff5321aef2010-02-12 12:35:59 -080052import android.os.INetworkManagementService;
Irfan Sheriff0d255342010-07-28 09:35:20 -070053import android.os.Message;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080054import android.os.RemoteException;
Amith Yamasani47873e52009-07-02 12:05:32 -070055import android.os.ServiceManager;
Irfan Sheriff227bec42011-02-15 19:30:27 -080056import android.os.SystemProperties;
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -070057import android.os.WorkSource;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080058import android.provider.Settings;
Irfan Sheriff0d255342010-07-28 09:35:20 -070059import android.text.TextUtils;
Joe Onorato8a9b2202010-02-26 18:56:32 -080060import android.util.Slog;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080061
62import java.util.ArrayList;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080063import java.util.List;
Jaikumar Ganesh084c6652009-12-07 10:58:18 -080064import java.util.Set;
Irfan Sheriff658772f2011-03-08 14:52:31 -080065import java.util.concurrent.atomic.AtomicInteger;
Irfan Sheriffa2a1b912010-06-07 09:03:04 -070066import java.util.concurrent.atomic.AtomicBoolean;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080067import java.io.FileDescriptor;
68import java.io.PrintWriter;
69
The Android Open Source Project10592532009-03-18 17:39:46 -070070import com.android.internal.app.IBatteryStats;
Wink Saville4b7ba092010-10-20 15:37:41 -070071import com.android.internal.util.AsyncChannel;
The Android Open Source Project10592532009-03-18 17:39:46 -070072import com.android.server.am.BatteryStatsService;
Irfan Sheriff9ab518ad2010-03-12 15:48:17 -080073import com.android.internal.R;
The Android Open Source Project10592532009-03-18 17:39:46 -070074
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080075/**
76 * WifiService handles remote WiFi operation requests by implementing
Irfan Sheriffa2a1b912010-06-07 09:03:04 -070077 * the IWifiManager interface.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080078 *
79 * @hide
80 */
Irfan Sheriffa2a1b912010-06-07 09:03:04 -070081//TODO: Clean up multiple locks and implement WifiService
82// as a SM to track soft AP/client/adhoc bring up based
83// on device idle state, airplane mode and boot.
84
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080085public class WifiService extends IWifiManager.Stub {
86 private static final String TAG = "WifiService";
Irfan Sheriffa2a1b912010-06-07 09:03:04 -070087 private static final boolean DBG = true;
88
Irfan Sheriff0d255342010-07-28 09:35:20 -070089 private final WifiStateMachine mWifiStateMachine;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080090
91 private Context mContext;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080092
93 private AlarmManager mAlarmManager;
94 private PendingIntent mIdleIntent;
95 private static final int IDLE_REQUEST = 0;
96 private boolean mScreenOff;
97 private boolean mDeviceIdle;
98 private int mPluggedType;
99
Irfan Sherifffcc08452011-02-17 16:44:54 -0800100 /* Chipset supports background scan */
101 private final boolean mBackgroundScanSupported;
102
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800103 private final LockList mLocks = new LockList();
Eric Shienbrood5711fad2009-03-27 20:25:31 -0700104 // some wifi lock statistics
Irfan Sheriff5876a422010-08-12 20:26:23 -0700105 private int mFullHighPerfLocksAcquired;
106 private int mFullHighPerfLocksReleased;
Eric Shienbrood5711fad2009-03-27 20:25:31 -0700107 private int mFullLocksAcquired;
108 private int mFullLocksReleased;
109 private int mScanLocksAcquired;
110 private int mScanLocksReleased;
The Android Open Source Project10592532009-03-18 17:39:46 -0700111
Robert Greenwalt58ff0212009-05-19 15:53:54 -0700112 private final List<Multicaster> mMulticasters =
113 new ArrayList<Multicaster>();
Robert Greenwalt5347bd42009-05-13 15:10:16 -0700114 private int mMulticastEnabled;
115 private int mMulticastDisabled;
116
The Android Open Source Project10592532009-03-18 17:39:46 -0700117 private final IBatteryStats mBatteryStats;
Jaikumar Ganesh084c6652009-12-07 10:58:18 -0800118
Irfan Sheriff227bec42011-02-15 19:30:27 -0800119 private boolean mEnableTrafficStatsPoll = false;
120 private int mTrafficStatsPollToken = 0;
121 private long mTxPkts;
122 private long mRxPkts;
123 /* Tracks last reported data activity */
124 private int mDataActivity;
125 private String mInterfaceName;
126
127 /**
128 * Interval in milliseconds between polling for traffic
129 * statistics
130 */
131 private static final int POLL_TRAFFIC_STATS_INTERVAL_MSECS = 1000;
132
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800133 /**
Doug Zongker43866e02010-01-07 12:09:54 -0800134 * See {@link Settings.Secure#WIFI_IDLE_MS}. This is the default value if a
135 * Settings.Secure value is not present. This timeout value is chosen as
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800136 * the approximate point at which the battery drain caused by Wi-Fi
137 * being enabled but not active exceeds the battery drain caused by
138 * re-establishing a connection to the mobile data network.
139 */
Irfan Sheriff4f5f7c92010-10-14 17:01:27 -0700140 private static final long DEFAULT_IDLE_MS = 15 * 60 * 1000; /* 15 minutes */
141
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800142 private static final String ACTION_DEVICE_IDLE =
143 "com.android.server.WifiManager.action.DEVICE_IDLE";
144
Irfan Sheriff658772f2011-03-08 14:52:31 -0800145 private static final int WIFI_DISABLED = 0;
146 private static final int WIFI_ENABLED = 1;
147 /* Wifi enabled while in airplane mode */
148 private static final int WIFI_ENABLED_AIRPLANE_OVERRIDE = 2;
149
150 private AtomicInteger mWifiState = new AtomicInteger(WIFI_DISABLED);
151 private AtomicBoolean mAirplaneModeOn = new AtomicBoolean(false);
152
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700153 private boolean mIsReceiverRegistered = false;
154
Irfan Sheriff0d255342010-07-28 09:35:20 -0700155
156 NetworkInfo mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_WIFI, 0, "WIFI", "");
157
158 // Variables relating to the 'available networks' notification
159 /**
160 * The icon to show in the 'available networks' notification. This will also
161 * be the ID of the Notification given to the NotificationManager.
162 */
163 private static final int ICON_NETWORKS_AVAILABLE =
164 com.android.internal.R.drawable.stat_notify_wifi_in_range;
165 /**
166 * When a notification is shown, we wait this amount before possibly showing it again.
167 */
168 private final long NOTIFICATION_REPEAT_DELAY_MS;
169 /**
170 * Whether the user has set the setting to show the 'available networks' notification.
171 */
172 private boolean mNotificationEnabled;
173 /**
174 * Observes the user setting to keep {@link #mNotificationEnabled} in sync.
175 */
176 private NotificationEnabledSettingObserver mNotificationEnabledSettingObserver;
177 /**
178 * The {@link System#currentTimeMillis()} must be at least this value for us
179 * to show the notification again.
180 */
181 private long mNotificationRepeatTime;
182 /**
183 * The Notification object given to the NotificationManager.
184 */
185 private Notification mNotification;
186 /**
187 * Whether the notification is being shown, as set by us. That is, if the
188 * user cancels the notification, we will not receive the callback so this
189 * will still be true. We only guarantee if this is false, then the
190 * notification is not showing.
191 */
192 private boolean mNotificationShown;
193 /**
194 * The number of continuous scans that must occur before consider the
195 * supplicant in a scanning state. This allows supplicant to associate with
196 * remembered networks that are in the scan results.
197 */
198 private static final int NUM_SCANS_BEFORE_ACTUALLY_SCANNING = 3;
199 /**
200 * The number of scans since the last network state change. When this
201 * exceeds {@link #NUM_SCANS_BEFORE_ACTUALLY_SCANNING}, we consider the
202 * supplicant to actually be scanning. When the network state changes to
203 * something other than scanning, we reset this to 0.
204 */
205 private int mNumScansSinceNetworkStateChange;
Jaikumar Ganesh7440fc22010-09-27 17:04:14 -0700206
Dianne Hackborn03f3cb02010-09-17 23:12:26 -0700207 /**
Wink Saville4b7ba092010-10-20 15:37:41 -0700208 * Asynchronous channel to WifiStateMachine
209 */
Irfan Sheriff227bec42011-02-15 19:30:27 -0800210 private AsyncChannel mWifiStateMachineChannel;
Wink Saville4b7ba092010-10-20 15:37:41 -0700211
212 /**
Irfan Sheriff227bec42011-02-15 19:30:27 -0800213 * Clients receiving asynchronous messages
Wink Saville4b7ba092010-10-20 15:37:41 -0700214 */
Irfan Sheriff227bec42011-02-15 19:30:27 -0800215 private List<AsyncChannel> mClients = new ArrayList<AsyncChannel>();
Wink Saville4b7ba092010-10-20 15:37:41 -0700216
Irfan Sheriff227bec42011-02-15 19:30:27 -0800217 /**
218 * Handles client connections
219 */
220 private class AsyncServiceHandler extends Handler {
221
222 AsyncServiceHandler(android.os.Looper looper) {
Wink Saville4b7ba092010-10-20 15:37:41 -0700223 super(looper);
Wink Saville4b7ba092010-10-20 15:37:41 -0700224 }
225
226 @Override
227 public void handleMessage(Message msg) {
228 switch (msg.what) {
229 case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: {
230 if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
Irfan Sheriff227bec42011-02-15 19:30:27 -0800231 Slog.d(TAG, "New client listening to asynchronous messages");
232 mClients.add((AsyncChannel) msg.obj);
Wink Saville4b7ba092010-10-20 15:37:41 -0700233 } else {
Irfan Sheriff227bec42011-02-15 19:30:27 -0800234 Slog.e(TAG, "Client connection failure, error=" + msg.arg1);
235 }
236 break;
237 }
238 case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION: {
239 AsyncChannel ac = new AsyncChannel();
240 ac.connect(mContext, this, msg.replyTo);
241 break;
242 }
Irfan Sheriffebe606f2011-02-24 11:39:15 -0800243 case WifiManager.CMD_ENABLE_TRAFFIC_STATS_POLL: {
Irfan Sheriff227bec42011-02-15 19:30:27 -0800244 mEnableTrafficStatsPoll = (msg.arg1 == 1);
245 mTrafficStatsPollToken++;
246 if (mEnableTrafficStatsPoll) {
247 notifyOnDataActivity();
Irfan Sheriffebe606f2011-02-24 11:39:15 -0800248 sendMessageDelayed(Message.obtain(this, WifiManager.CMD_TRAFFIC_STATS_POLL,
Irfan Sheriff227bec42011-02-15 19:30:27 -0800249 mTrafficStatsPollToken, 0), POLL_TRAFFIC_STATS_INTERVAL_MSECS);
250 }
251 break;
252 }
Irfan Sheriffebe606f2011-02-24 11:39:15 -0800253 case WifiManager.CMD_TRAFFIC_STATS_POLL: {
Irfan Sheriff227bec42011-02-15 19:30:27 -0800254 if (msg.arg1 == mTrafficStatsPollToken) {
255 notifyOnDataActivity();
Irfan Sheriffebe606f2011-02-24 11:39:15 -0800256 sendMessageDelayed(Message.obtain(this, WifiManager.CMD_TRAFFIC_STATS_POLL,
Irfan Sheriff227bec42011-02-15 19:30:27 -0800257 mTrafficStatsPollToken, 0), POLL_TRAFFIC_STATS_INTERVAL_MSECS);
Wink Saville4b7ba092010-10-20 15:37:41 -0700258 }
259 break;
260 }
Irfan Sheriffebe606f2011-02-24 11:39:15 -0800261 case WifiManager.CMD_CONNECT_NETWORK: {
262 if (msg.obj != null) {
263 mWifiStateMachine.connectNetwork((WifiConfiguration)msg.obj);
264 } else {
265 mWifiStateMachine.connectNetwork(msg.arg1);
266 }
267 break;
268 }
269 case WifiManager.CMD_SAVE_NETWORK: {
270 mWifiStateMachine.saveNetwork((WifiConfiguration)msg.obj);
271 break;
272 }
273 case WifiManager.CMD_FORGET_NETWORK: {
274 mWifiStateMachine.forgetNetwork(msg.arg1);
275 break;
276 }
277 case WifiManager.CMD_START_WPS: {
278 //replyTo has the original source
279 mWifiStateMachine.startWps(msg.replyTo, (WpsConfiguration)msg.obj);
280 break;
281 }
Wink Saville4b7ba092010-10-20 15:37:41 -0700282 default: {
283 Slog.d(TAG, "WifiServicehandler.handleMessage ignoring msg=" + msg);
284 break;
285 }
286 }
287 }
288 }
Irfan Sheriff227bec42011-02-15 19:30:27 -0800289 private AsyncServiceHandler mAsyncServiceHandler;
290
291 /**
292 * Handles interaction with WifiStateMachine
293 */
294 private class WifiStateMachineHandler extends Handler {
295 private AsyncChannel mWsmChannel;
296
297 WifiStateMachineHandler(android.os.Looper looper) {
298 super(looper);
299 mWsmChannel = new AsyncChannel();
300 mWsmChannel.connect(mContext, this, mWifiStateMachine.getHandler());
301 }
302
303 @Override
304 public void handleMessage(Message msg) {
305 switch (msg.what) {
306 case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: {
307 if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
308 mWifiStateMachineChannel = mWsmChannel;
309 } else {
310 Slog.e(TAG, "WifiStateMachine connection failure, error=" + msg.arg1);
311 mWifiStateMachineChannel = null;
312 }
313 break;
314 }
315 default: {
316 Slog.d(TAG, "WifiStateMachineHandler.handleMessage ignoring msg=" + msg);
317 break;
318 }
319 }
320 }
321 }
322 WifiStateMachineHandler mWifiStateMachineHandler;
Wink Saville4b7ba092010-10-20 15:37:41 -0700323
324 /**
Dianne Hackborn03f3cb02010-09-17 23:12:26 -0700325 * Temporary for computing UIDS that are responsible for starting WIFI.
326 * Protected by mWifiStateTracker lock.
327 */
328 private final WorkSource mTmpWorkSource = new WorkSource();
Irfan Sheriff0d255342010-07-28 09:35:20 -0700329
330 WifiService(Context context) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800331 mContext = context;
Irfan Sheriff227bec42011-02-15 19:30:27 -0800332
333 mInterfaceName = SystemProperties.get("wifi.interface", "wlan0");
334
335 mWifiStateMachine = new WifiStateMachine(mContext, mInterfaceName);
Irfan Sheriff0d255342010-07-28 09:35:20 -0700336 mWifiStateMachine.enableRssiPolling(true);
The Android Open Source Project10592532009-03-18 17:39:46 -0700337 mBatteryStats = BatteryStatsService.getService();
Jaikumar Ganesh084c6652009-12-07 10:58:18 -0800338
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800339 mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
340 Intent idleIntent = new Intent(ACTION_DEVICE_IDLE, null);
341 mIdleIntent = PendingIntent.getBroadcast(mContext, IDLE_REQUEST, idleIntent, 0);
342
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800343 mContext.registerReceiver(
344 new BroadcastReceiver() {
345 @Override
346 public void onReceive(Context context, Intent intent) {
Irfan Sheriff658772f2011-03-08 14:52:31 -0800347 mAirplaneModeOn.set(isAirplaneModeOn());
348 /* On airplane mode disable, restore wifi state if necessary */
349 if (!mAirplaneModeOn.get() && (testAndClearWifiSavedState() ||
350 mWifiState.get() == WIFI_ENABLED_AIRPLANE_OVERRIDE)) {
351 persistWifiEnabled(true);
Irfan Sheriffb2e6c012010-04-05 11:57:56 -0700352 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800353 updateWifiState();
354 }
355 },
356 new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED));
357
Irfan Sheriff0d255342010-07-28 09:35:20 -0700358 IntentFilter filter = new IntentFilter();
359 filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
360 filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
361 filter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
362
363 mContext.registerReceiver(
364 new BroadcastReceiver() {
365 @Override
366 public void onReceive(Context context, Intent intent) {
367 if (intent.getAction().equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) {
368 // reset & clear notification on any wifi state change
369 resetNotification();
370 } else if (intent.getAction().equals(
371 WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
372 mNetworkInfo = (NetworkInfo) intent.getParcelableExtra(
373 WifiManager.EXTRA_NETWORK_INFO);
374 // reset & clear notification on a network connect & disconnect
375 switch(mNetworkInfo.getDetailedState()) {
376 case CONNECTED:
377 case DISCONNECTED:
Irfan Sheriff227bec42011-02-15 19:30:27 -0800378 evaluateTrafficStatsPolling();
Irfan Sheriff0d255342010-07-28 09:35:20 -0700379 resetNotification();
380 break;
381 }
382 } else if (intent.getAction().equals(
383 WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) {
384 checkAndSetNotification();
385 }
386 }
387 }, filter);
388
Irfan Sheriff227bec42011-02-15 19:30:27 -0800389 HandlerThread wifiThread = new HandlerThread("WifiService");
390 wifiThread.start();
391 mAsyncServiceHandler = new AsyncServiceHandler(wifiThread.getLooper());
392 mWifiStateMachineHandler = new WifiStateMachineHandler(wifiThread.getLooper());
393
Irfan Sheriff0d255342010-07-28 09:35:20 -0700394 // Setting is in seconds
395 NOTIFICATION_REPEAT_DELAY_MS = Settings.Secure.getInt(context.getContentResolver(),
396 Settings.Secure.WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY, 900) * 1000l;
397 mNotificationEnabledSettingObserver = new NotificationEnabledSettingObserver(new Handler());
398 mNotificationEnabledSettingObserver.register();
Irfan Sherifffcc08452011-02-17 16:44:54 -0800399
400 mBackgroundScanSupported = mContext.getResources().getBoolean(
401 com.android.internal.R.bool.config_wifi_background_scan_support);
Irfan Sheriff7b009782010-03-11 16:37:45 -0800402 }
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800403
Irfan Sheriff7b009782010-03-11 16:37:45 -0800404 /**
405 * Check if Wi-Fi needs to be enabled and start
406 * if needed
Irfan Sheriff60e3ba02010-04-02 12:18:45 -0700407 *
408 * This function is used only at boot time
Irfan Sheriff7b009782010-03-11 16:37:45 -0800409 */
Irfan Sheriff0d255342010-07-28 09:35:20 -0700410 public void checkAndStartWifi() {
Irfan Sheriff658772f2011-03-08 14:52:31 -0800411 mAirplaneModeOn.set(isAirplaneModeOn());
412 mWifiState.set(getPersistedWifiState());
413 /* Start if Wi-Fi should be enabled or the saved state indicates Wi-Fi was on */
414 boolean wifiEnabled = shouldWifiBeEnabled() || testAndClearWifiSavedState();
Irfan Sheriff7b009782010-03-11 16:37:45 -0800415 Slog.i(TAG, "WifiService starting up with Wi-Fi " +
416 (wifiEnabled ? "enabled" : "disabled"));
Irfan Sheriffb99fe5e2010-03-26 14:56:07 -0700417 setWifiEnabled(wifiEnabled);
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800418 }
419
Irfan Sheriffa3bd4092010-03-24 17:58:59 -0700420 private boolean testAndClearWifiSavedState() {
421 final ContentResolver cr = mContext.getContentResolver();
422 int wifiSavedState = 0;
423 try {
424 wifiSavedState = Settings.Secure.getInt(cr, Settings.Secure.WIFI_SAVED_STATE);
425 if(wifiSavedState == 1)
426 Settings.Secure.putInt(cr, Settings.Secure.WIFI_SAVED_STATE, 0);
427 } catch (Settings.SettingNotFoundException e) {
428 ;
429 }
430 return (wifiSavedState == 1);
431 }
432
Irfan Sheriff658772f2011-03-08 14:52:31 -0800433 private int getPersistedWifiState() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800434 final ContentResolver cr = mContext.getContentResolver();
435 try {
Irfan Sheriff658772f2011-03-08 14:52:31 -0800436 return Settings.Secure.getInt(cr, Settings.Secure.WIFI_ON);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800437 } catch (Settings.SettingNotFoundException e) {
Irfan Sheriff658772f2011-03-08 14:52:31 -0800438 Settings.Secure.putInt(cr, Settings.Secure.WIFI_ON, WIFI_DISABLED);
439 return WIFI_DISABLED;
440 }
441 }
442
443 private boolean shouldWifiBeEnabled() {
444 if (mAirplaneModeOn.get()) {
445 return mWifiState.get() == WIFI_ENABLED_AIRPLANE_OVERRIDE;
446 } else {
447 return mWifiState.get() != WIFI_DISABLED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800448 }
449 }
450
451 private void persistWifiEnabled(boolean enabled) {
452 final ContentResolver cr = mContext.getContentResolver();
Irfan Sheriff658772f2011-03-08 14:52:31 -0800453 if (enabled) {
454 if (isAirplaneModeOn() && isAirplaneToggleable()) {
455 mWifiState.set(WIFI_ENABLED_AIRPLANE_OVERRIDE);
456 } else {
457 mWifiState.set(WIFI_ENABLED);
458 }
459 } else {
460 mWifiState.set(WIFI_DISABLED);
461 }
462 Settings.Secure.putInt(cr, Settings.Secure.WIFI_ON, mWifiState.get());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800463 }
464
Irfan Sheriff658772f2011-03-08 14:52:31 -0800465
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800466 /**
467 * see {@link android.net.wifi.WifiManager#pingSupplicant()}
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700468 * @return {@code true} if the operation succeeds, {@code false} otherwise
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800469 */
470 public boolean pingSupplicant() {
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700471 enforceAccessPermission();
Irfan Sheriff227bec42011-02-15 19:30:27 -0800472 if (mWifiStateMachineChannel != null) {
473 return mWifiStateMachine.syncPingSupplicant(mWifiStateMachineChannel);
Irfan Sheriff1406bcb2010-10-28 14:41:39 -0700474 } else {
Irfan Sheriff227bec42011-02-15 19:30:27 -0800475 Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
Irfan Sheriff1406bcb2010-10-28 14:41:39 -0700476 return false;
477 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800478 }
479
480 /**
481 * see {@link android.net.wifi.WifiManager#startScan()}
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800482 */
Irfan Sheriffe4984752010-08-19 11:29:22 -0700483 public void startScan(boolean forceActive) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800484 enforceChangePermission();
Irfan Sheriffe4984752010-08-19 11:29:22 -0700485 mWifiStateMachine.startScan(forceActive);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800486 }
487
488 private void enforceAccessPermission() {
489 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_WIFI_STATE,
490 "WifiService");
491 }
492
493 private void enforceChangePermission() {
494 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CHANGE_WIFI_STATE,
495 "WifiService");
496
497 }
498
Robert Greenwaltfc1b15c2009-05-22 15:09:51 -0700499 private void enforceMulticastChangePermission() {
500 mContext.enforceCallingOrSelfPermission(
501 android.Manifest.permission.CHANGE_WIFI_MULTICAST_STATE,
502 "WifiService");
503 }
504
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800505 /**
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700506 * see {@link android.net.wifi.WifiManager#setWifiEnabled(boolean)}
507 * @param enable {@code true} to enable, {@code false} to disable.
508 * @return {@code true} if the enable/disable operation was
509 * started or is already in the queue.
510 */
511 public synchronized boolean setWifiEnabled(boolean enable) {
512 enforceChangePermission();
513
514 if (DBG) {
Irfan Sheriff0d255342010-07-28 09:35:20 -0700515 Slog.e(TAG, "Invoking mWifiStateMachine.setWifiEnabled\n");
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700516 }
517
Dianne Hackborn03f3cb02010-09-17 23:12:26 -0700518 if (enable) {
519 reportStartWorkSource();
520 }
Irfan Sheriff0d255342010-07-28 09:35:20 -0700521 mWifiStateMachine.setWifiEnabled(enable);
Irfan Sheriff61180692010-08-18 16:07:39 -0700522
523 /*
524 * Caller might not have WRITE_SECURE_SETTINGS,
525 * only CHANGE_WIFI_STATE is enforced
526 */
527 long ident = Binder.clearCallingIdentity();
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700528 persistWifiEnabled(enable);
Irfan Sheriff61180692010-08-18 16:07:39 -0700529 Binder.restoreCallingIdentity(ident);
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700530
531 if (enable) {
532 if (!mIsReceiverRegistered) {
533 registerForBroadcasts();
534 mIsReceiverRegistered = true;
535 }
536 } else if (mIsReceiverRegistered){
537 mContext.unregisterReceiver(mReceiver);
538 mIsReceiverRegistered = false;
539 }
540
541 return true;
542 }
543
544 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800545 * see {@link WifiManager#getWifiState()}
546 * @return One of {@link WifiManager#WIFI_STATE_DISABLED},
547 * {@link WifiManager#WIFI_STATE_DISABLING},
548 * {@link WifiManager#WIFI_STATE_ENABLED},
549 * {@link WifiManager#WIFI_STATE_ENABLING},
550 * {@link WifiManager#WIFI_STATE_UNKNOWN}
551 */
552 public int getWifiEnabledState() {
553 enforceAccessPermission();
Irfan Sheriffd8134ff2010-08-22 17:06:34 -0700554 return mWifiStateMachine.syncGetWifiState();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800555 }
556
557 /**
Irfan Sheriffc2f54c22010-03-18 14:02:22 -0700558 * see {@link android.net.wifi.WifiManager#setWifiApEnabled(WifiConfiguration, boolean)}
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800559 * @param wifiConfig SSID, security and channel details as
560 * part of WifiConfiguration
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700561 * @param enabled true to enable and false to disable
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800562 * @return {@code true} if the start operation was
563 * started or is already in the queue.
564 */
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700565 public synchronized boolean setWifiApEnabled(WifiConfiguration wifiConfig, boolean enabled) {
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800566 enforceChangePermission();
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800567
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700568 if (enabled) {
569 /* Use default config if there is no existing config */
570 if (wifiConfig == null && ((wifiConfig = getWifiApConfiguration()) == null)) {
571 wifiConfig = new WifiConfiguration();
572 wifiConfig.SSID = mContext.getString(R.string.wifi_tether_configure_ssid_default);
573 wifiConfig.allowedKeyManagement.set(KeyMgmt.NONE);
574 }
Irfan Sheriff61180692010-08-18 16:07:39 -0700575 /*
576 * Caller might not have WRITE_SECURE_SETTINGS,
577 * only CHANGE_WIFI_STATE is enforced
578 */
579 long ident = Binder.clearCallingIdentity();
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700580 setWifiApConfiguration(wifiConfig);
Irfan Sheriff61180692010-08-18 16:07:39 -0700581 Binder.restoreCallingIdentity(ident);
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800582 }
583
Irfan Sheriff0d255342010-07-28 09:35:20 -0700584 mWifiStateMachine.setWifiApEnabled(wifiConfig, enabled);
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700585
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800586 return true;
587 }
588
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700589 /**
590 * see {@link WifiManager#getWifiApState()}
591 * @return One of {@link WifiManager#WIFI_AP_STATE_DISABLED},
592 * {@link WifiManager#WIFI_AP_STATE_DISABLING},
593 * {@link WifiManager#WIFI_AP_STATE_ENABLED},
594 * {@link WifiManager#WIFI_AP_STATE_ENABLING},
595 * {@link WifiManager#WIFI_AP_STATE_FAILED}
596 */
597 public int getWifiApEnabledState() {
Irfan Sheriff17b232b2010-06-24 11:32:26 -0700598 enforceAccessPermission();
Irfan Sheriffd8134ff2010-08-22 17:06:34 -0700599 return mWifiStateMachine.syncGetWifiApState();
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700600 }
601
602 /**
603 * see {@link WifiManager#getWifiApConfiguration()}
604 * @return soft access point configuration
605 */
606 public synchronized WifiConfiguration getWifiApConfiguration() {
Irfan Sheriff9ab518ad2010-03-12 15:48:17 -0800607 final ContentResolver cr = mContext.getContentResolver();
608 WifiConfiguration wifiConfig = new WifiConfiguration();
609 int authType;
610 try {
611 wifiConfig.SSID = Settings.Secure.getString(cr, Settings.Secure.WIFI_AP_SSID);
612 if (wifiConfig.SSID == null)
613 return null;
614 authType = Settings.Secure.getInt(cr, Settings.Secure.WIFI_AP_SECURITY);
615 wifiConfig.allowedKeyManagement.set(authType);
616 wifiConfig.preSharedKey = Settings.Secure.getString(cr, Settings.Secure.WIFI_AP_PASSWD);
617 return wifiConfig;
618 } catch (Settings.SettingNotFoundException e) {
619 Slog.e(TAG,"AP settings not found, returning");
620 return null;
621 }
622 }
623
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700624 /**
625 * see {@link WifiManager#setWifiApConfiguration(WifiConfiguration)}
626 * @param wifiConfig WifiConfiguration details for soft access point
627 */
628 public synchronized void setWifiApConfiguration(WifiConfiguration wifiConfig) {
Irfan Sheriff17b232b2010-06-24 11:32:26 -0700629 enforceChangePermission();
Irfan Sheriff9ab518ad2010-03-12 15:48:17 -0800630 final ContentResolver cr = mContext.getContentResolver();
Irfan Sheriff9ab518ad2010-03-12 15:48:17 -0800631 if (wifiConfig == null)
632 return;
Irfan Sheriffec8d23a2011-02-16 17:00:33 -0800633 int authType = wifiConfig.getAuthType();
Irfan Sheriff9ab518ad2010-03-12 15:48:17 -0800634 Settings.Secure.putString(cr, Settings.Secure.WIFI_AP_SSID, wifiConfig.SSID);
Irfan Sheriffec8d23a2011-02-16 17:00:33 -0800635 Settings.Secure.putInt(cr, Settings.Secure.WIFI_AP_SECURITY, authType);
636 if (authType != KeyMgmt.NONE)
Irfan Sheriff9ab518ad2010-03-12 15:48:17 -0800637 Settings.Secure.putString(cr, Settings.Secure.WIFI_AP_PASSWD, wifiConfig.preSharedKey);
638 }
639
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800640 /**
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700641 * see {@link android.net.wifi.WifiManager#disconnect()}
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800642 */
Irfan Sheriffe4984752010-08-19 11:29:22 -0700643 public void disconnect() {
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700644 enforceChangePermission();
Irfan Sheriffe4984752010-08-19 11:29:22 -0700645 mWifiStateMachine.disconnectCommand();
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800646 }
647
648 /**
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700649 * see {@link android.net.wifi.WifiManager#reconnect()}
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800650 */
Irfan Sheriffe4984752010-08-19 11:29:22 -0700651 public void reconnect() {
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700652 enforceChangePermission();
Irfan Sheriffe4984752010-08-19 11:29:22 -0700653 mWifiStateMachine.reconnectCommand();
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800654 }
655
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700656 /**
657 * see {@link android.net.wifi.WifiManager#reassociate()}
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700658 */
Irfan Sheriffe4984752010-08-19 11:29:22 -0700659 public void reassociate() {
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700660 enforceChangePermission();
Irfan Sheriffe4984752010-08-19 11:29:22 -0700661 mWifiStateMachine.reassociateCommand();
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800662 }
663
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800664 /**
665 * see {@link android.net.wifi.WifiManager#getConfiguredNetworks()}
666 * @return the list of configured networks
667 */
668 public List<WifiConfiguration> getConfiguredNetworks() {
669 enforceAccessPermission();
Irfan Sheriffd8134ff2010-08-22 17:06:34 -0700670 return mWifiStateMachine.syncGetConfiguredNetworks();
Chung-yih Wanga8d15942009-10-09 11:01:49 +0800671 }
672
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800673 /**
674 * see {@link android.net.wifi.WifiManager#addOrUpdateNetwork(WifiConfiguration)}
675 * @return the supplicant-assigned identifier for the new or updated
676 * network if the operation succeeds, or {@code -1} if it fails
677 */
Irfan Sheriff7aac5542009-12-22 21:42:17 -0800678 public int addOrUpdateNetwork(WifiConfiguration config) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800679 enforceChangePermission();
Irfan Sheriff227bec42011-02-15 19:30:27 -0800680 if (mWifiStateMachineChannel != null) {
681 return mWifiStateMachine.syncAddOrUpdateNetwork(mWifiStateMachineChannel, config);
Irfan Sheriff1406bcb2010-10-28 14:41:39 -0700682 } else {
Irfan Sheriff227bec42011-02-15 19:30:27 -0800683 Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
Irfan Sheriff1406bcb2010-10-28 14:41:39 -0700684 return -1;
685 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800686 }
687
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700688 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800689 * See {@link android.net.wifi.WifiManager#removeNetwork(int)}
690 * @param netId the integer that identifies the network configuration
691 * to the supplicant
692 * @return {@code true} if the operation succeeded
693 */
694 public boolean removeNetwork(int netId) {
695 enforceChangePermission();
Irfan Sheriff227bec42011-02-15 19:30:27 -0800696 if (mWifiStateMachineChannel != null) {
697 return mWifiStateMachine.syncRemoveNetwork(mWifiStateMachineChannel, netId);
Wink Saville4b7ba092010-10-20 15:37:41 -0700698 } else {
Irfan Sheriff227bec42011-02-15 19:30:27 -0800699 Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
Wink Saville4b7ba092010-10-20 15:37:41 -0700700 return false;
701 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800702 }
703
704 /**
705 * See {@link android.net.wifi.WifiManager#enableNetwork(int, boolean)}
706 * @param netId the integer that identifies the network configuration
707 * to the supplicant
708 * @param disableOthers if true, disable all other networks.
709 * @return {@code true} if the operation succeeded
710 */
711 public boolean enableNetwork(int netId, boolean disableOthers) {
712 enforceChangePermission();
Irfan Sheriff227bec42011-02-15 19:30:27 -0800713 if (mWifiStateMachineChannel != null) {
714 return mWifiStateMachine.syncEnableNetwork(mWifiStateMachineChannel, netId,
715 disableOthers);
Irfan Sheriff1406bcb2010-10-28 14:41:39 -0700716 } else {
Irfan Sheriff227bec42011-02-15 19:30:27 -0800717 Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
Irfan Sheriff1406bcb2010-10-28 14:41:39 -0700718 return false;
719 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800720 }
721
722 /**
723 * See {@link android.net.wifi.WifiManager#disableNetwork(int)}
724 * @param netId the integer that identifies the network configuration
725 * to the supplicant
726 * @return {@code true} if the operation succeeded
727 */
728 public boolean disableNetwork(int netId) {
729 enforceChangePermission();
Irfan Sheriff227bec42011-02-15 19:30:27 -0800730 if (mWifiStateMachineChannel != null) {
731 return mWifiStateMachine.syncDisableNetwork(mWifiStateMachineChannel, netId);
Irfan Sheriff1406bcb2010-10-28 14:41:39 -0700732 } else {
Irfan Sheriff227bec42011-02-15 19:30:27 -0800733 Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
Irfan Sheriff1406bcb2010-10-28 14:41:39 -0700734 return false;
735 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800736 }
737
738 /**
739 * See {@link android.net.wifi.WifiManager#getConnectionInfo()}
740 * @return the Wi-Fi information, contained in {@link WifiInfo}.
741 */
742 public WifiInfo getConnectionInfo() {
743 enforceAccessPermission();
744 /*
745 * Make sure we have the latest information, by sending
746 * a status request to the supplicant.
747 */
Irfan Sheriffd8134ff2010-08-22 17:06:34 -0700748 return mWifiStateMachine.syncRequestConnectionInfo();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800749 }
750
751 /**
752 * Return the results of the most recent access point scan, in the form of
753 * a list of {@link ScanResult} objects.
754 * @return the list of results
755 */
756 public List<ScanResult> getScanResults() {
757 enforceAccessPermission();
Irfan Sheriffd8134ff2010-08-22 17:06:34 -0700758 return mWifiStateMachine.syncGetScanResultsList();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800759 }
760
761 /**
762 * Tell the supplicant to persist the current list of configured networks.
763 * @return {@code true} if the operation succeeded
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700764 *
765 * TODO: deprecate this
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800766 */
767 public boolean saveConfiguration() {
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700768 boolean result = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800769 enforceChangePermission();
Irfan Sheriff227bec42011-02-15 19:30:27 -0800770 if (mWifiStateMachineChannel != null) {
771 return mWifiStateMachine.syncSaveConfig(mWifiStateMachineChannel);
Irfan Sheriff1406bcb2010-10-28 14:41:39 -0700772 } else {
Irfan Sheriff227bec42011-02-15 19:30:27 -0800773 Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
Irfan Sheriff1406bcb2010-10-28 14:41:39 -0700774 return false;
775 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800776 }
777
778 /**
Irfan Sheriffed4f28b2010-10-29 15:32:10 -0700779 * Set the country code
780 * @param countryCode ISO 3166 country code.
Robert Greenwaltb5010cc2009-05-21 15:11:40 -0700781 * @param persist {@code true} if the setting should be remembered.
Irfan Sheriffed4f28b2010-10-29 15:32:10 -0700782 *
783 * The persist behavior exists so that wifi can fall back to the last
784 * persisted country code on a restart, when the locale information is
785 * not available from telephony.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800786 */
Irfan Sheriffed4f28b2010-10-29 15:32:10 -0700787 public void setCountryCode(String countryCode, boolean persist) {
788 Slog.i(TAG, "WifiService trying to set country code to " + countryCode +
789 " with persist set to " + persist);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800790 enforceChangePermission();
Irfan Sheriffed4f28b2010-10-29 15:32:10 -0700791 mWifiStateMachine.setCountryCode(countryCode, persist);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800792 }
793
794 /**
Irfan Sheriff36f74132010-11-04 16:57:37 -0700795 * Set the operational frequency band
796 * @param band One of
797 * {@link WifiManager#WIFI_FREQUENCY_BAND_AUTO},
798 * {@link WifiManager#WIFI_FREQUENCY_BAND_5GHZ},
799 * {@link WifiManager#WIFI_FREQUENCY_BAND_2GHZ},
800 * @param persist {@code true} if the setting should be remembered.
801 *
802 */
803 public void setFrequencyBand(int band, boolean persist) {
804 enforceChangePermission();
805 if (!isDualBandSupported()) return;
806 Slog.i(TAG, "WifiService trying to set frequency band to " + band +
807 " with persist set to " + persist);
808 mWifiStateMachine.setFrequencyBand(band, persist);
809 }
810
811
812 /**
813 * Get the operational frequency band
814 */
815 public int getFrequencyBand() {
816 enforceAccessPermission();
817 return mWifiStateMachine.getFrequencyBand();
818 }
819
820 public boolean isDualBandSupported() {
821 //TODO: Should move towards adding a driver API that checks at runtime
822 return mContext.getResources().getBoolean(
823 com.android.internal.R.bool.config_wifi_dual_band_support);
824 }
825
826 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800827 * Return the DHCP-assigned addresses from the last successful DHCP request,
828 * if any.
829 * @return the DHCP information
830 */
831 public DhcpInfo getDhcpInfo() {
832 enforceAccessPermission();
Irfan Sheriffd8134ff2010-08-22 17:06:34 -0700833 return mWifiStateMachine.syncGetDhcpInfo();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800834 }
835
Irfan Sheriff0d255342010-07-28 09:35:20 -0700836 /**
837 * see {@link android.net.wifi.WifiManager#startWifi}
838 *
839 */
840 public void startWifi() {
841 enforceChangePermission();
842 /* TODO: may be add permissions for access only to connectivity service
843 * TODO: if a start issued, keep wifi alive until a stop issued irrespective
844 * of WifiLock & device idle status unless wifi enabled status is toggled
845 */
846
847 mWifiStateMachine.setDriverStart(true);
848 mWifiStateMachine.reconnectCommand();
849 }
850
851 /**
852 * see {@link android.net.wifi.WifiManager#stopWifi}
853 *
854 */
855 public void stopWifi() {
856 enforceChangePermission();
857 /* TODO: may be add permissions for access only to connectivity service
858 * TODO: if a stop is issued, wifi is brought up only by startWifi
859 * unless wifi enabled status is toggled
860 */
861 mWifiStateMachine.setDriverStart(false);
862 }
863
864
865 /**
866 * see {@link android.net.wifi.WifiManager#addToBlacklist}
867 *
868 */
869 public void addToBlacklist(String bssid) {
870 enforceChangePermission();
871
872 mWifiStateMachine.addToBlacklist(bssid);
873 }
874
875 /**
876 * see {@link android.net.wifi.WifiManager#clearBlacklist}
877 *
878 */
879 public void clearBlacklist() {
880 enforceChangePermission();
881
882 mWifiStateMachine.clearBlacklist();
883 }
884
Irfan Sheriff227bec42011-02-15 19:30:27 -0800885 /**
886 * Get a reference to handler. This is used by a client to establish
887 * an AsyncChannel communication with WifiService
888 */
889 public Messenger getMessenger() {
Irfan Sheriffebe606f2011-02-24 11:39:15 -0800890 /* Enforce the highest permissions
891 TODO: when we consider exposing the asynchronous API, think about
892 how to provide both access and change permissions seperately
893 */
Irfan Sheriff227bec42011-02-15 19:30:27 -0800894 enforceAccessPermission();
Irfan Sheriffebe606f2011-02-24 11:39:15 -0800895 enforceChangePermission();
Irfan Sheriff227bec42011-02-15 19:30:27 -0800896 return new Messenger(mAsyncServiceHandler);
897 }
898
Irfan Sheriff4aeca7c52011-03-10 16:53:33 -0800899 /**
900 * Get the IP and proxy configuration file
901 */
902 public String getConfigFile() {
903 enforceAccessPermission();
904 return mWifiStateMachine.getConfigFile();
905 }
906
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800907 private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
908 @Override
909 public void onReceive(Context context, Intent intent) {
910 String action = intent.getAction();
911
Doug Zongker43866e02010-01-07 12:09:54 -0800912 long idleMillis =
913 Settings.Secure.getLong(mContext.getContentResolver(),
Irfan Sheriff4f5f7c92010-10-14 17:01:27 -0700914 Settings.Secure.WIFI_IDLE_MS, DEFAULT_IDLE_MS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800915 int stayAwakeConditions =
Doug Zongker43866e02010-01-07 12:09:54 -0800916 Settings.System.getInt(mContext.getContentResolver(),
917 Settings.System.STAY_ON_WHILE_PLUGGED_IN, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800918 if (action.equals(Intent.ACTION_SCREEN_ON)) {
Joe Onorato431bb222010-10-18 19:13:23 -0400919 if (DBG) {
920 Slog.d(TAG, "ACTION_SCREEN_ON");
921 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800922 mAlarmManager.cancel(mIdleIntent);
923 mDeviceIdle = false;
924 mScreenOff = false;
Dianne Hackborn58e0eef2010-09-16 01:22:10 -0700925 // Once the screen is on, we are not keeping WIFI running
926 // because of any locks so clear that tracking immediately.
927 reportStartWorkSource();
Irfan Sheriff227bec42011-02-15 19:30:27 -0800928 evaluateTrafficStatsPolling();
Irfan Sheriff0d255342010-07-28 09:35:20 -0700929 mWifiStateMachine.enableRssiPolling(true);
Irfan Sherifffcc08452011-02-17 16:44:54 -0800930 if (mBackgroundScanSupported) {
931 mWifiStateMachine.enableBackgroundScan(false);
932 }
Irfan Sheriff8e86b892010-12-22 11:02:20 -0800933 mWifiStateMachine.enableAllNetworks();
Irfan Sheriff4f5f7c92010-10-14 17:01:27 -0700934 updateWifiState();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800935 } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
Joe Onorato431bb222010-10-18 19:13:23 -0400936 if (DBG) {
937 Slog.d(TAG, "ACTION_SCREEN_OFF");
938 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800939 mScreenOff = true;
Irfan Sheriff227bec42011-02-15 19:30:27 -0800940 evaluateTrafficStatsPolling();
Irfan Sheriff0d255342010-07-28 09:35:20 -0700941 mWifiStateMachine.enableRssiPolling(false);
Irfan Sherifffcc08452011-02-17 16:44:54 -0800942 if (mBackgroundScanSupported) {
943 mWifiStateMachine.enableBackgroundScan(true);
944 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800945 /*
946 * Set a timer to put Wi-Fi to sleep, but only if the screen is off
947 * AND the "stay on while plugged in" setting doesn't match the
948 * current power conditions (i.e, not plugged in, plugged in to USB,
949 * or plugged in to AC).
950 */
951 if (!shouldWifiStayAwake(stayAwakeConditions, mPluggedType)) {
Irfan Sheriffd8134ff2010-08-22 17:06:34 -0700952 WifiInfo info = mWifiStateMachine.syncRequestConnectionInfo();
San Mehatfa6c7112009-07-07 09:34:44 -0700953 if (info.getSupplicantState() != SupplicantState.COMPLETED) {
Robert Greenwalt84612ea62009-09-30 09:04:22 -0700954 // we used to go to sleep immediately, but this caused some race conditions
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700955 // we don't have time to track down for this release. Delay instead,
956 // but not as long as we would if connected (below)
Robert Greenwalt84612ea62009-09-30 09:04:22 -0700957 // TODO - fix the race conditions and switch back to the immediate turn-off
958 long triggerTime = System.currentTimeMillis() + (2*60*1000); // 2 min
Joe Onorato431bb222010-10-18 19:13:23 -0400959 if (DBG) {
960 Slog.d(TAG, "setting ACTION_DEVICE_IDLE timer for 120,000 ms");
961 }
Robert Greenwalt84612ea62009-09-30 09:04:22 -0700962 mAlarmManager.set(AlarmManager.RTC_WAKEUP, triggerTime, mIdleIntent);
963 // // do not keep Wifi awake when screen is off if Wifi is not associated
964 // mDeviceIdle = true;
965 // updateWifiState();
Mike Lockwoodd9c32bc2009-05-18 14:14:15 -0400966 } else {
967 long triggerTime = System.currentTimeMillis() + idleMillis;
Joe Onorato431bb222010-10-18 19:13:23 -0400968 if (DBG) {
969 Slog.d(TAG, "setting ACTION_DEVICE_IDLE timer for " + idleMillis
970 + "ms");
971 }
Mike Lockwoodd9c32bc2009-05-18 14:14:15 -0400972 mAlarmManager.set(AlarmManager.RTC_WAKEUP, triggerTime, mIdleIntent);
973 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800974 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800975 } else if (action.equals(ACTION_DEVICE_IDLE)) {
Joe Onorato431bb222010-10-18 19:13:23 -0400976 if (DBG) {
977 Slog.d(TAG, "got ACTION_DEVICE_IDLE");
978 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800979 mDeviceIdle = true;
Dianne Hackborn58e0eef2010-09-16 01:22:10 -0700980 reportStartWorkSource();
Irfan Sheriff4f5f7c92010-10-14 17:01:27 -0700981 updateWifiState();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800982 } else if (action.equals(Intent.ACTION_BATTERY_CHANGED)) {
983 /*
984 * Set a timer to put Wi-Fi to sleep, but only if the screen is off
985 * AND we are transitioning from a state in which the device was supposed
986 * to stay awake to a state in which it is not supposed to stay awake.
987 * If "stay awake" state is not changing, we do nothing, to avoid resetting
988 * the already-set timer.
989 */
990 int pluggedType = intent.getIntExtra("plugged", 0);
Joe Onorato431bb222010-10-18 19:13:23 -0400991 if (DBG) {
992 Slog.d(TAG, "ACTION_BATTERY_CHANGED pluggedType: " + pluggedType);
993 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800994 if (mScreenOff && shouldWifiStayAwake(stayAwakeConditions, mPluggedType) &&
995 !shouldWifiStayAwake(stayAwakeConditions, pluggedType)) {
996 long triggerTime = System.currentTimeMillis() + idleMillis;
Joe Onorato431bb222010-10-18 19:13:23 -0400997 if (DBG) {
998 Slog.d(TAG, "setting ACTION_DEVICE_IDLE timer for " + idleMillis + "ms");
999 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001000 mAlarmManager.set(AlarmManager.RTC_WAKEUP, triggerTime, mIdleIntent);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001001 }
1002 mPluggedType = pluggedType;
Irfan Sheriff65eaec82011-01-05 22:00:16 -08001003 } else if (action.equals(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED)) {
1004 int state = intent.getIntExtra(BluetoothAdapter.EXTRA_CONNECTION_STATE,
1005 BluetoothAdapter.STATE_DISCONNECTED);
1006 mWifiStateMachine.sendBluetoothAdapterStateChange(state);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001007 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001008 }
1009
1010 /**
1011 * Determines whether the Wi-Fi chipset should stay awake or be put to
1012 * sleep. Looks at the setting for the sleep policy and the current
1013 * conditions.
Jaikumar Ganesh084c6652009-12-07 10:58:18 -08001014 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001015 * @see #shouldDeviceStayAwake(int, int)
1016 */
1017 private boolean shouldWifiStayAwake(int stayAwakeConditions, int pluggedType) {
Irfan Sheriff739f6bc2011-01-28 16:43:12 -08001018 //Never sleep as long as the user has not changed the settings
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001019 int wifiSleepPolicy = Settings.System.getInt(mContext.getContentResolver(),
Irfan Sheriff96b10d62011-01-11 15:40:35 -08001020 Settings.System.WIFI_SLEEP_POLICY,
Irfan Sheriff739f6bc2011-01-28 16:43:12 -08001021 Settings.System.WIFI_SLEEP_POLICY_NEVER);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001022
1023 if (wifiSleepPolicy == Settings.System.WIFI_SLEEP_POLICY_NEVER) {
1024 // Never sleep
1025 return true;
1026 } else if ((wifiSleepPolicy == Settings.System.WIFI_SLEEP_POLICY_NEVER_WHILE_PLUGGED) &&
1027 (pluggedType != 0)) {
1028 // Never sleep while plugged, and we're plugged
1029 return true;
1030 } else {
1031 // Default
1032 return shouldDeviceStayAwake(stayAwakeConditions, pluggedType);
1033 }
1034 }
Jaikumar Ganesh084c6652009-12-07 10:58:18 -08001035
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001036 /**
1037 * Determine whether the bit value corresponding to {@code pluggedType} is set in
1038 * the bit string {@code stayAwakeConditions}. Because a {@code pluggedType} value
1039 * of {@code 0} isn't really a plugged type, but rather an indication that the
1040 * device isn't plugged in at all, there is no bit value corresponding to a
1041 * {@code pluggedType} value of {@code 0}. That is why we shift by
Ben Dodson4e8620f2010-08-25 10:55:47 -07001042 * {@code pluggedType - 1} instead of by {@code pluggedType}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001043 * @param stayAwakeConditions a bit string specifying which "plugged types" should
1044 * keep the device (and hence Wi-Fi) awake.
1045 * @param pluggedType the type of plug (USB, AC, or none) for which the check is
1046 * being made
1047 * @return {@code true} if {@code pluggedType} indicates that the device is
1048 * supposed to stay awake, {@code false} otherwise.
1049 */
1050 private boolean shouldDeviceStayAwake(int stayAwakeConditions, int pluggedType) {
1051 return (stayAwakeConditions & pluggedType) != 0;
1052 }
1053 };
1054
Dianne Hackborn03f3cb02010-09-17 23:12:26 -07001055 private synchronized void reportStartWorkSource() {
1056 mTmpWorkSource.clear();
1057 if (mDeviceIdle) {
1058 for (int i=0; i<mLocks.mList.size(); i++) {
1059 mTmpWorkSource.add(mLocks.mList.get(i).mWorkSource);
Dianne Hackborn58e0eef2010-09-16 01:22:10 -07001060 }
Dianne Hackborn58e0eef2010-09-16 01:22:10 -07001061 }
Dianne Hackborn03f3cb02010-09-17 23:12:26 -07001062 mWifiStateMachine.updateBatteryWorkSource(mTmpWorkSource);
Dianne Hackborn58e0eef2010-09-16 01:22:10 -07001063 }
Jaikumar Ganesh7440fc22010-09-27 17:04:14 -07001064
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001065 private void updateWifiState() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001066 boolean lockHeld = mLocks.hasLocks();
Irfan Sheriff5876a422010-08-12 20:26:23 -07001067 int strongestLockMode = WifiManager.WIFI_MODE_FULL;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001068 boolean wifiShouldBeStarted = !mDeviceIdle || lockHeld;
Irfan Sheriff5876a422010-08-12 20:26:23 -07001069
1070 if (lockHeld) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001071 strongestLockMode = mLocks.getStrongestLockMode();
Irfan Sheriff5876a422010-08-12 20:26:23 -07001072 }
1073 /* If device is not idle, lockmode cannot be scan only */
1074 if (!mDeviceIdle && strongestLockMode == WifiManager.WIFI_MODE_SCAN_ONLY) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001075 strongestLockMode = WifiManager.WIFI_MODE_FULL;
1076 }
1077
Irfan Sheriffa2a1b912010-06-07 09:03:04 -07001078 /* Disable tethering when airplane mode is enabled */
Irfan Sheriff658772f2011-03-08 14:52:31 -08001079 if (mAirplaneModeOn.get()) {
Irfan Sheriff0d255342010-07-28 09:35:20 -07001080 mWifiStateMachine.setWifiApEnabled(null, false);
Irfan Sheriffa2a1b912010-06-07 09:03:04 -07001081 }
Irfan Sheriffb2e6c012010-04-05 11:57:56 -07001082
Irfan Sheriff658772f2011-03-08 14:52:31 -08001083 if (shouldWifiBeEnabled()) {
Irfan Sheriffa2a1b912010-06-07 09:03:04 -07001084 if (wifiShouldBeStarted) {
Dianne Hackborn03f3cb02010-09-17 23:12:26 -07001085 reportStartWorkSource();
Irfan Sheriff0d255342010-07-28 09:35:20 -07001086 mWifiStateMachine.setWifiEnabled(true);
1087 mWifiStateMachine.setScanOnlyMode(
Irfan Sheriffa2a1b912010-06-07 09:03:04 -07001088 strongestLockMode == WifiManager.WIFI_MODE_SCAN_ONLY);
Irfan Sheriff0d255342010-07-28 09:35:20 -07001089 mWifiStateMachine.setDriverStart(true);
Irfan Sheriff5876a422010-08-12 20:26:23 -07001090 mWifiStateMachine.setHighPerfModeEnabled(strongestLockMode
1091 == WifiManager.WIFI_MODE_FULL_HIGH_PERF);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001092 } else {
Irfan Sheriff0d255342010-07-28 09:35:20 -07001093 mWifiStateMachine.requestCmWakeLock();
1094 mWifiStateMachine.setDriverStart(false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001095 }
Irfan Sheriffa2a1b912010-06-07 09:03:04 -07001096 } else {
Irfan Sheriff0d255342010-07-28 09:35:20 -07001097 mWifiStateMachine.setWifiEnabled(false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001098 }
1099 }
1100
1101 private void registerForBroadcasts() {
1102 IntentFilter intentFilter = new IntentFilter();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001103 intentFilter.addAction(Intent.ACTION_SCREEN_ON);
1104 intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
1105 intentFilter.addAction(Intent.ACTION_BATTERY_CHANGED);
1106 intentFilter.addAction(ACTION_DEVICE_IDLE);
Irfan Sheriff65eaec82011-01-05 22:00:16 -08001107 intentFilter.addAction(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001108 mContext.registerReceiver(mReceiver, intentFilter);
1109 }
Jaikumar Ganesh084c6652009-12-07 10:58:18 -08001110
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001111 private boolean isAirplaneSensitive() {
1112 String airplaneModeRadios = Settings.System.getString(mContext.getContentResolver(),
1113 Settings.System.AIRPLANE_MODE_RADIOS);
1114 return airplaneModeRadios == null
1115 || airplaneModeRadios.contains(Settings.System.RADIO_WIFI);
1116 }
1117
Mike Lockwoodbd5ddf02009-07-29 21:37:14 -07001118 private boolean isAirplaneToggleable() {
1119 String toggleableRadios = Settings.System.getString(mContext.getContentResolver(),
1120 Settings.System.AIRPLANE_MODE_TOGGLEABLE_RADIOS);
1121 return toggleableRadios != null
1122 && toggleableRadios.contains(Settings.System.RADIO_WIFI);
1123 }
1124
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001125 /**
1126 * Returns true if Wi-Fi is sensitive to airplane mode, and airplane mode is
1127 * currently on.
1128 * @return {@code true} if airplane mode is on.
1129 */
1130 private boolean isAirplaneModeOn() {
1131 return isAirplaneSensitive() && Settings.System.getInt(mContext.getContentResolver(),
1132 Settings.System.AIRPLANE_MODE_ON, 0) == 1;
1133 }
1134
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001135 @Override
1136 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1137 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
1138 != PackageManager.PERMISSION_GRANTED) {
1139 pw.println("Permission Denial: can't dump WifiService from from pid="
1140 + Binder.getCallingPid()
1141 + ", uid=" + Binder.getCallingUid());
1142 return;
1143 }
Irfan Sheriffd8134ff2010-08-22 17:06:34 -07001144 pw.println("Wi-Fi is " + mWifiStateMachine.syncGetWifiStateByName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001145 pw.println("Stay-awake conditions: " +
1146 Settings.System.getInt(mContext.getContentResolver(),
1147 Settings.System.STAY_ON_WHILE_PLUGGED_IN, 0));
1148 pw.println();
1149
1150 pw.println("Internal state:");
Irfan Sheriff0d255342010-07-28 09:35:20 -07001151 pw.println(mWifiStateMachine);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001152 pw.println();
1153 pw.println("Latest scan results:");
Irfan Sheriffd8134ff2010-08-22 17:06:34 -07001154 List<ScanResult> scanResults = mWifiStateMachine.syncGetScanResultsList();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001155 if (scanResults != null && scanResults.size() != 0) {
1156 pw.println(" BSSID Frequency RSSI Flags SSID");
1157 for (ScanResult r : scanResults) {
1158 pw.printf(" %17s %9d %5d %-16s %s%n",
1159 r.BSSID,
1160 r.frequency,
1161 r.level,
1162 r.capabilities,
1163 r.SSID == null ? "" : r.SSID);
1164 }
1165 }
1166 pw.println();
Eric Shienbrood5711fad2009-03-27 20:25:31 -07001167 pw.println("Locks acquired: " + mFullLocksAcquired + " full, " +
Irfan Sheriff5876a422010-08-12 20:26:23 -07001168 mFullHighPerfLocksAcquired + " full high perf, " +
Eric Shienbrood5711fad2009-03-27 20:25:31 -07001169 mScanLocksAcquired + " scan");
1170 pw.println("Locks released: " + mFullLocksReleased + " full, " +
Irfan Sheriff5876a422010-08-12 20:26:23 -07001171 mFullHighPerfLocksReleased + " full high perf, " +
Eric Shienbrood5711fad2009-03-27 20:25:31 -07001172 mScanLocksReleased + " scan");
1173 pw.println();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001174 pw.println("Locks held:");
1175 mLocks.dump(pw);
1176 }
1177
Robert Greenwalt58ff0212009-05-19 15:53:54 -07001178 private class WifiLock extends DeathRecipient {
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001179 WifiLock(int lockMode, String tag, IBinder binder, WorkSource ws) {
1180 super(lockMode, tag, binder, ws);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001181 }
1182
1183 public void binderDied() {
1184 synchronized (mLocks) {
1185 releaseWifiLockLocked(mBinder);
1186 }
1187 }
1188
1189 public String toString() {
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001190 return "WifiLock{" + mTag + " type=" + mMode + " binder=" + mBinder + "}";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001191 }
1192 }
1193
1194 private class LockList {
1195 private List<WifiLock> mList;
1196
1197 private LockList() {
1198 mList = new ArrayList<WifiLock>();
1199 }
1200
1201 private synchronized boolean hasLocks() {
1202 return !mList.isEmpty();
1203 }
1204
1205 private synchronized int getStrongestLockMode() {
1206 if (mList.isEmpty()) {
1207 return WifiManager.WIFI_MODE_FULL;
1208 }
Irfan Sheriff5876a422010-08-12 20:26:23 -07001209
1210 if (mFullHighPerfLocksAcquired > mFullHighPerfLocksReleased) {
1211 return WifiManager.WIFI_MODE_FULL_HIGH_PERF;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001212 }
Irfan Sheriff5876a422010-08-12 20:26:23 -07001213
1214 if (mFullLocksAcquired > mFullLocksReleased) {
1215 return WifiManager.WIFI_MODE_FULL;
1216 }
1217
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001218 return WifiManager.WIFI_MODE_SCAN_ONLY;
1219 }
1220
1221 private void addLock(WifiLock lock) {
1222 if (findLockByBinder(lock.mBinder) < 0) {
1223 mList.add(lock);
1224 }
1225 }
1226
1227 private WifiLock removeLock(IBinder binder) {
1228 int index = findLockByBinder(binder);
1229 if (index >= 0) {
Suchi Amalapurapufff2fda2009-06-30 21:36:16 -07001230 WifiLock ret = mList.remove(index);
1231 ret.unlinkDeathRecipient();
1232 return ret;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001233 } else {
1234 return null;
1235 }
1236 }
1237
1238 private int findLockByBinder(IBinder binder) {
1239 int size = mList.size();
1240 for (int i = size - 1; i >= 0; i--)
1241 if (mList.get(i).mBinder == binder)
1242 return i;
1243 return -1;
1244 }
1245
1246 private void dump(PrintWriter pw) {
1247 for (WifiLock l : mList) {
1248 pw.print(" ");
1249 pw.println(l);
1250 }
1251 }
1252 }
1253
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001254 void enforceWakeSourcePermission(int uid, int pid) {
Dianne Hackborne746f032010-09-13 16:02:57 -07001255 if (uid == android.os.Process.myUid()) {
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001256 return;
1257 }
1258 mContext.enforcePermission(android.Manifest.permission.UPDATE_DEVICE_STATS,
1259 pid, uid, null);
1260 }
1261
1262 public boolean acquireWifiLock(IBinder binder, int lockMode, String tag, WorkSource ws) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001263 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WAKE_LOCK, null);
Irfan Sheriff5876a422010-08-12 20:26:23 -07001264 if (lockMode != WifiManager.WIFI_MODE_FULL &&
1265 lockMode != WifiManager.WIFI_MODE_SCAN_ONLY &&
1266 lockMode != WifiManager.WIFI_MODE_FULL_HIGH_PERF) {
1267 Slog.e(TAG, "Illegal argument, lockMode= " + lockMode);
1268 if (DBG) throw new IllegalArgumentException("lockMode=" + lockMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001269 return false;
1270 }
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001271 if (ws != null && ws.size() == 0) {
1272 ws = null;
1273 }
Dianne Hackbornecfd7f72010-10-08 14:23:40 -07001274 if (ws != null) {
1275 enforceWakeSourcePermission(Binder.getCallingUid(), Binder.getCallingPid());
1276 }
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001277 if (ws == null) {
1278 ws = new WorkSource(Binder.getCallingUid());
1279 }
1280 WifiLock wifiLock = new WifiLock(lockMode, tag, binder, ws);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001281 synchronized (mLocks) {
1282 return acquireWifiLockLocked(wifiLock);
1283 }
1284 }
1285
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001286 private void noteAcquireWifiLock(WifiLock wifiLock) throws RemoteException {
1287 switch(wifiLock.mMode) {
1288 case WifiManager.WIFI_MODE_FULL:
Irfan Sheriff5876a422010-08-12 20:26:23 -07001289 case WifiManager.WIFI_MODE_FULL_HIGH_PERF:
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001290 mBatteryStats.noteFullWifiLockAcquiredFromSource(wifiLock.mWorkSource);
1291 break;
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001292 case WifiManager.WIFI_MODE_SCAN_ONLY:
1293 mBatteryStats.noteScanWifiLockAcquiredFromSource(wifiLock.mWorkSource);
1294 break;
1295 }
1296 }
1297
1298 private void noteReleaseWifiLock(WifiLock wifiLock) throws RemoteException {
1299 switch(wifiLock.mMode) {
1300 case WifiManager.WIFI_MODE_FULL:
Irfan Sheriff5876a422010-08-12 20:26:23 -07001301 case WifiManager.WIFI_MODE_FULL_HIGH_PERF:
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001302 mBatteryStats.noteFullWifiLockReleasedFromSource(wifiLock.mWorkSource);
1303 break;
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001304 case WifiManager.WIFI_MODE_SCAN_ONLY:
1305 mBatteryStats.noteScanWifiLockReleasedFromSource(wifiLock.mWorkSource);
1306 break;
1307 }
1308 }
1309
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001310 private boolean acquireWifiLockLocked(WifiLock wifiLock) {
Irfan Sheriffc89dd542010-09-28 08:40:54 -07001311 if (DBG) Slog.d(TAG, "acquireWifiLockLocked: " + wifiLock);
Robert Greenwaltf1acb2d2009-10-13 08:20:55 -07001312
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001313 mLocks.addLock(wifiLock);
Robert Greenwaltf1acb2d2009-10-13 08:20:55 -07001314
The Android Open Source Project10592532009-03-18 17:39:46 -07001315 long ident = Binder.clearCallingIdentity();
1316 try {
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001317 noteAcquireWifiLock(wifiLock);
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001318 switch(wifiLock.mMode) {
Eric Shienbrood5711fad2009-03-27 20:25:31 -07001319 case WifiManager.WIFI_MODE_FULL:
1320 ++mFullLocksAcquired;
Eric Shienbrood5711fad2009-03-27 20:25:31 -07001321 break;
Irfan Sheriff5876a422010-08-12 20:26:23 -07001322 case WifiManager.WIFI_MODE_FULL_HIGH_PERF:
1323 ++mFullHighPerfLocksAcquired;
1324 break;
1325
Eric Shienbrood5711fad2009-03-27 20:25:31 -07001326 case WifiManager.WIFI_MODE_SCAN_ONLY:
1327 ++mScanLocksAcquired;
Eric Shienbrood5711fad2009-03-27 20:25:31 -07001328 break;
The Android Open Source Project10592532009-03-18 17:39:46 -07001329 }
Dianne Hackbornecfd7f72010-10-08 14:23:40 -07001330
1331 // Be aggressive about adding new locks into the accounted state...
1332 // we want to over-report rather than under-report.
1333 reportStartWorkSource();
1334
1335 updateWifiState();
1336 return true;
The Android Open Source Project10592532009-03-18 17:39:46 -07001337 } catch (RemoteException e) {
Dianne Hackbornecfd7f72010-10-08 14:23:40 -07001338 return false;
The Android Open Source Project10592532009-03-18 17:39:46 -07001339 } finally {
1340 Binder.restoreCallingIdentity(ident);
1341 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001342 }
1343
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001344 public void updateWifiLockWorkSource(IBinder lock, WorkSource ws) {
1345 int uid = Binder.getCallingUid();
1346 int pid = Binder.getCallingPid();
1347 if (ws != null && ws.size() == 0) {
1348 ws = null;
1349 }
1350 if (ws != null) {
1351 enforceWakeSourcePermission(uid, pid);
1352 }
1353 long ident = Binder.clearCallingIdentity();
1354 try {
1355 synchronized (mLocks) {
1356 int index = mLocks.findLockByBinder(lock);
1357 if (index < 0) {
1358 throw new IllegalArgumentException("Wifi lock not active");
1359 }
1360 WifiLock wl = mLocks.mList.get(index);
1361 noteReleaseWifiLock(wl);
1362 wl.mWorkSource = ws != null ? new WorkSource(ws) : new WorkSource(uid);
1363 noteAcquireWifiLock(wl);
1364 }
1365 } catch (RemoteException e) {
1366 } finally {
1367 Binder.restoreCallingIdentity(ident);
1368 }
1369 }
1370
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001371 public boolean releaseWifiLock(IBinder lock) {
1372 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WAKE_LOCK, null);
1373 synchronized (mLocks) {
1374 return releaseWifiLockLocked(lock);
1375 }
1376 }
1377
1378 private boolean releaseWifiLockLocked(IBinder lock) {
Eric Shienbroodd4c5f892009-03-24 18:13:20 -07001379 boolean hadLock;
Robert Greenwaltf1acb2d2009-10-13 08:20:55 -07001380
The Android Open Source Project10592532009-03-18 17:39:46 -07001381 WifiLock wifiLock = mLocks.removeLock(lock);
Robert Greenwaltf1acb2d2009-10-13 08:20:55 -07001382
Irfan Sheriffc89dd542010-09-28 08:40:54 -07001383 if (DBG) Slog.d(TAG, "releaseWifiLockLocked: " + wifiLock);
Robert Greenwaltf1acb2d2009-10-13 08:20:55 -07001384
Eric Shienbroodd4c5f892009-03-24 18:13:20 -07001385 hadLock = (wifiLock != null);
1386
Dianne Hackbornecfd7f72010-10-08 14:23:40 -07001387 long ident = Binder.clearCallingIdentity();
1388 try {
1389 if (hadLock) {
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001390 noteAcquireWifiLock(wifiLock);
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001391 switch(wifiLock.mMode) {
Eric Shienbrood5711fad2009-03-27 20:25:31 -07001392 case WifiManager.WIFI_MODE_FULL:
1393 ++mFullLocksReleased;
Eric Shienbrood5711fad2009-03-27 20:25:31 -07001394 break;
Irfan Sheriff5876a422010-08-12 20:26:23 -07001395 case WifiManager.WIFI_MODE_FULL_HIGH_PERF:
1396 ++mFullHighPerfLocksReleased;
1397 break;
Eric Shienbrood5711fad2009-03-27 20:25:31 -07001398 case WifiManager.WIFI_MODE_SCAN_ONLY:
1399 ++mScanLocksReleased;
Eric Shienbrood5711fad2009-03-27 20:25:31 -07001400 break;
Eric Shienbroodd4c5f892009-03-24 18:13:20 -07001401 }
The Android Open Source Project10592532009-03-18 17:39:46 -07001402 }
Dianne Hackbornecfd7f72010-10-08 14:23:40 -07001403
1404 // TODO - should this only happen if you hadLock?
1405 updateWifiState();
1406
1407 } catch (RemoteException e) {
1408 } finally {
1409 Binder.restoreCallingIdentity(ident);
The Android Open Source Project10592532009-03-18 17:39:46 -07001410 }
Dianne Hackbornecfd7f72010-10-08 14:23:40 -07001411
Eric Shienbroodd4c5f892009-03-24 18:13:20 -07001412 return hadLock;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001413 }
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001414
Robert Greenwalt58ff0212009-05-19 15:53:54 -07001415 private abstract class DeathRecipient
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001416 implements IBinder.DeathRecipient {
1417 String mTag;
1418 int mMode;
1419 IBinder mBinder;
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001420 WorkSource mWorkSource;
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001421
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001422 DeathRecipient(int mode, String tag, IBinder binder, WorkSource ws) {
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001423 super();
1424 mTag = tag;
1425 mMode = mode;
1426 mBinder = binder;
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001427 mWorkSource = ws;
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001428 try {
1429 mBinder.linkToDeath(this, 0);
1430 } catch (RemoteException e) {
1431 binderDied();
1432 }
1433 }
Suchi Amalapurapufff2fda2009-06-30 21:36:16 -07001434
1435 void unlinkDeathRecipient() {
1436 mBinder.unlinkToDeath(this, 0);
1437 }
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001438 }
1439
Robert Greenwalt58ff0212009-05-19 15:53:54 -07001440 private class Multicaster extends DeathRecipient {
1441 Multicaster(String tag, IBinder binder) {
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001442 super(Binder.getCallingUid(), tag, binder, null);
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001443 }
1444
1445 public void binderDied() {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001446 Slog.e(TAG, "Multicaster binderDied");
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001447 synchronized (mMulticasters) {
1448 int i = mMulticasters.indexOf(this);
1449 if (i != -1) {
1450 removeMulticasterLocked(i, mMode);
1451 }
1452 }
1453 }
1454
1455 public String toString() {
Robert Greenwalt58ff0212009-05-19 15:53:54 -07001456 return "Multicaster{" + mTag + " binder=" + mBinder + "}";
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001457 }
1458
1459 public int getUid() {
1460 return mMode;
1461 }
1462 }
1463
Robert Greenwalte2d155a2009-10-21 14:58:34 -07001464 public void initializeMulticastFiltering() {
1465 enforceMulticastChangePermission();
Irfan Sheriffa8fbe1f2010-03-09 09:13:58 -08001466
Robert Greenwalte2d155a2009-10-21 14:58:34 -07001467 synchronized (mMulticasters) {
1468 // if anybody had requested filters be off, leave off
1469 if (mMulticasters.size() != 0) {
1470 return;
1471 } else {
Irfan Sheriff0d255342010-07-28 09:35:20 -07001472 mWifiStateMachine.startPacketFiltering();
Robert Greenwalte2d155a2009-10-21 14:58:34 -07001473 }
1474 }
1475 }
1476
Robert Greenwaltfc1b15c2009-05-22 15:09:51 -07001477 public void acquireMulticastLock(IBinder binder, String tag) {
1478 enforceMulticastChangePermission();
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001479
1480 synchronized (mMulticasters) {
1481 mMulticastEnabled++;
Robert Greenwalt58ff0212009-05-19 15:53:54 -07001482 mMulticasters.add(new Multicaster(tag, binder));
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001483 // Note that we could call stopPacketFiltering only when
1484 // our new size == 1 (first call), but this function won't
1485 // be called often and by making the stopPacket call each
1486 // time we're less fragile and self-healing.
Irfan Sheriff0d255342010-07-28 09:35:20 -07001487 mWifiStateMachine.stopPacketFiltering();
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001488 }
1489
1490 int uid = Binder.getCallingUid();
1491 Long ident = Binder.clearCallingIdentity();
1492 try {
1493 mBatteryStats.noteWifiMulticastEnabled(uid);
1494 } catch (RemoteException e) {
1495 } finally {
1496 Binder.restoreCallingIdentity(ident);
1497 }
1498 }
1499
Robert Greenwaltfc1b15c2009-05-22 15:09:51 -07001500 public void releaseMulticastLock() {
1501 enforceMulticastChangePermission();
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001502
1503 int uid = Binder.getCallingUid();
1504 synchronized (mMulticasters) {
1505 mMulticastDisabled++;
1506 int size = mMulticasters.size();
1507 for (int i = size - 1; i >= 0; i--) {
Robert Greenwalt58ff0212009-05-19 15:53:54 -07001508 Multicaster m = mMulticasters.get(i);
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001509 if ((m != null) && (m.getUid() == uid)) {
1510 removeMulticasterLocked(i, uid);
1511 }
1512 }
1513 }
1514 }
1515
1516 private void removeMulticasterLocked(int i, int uid)
1517 {
Suchi Amalapurapufff2fda2009-06-30 21:36:16 -07001518 Multicaster removed = mMulticasters.remove(i);
Irfan Sheriffa8fbe1f2010-03-09 09:13:58 -08001519
Suchi Amalapurapufff2fda2009-06-30 21:36:16 -07001520 if (removed != null) {
1521 removed.unlinkDeathRecipient();
1522 }
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001523 if (mMulticasters.size() == 0) {
Irfan Sheriff0d255342010-07-28 09:35:20 -07001524 mWifiStateMachine.startPacketFiltering();
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001525 }
1526
1527 Long ident = Binder.clearCallingIdentity();
1528 try {
1529 mBatteryStats.noteWifiMulticastDisabled(uid);
1530 } catch (RemoteException e) {
1531 } finally {
1532 Binder.restoreCallingIdentity(ident);
1533 }
1534 }
1535
Robert Greenwalt58ff0212009-05-19 15:53:54 -07001536 public boolean isMulticastEnabled() {
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001537 enforceAccessPermission();
1538
1539 synchronized (mMulticasters) {
1540 return (mMulticasters.size() > 0);
1541 }
1542 }
Irfan Sheriff0d255342010-07-28 09:35:20 -07001543
Irfan Sheriff227bec42011-02-15 19:30:27 -08001544 /**
1545 * Evaluate if traffic stats polling is needed based on
1546 * connection and screen on status
1547 */
1548 private void evaluateTrafficStatsPolling() {
1549 Message msg;
1550 if (mNetworkInfo.getDetailedState() == DetailedState.CONNECTED && !mScreenOff) {
Irfan Sheriffebe606f2011-02-24 11:39:15 -08001551 msg = Message.obtain(mAsyncServiceHandler,
1552 WifiManager.CMD_ENABLE_TRAFFIC_STATS_POLL, 1, 0);
Irfan Sheriff227bec42011-02-15 19:30:27 -08001553 } else {
Irfan Sheriffebe606f2011-02-24 11:39:15 -08001554 msg = Message.obtain(mAsyncServiceHandler,
1555 WifiManager.CMD_ENABLE_TRAFFIC_STATS_POLL, 0, 0);
Irfan Sheriff227bec42011-02-15 19:30:27 -08001556 }
1557 msg.sendToTarget();
1558 }
1559
1560 private void notifyOnDataActivity() {
1561 long sent, received;
1562 long preTxPkts = mTxPkts, preRxPkts = mRxPkts;
1563 int dataActivity = WifiManager.DATA_ACTIVITY_NONE;
1564
1565 mTxPkts = TrafficStats.getTxPackets(mInterfaceName);
1566 mRxPkts = TrafficStats.getRxPackets(mInterfaceName);
1567
1568 if (preTxPkts > 0 || preRxPkts > 0) {
1569 sent = mTxPkts - preTxPkts;
1570 received = mRxPkts - preRxPkts;
1571 if (sent > 0) {
1572 dataActivity |= WifiManager.DATA_ACTIVITY_OUT;
1573 }
1574 if (received > 0) {
1575 dataActivity |= WifiManager.DATA_ACTIVITY_IN;
1576 }
1577
1578 if (dataActivity != mDataActivity && !mScreenOff) {
1579 mDataActivity = dataActivity;
1580 for (AsyncChannel client : mClients) {
1581 client.sendMessage(WifiManager.DATA_ACTIVITY_NOTIFICATION, mDataActivity);
1582 }
1583 }
1584 }
1585 }
1586
1587
Irfan Sheriff0d255342010-07-28 09:35:20 -07001588 private void checkAndSetNotification() {
1589 // If we shouldn't place a notification on available networks, then
1590 // don't bother doing any of the following
1591 if (!mNotificationEnabled) return;
1592
1593 State state = mNetworkInfo.getState();
1594 if ((state == NetworkInfo.State.DISCONNECTED)
1595 || (state == NetworkInfo.State.UNKNOWN)) {
1596 // Look for an open network
Irfan Sheriffd8134ff2010-08-22 17:06:34 -07001597 List<ScanResult> scanResults = mWifiStateMachine.syncGetScanResultsList();
Irfan Sheriff0d255342010-07-28 09:35:20 -07001598 if (scanResults != null) {
1599 int numOpenNetworks = 0;
1600 for (int i = scanResults.size() - 1; i >= 0; i--) {
1601 ScanResult scanResult = scanResults.get(i);
1602
1603 if (TextUtils.isEmpty(scanResult.capabilities)) {
1604 numOpenNetworks++;
1605 }
1606 }
1607
1608 if (numOpenNetworks > 0) {
1609 if (++mNumScansSinceNetworkStateChange >= NUM_SCANS_BEFORE_ACTUALLY_SCANNING) {
1610 /*
1611 * We've scanned continuously at least
1612 * NUM_SCANS_BEFORE_NOTIFICATION times. The user
1613 * probably does not have a remembered network in range,
1614 * since otherwise supplicant would have tried to
1615 * associate and thus resetting this counter.
1616 */
1617 setNotificationVisible(true, numOpenNetworks, false, 0);
1618 }
1619 return;
1620 }
1621 }
1622 }
1623
1624 // No open networks in range, remove the notification
1625 setNotificationVisible(false, 0, false, 0);
1626 }
1627
1628 /**
1629 * Clears variables related to tracking whether a notification has been
1630 * shown recently and clears the current notification.
1631 */
1632 private void resetNotification() {
1633 mNotificationRepeatTime = 0;
1634 mNumScansSinceNetworkStateChange = 0;
1635 setNotificationVisible(false, 0, false, 0);
1636 }
1637
1638 /**
1639 * Display or don't display a notification that there are open Wi-Fi networks.
1640 * @param visible {@code true} if notification should be visible, {@code false} otherwise
1641 * @param numNetworks the number networks seen
1642 * @param force {@code true} to force notification to be shown/not-shown,
1643 * even if it is already shown/not-shown.
1644 * @param delay time in milliseconds after which the notification should be made
1645 * visible or invisible.
1646 */
1647 private void setNotificationVisible(boolean visible, int numNetworks, boolean force,
1648 int delay) {
1649
1650 // Since we use auto cancel on the notification, when the
1651 // mNetworksAvailableNotificationShown is true, the notification may
1652 // have actually been canceled. However, when it is false we know
1653 // for sure that it is not being shown (it will not be shown any other
1654 // place than here)
1655
1656 // If it should be hidden and it is already hidden, then noop
1657 if (!visible && !mNotificationShown && !force) {
1658 return;
1659 }
1660
1661 NotificationManager notificationManager = (NotificationManager) mContext
1662 .getSystemService(Context.NOTIFICATION_SERVICE);
1663
1664 Message message;
1665 if (visible) {
1666
1667 // Not enough time has passed to show the notification again
1668 if (System.currentTimeMillis() < mNotificationRepeatTime) {
1669 return;
1670 }
1671
1672 if (mNotification == null) {
Wink Savillec7a98342010-08-13 16:11:42 -07001673 // Cache the Notification object.
Irfan Sheriff0d255342010-07-28 09:35:20 -07001674 mNotification = new Notification();
1675 mNotification.when = 0;
1676 mNotification.icon = ICON_NETWORKS_AVAILABLE;
1677 mNotification.flags = Notification.FLAG_AUTO_CANCEL;
1678 mNotification.contentIntent = PendingIntent.getActivity(mContext, 0,
1679 new Intent(WifiManager.ACTION_PICK_WIFI_NETWORK), 0);
1680 }
1681
1682 CharSequence title = mContext.getResources().getQuantityText(
1683 com.android.internal.R.plurals.wifi_available, numNetworks);
1684 CharSequence details = mContext.getResources().getQuantityText(
1685 com.android.internal.R.plurals.wifi_available_detailed, numNetworks);
1686 mNotification.tickerText = title;
1687 mNotification.setLatestEventInfo(mContext, title, details, mNotification.contentIntent);
1688
1689 mNotificationRepeatTime = System.currentTimeMillis() + NOTIFICATION_REPEAT_DELAY_MS;
1690
1691 notificationManager.notify(ICON_NETWORKS_AVAILABLE, mNotification);
Irfan Sheriff0d255342010-07-28 09:35:20 -07001692 } else {
Irfan Sheriff0d255342010-07-28 09:35:20 -07001693 notificationManager.cancel(ICON_NETWORKS_AVAILABLE);
Irfan Sheriff0d255342010-07-28 09:35:20 -07001694 }
1695
Irfan Sheriff0d255342010-07-28 09:35:20 -07001696 mNotificationShown = visible;
1697 }
1698
1699 private class NotificationEnabledSettingObserver extends ContentObserver {
1700
1701 public NotificationEnabledSettingObserver(Handler handler) {
1702 super(handler);
1703 }
1704
1705 public void register() {
1706 ContentResolver cr = mContext.getContentResolver();
1707 cr.registerContentObserver(Settings.Secure.getUriFor(
1708 Settings.Secure.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON), true, this);
1709 mNotificationEnabled = getValue();
1710 }
1711
1712 @Override
1713 public void onChange(boolean selfChange) {
1714 super.onChange(selfChange);
1715
1716 mNotificationEnabled = getValue();
1717 resetNotification();
1718 }
1719
1720 private boolean getValue() {
1721 return Settings.Secure.getInt(mContext.getContentResolver(),
1722 Settings.Secure.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON, 1) == 1;
1723 }
1724 }
1725
1726
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001727}