blob: 52087854c07b5326832ac3ae28fb910c8d8a92c7 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
Irfan Sheriffa2a1b912010-06-07 09:03:04 -07002 * Copyright (C) 2010 The Android Open Source Project
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server;
18
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080019import android.app.AlarmManager;
Irfan Sheriff0d255342010-07-28 09:35:20 -070020import android.app.Notification;
21import android.app.NotificationManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080022import android.app.PendingIntent;
Jaikumar Ganesh7440fc22010-09-27 17:04:14 -070023import android.bluetooth.BluetoothAdapter;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080024import android.content.BroadcastReceiver;
25import android.content.ContentResolver;
26import android.content.Context;
27import android.content.Intent;
28import android.content.IntentFilter;
29import android.content.pm.PackageManager;
Irfan Sheriff0d255342010-07-28 09:35:20 -070030import android.database.ContentObserver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080031import android.net.wifi.IWifiManager;
Irfan Sheriff4aeca7c52011-03-10 16:53:33 -080032import android.net.wifi.ScanResult;
33import android.net.wifi.SupplicantState;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080034import android.net.wifi.WifiInfo;
35import android.net.wifi.WifiManager;
Irfan Sheriff0d255342010-07-28 09:35:20 -070036import android.net.wifi.WifiStateMachine;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080037import android.net.wifi.WifiConfiguration;
Isaac Levy654f5092011-07-13 17:41:45 -070038import android.net.wifi.WifiWatchdogStateMachine;
Irfan Sheriff9ab518ad2010-03-12 15:48:17 -080039import android.net.wifi.WifiConfiguration.KeyMgmt;
Irfan Sheriff651cdfc2011-09-07 00:31:20 -070040import android.net.wifi.WpsInfo;
Irfan Sheriffe4c56c92011-01-12 16:33:58 -080041import android.net.wifi.WpsResult;
Irfan Sheriff5321aef2010-02-12 12:35:59 -080042import android.net.ConnectivityManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080043import android.net.DhcpInfo;
Irfan Sheriff0d255342010-07-28 09:35:20 -070044import android.net.NetworkInfo;
45import android.net.NetworkInfo.State;
Irfan Sheriff227bec42011-02-15 19:30:27 -080046import android.net.NetworkInfo.DetailedState;
47import android.net.TrafficStats;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080048import android.os.Binder;
Irfan Sheriff0d255342010-07-28 09:35:20 -070049import android.os.Handler;
Irfan Sheriff227bec42011-02-15 19:30:27 -080050import android.os.Messenger;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080051import android.os.HandlerThread;
52import android.os.IBinder;
Irfan Sheriff5321aef2010-02-12 12:35:59 -080053import android.os.INetworkManagementService;
Irfan Sheriff0d255342010-07-28 09:35:20 -070054import android.os.Message;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080055import android.os.RemoteException;
Amith Yamasani47873e52009-07-02 12:05:32 -070056import android.os.ServiceManager;
Irfan Sheriff227bec42011-02-15 19:30:27 -080057import android.os.SystemProperties;
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -070058import android.os.WorkSource;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080059import android.provider.Settings;
Irfan Sheriff0d255342010-07-28 09:35:20 -070060import android.text.TextUtils;
Joe Onorato8a9b2202010-02-26 18:56:32 -080061import android.util.Slog;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080062
63import java.util.ArrayList;
Irfan Sheriff8cef0672011-12-13 17:03:59 -080064import java.util.HashMap;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080065import java.util.List;
Jaikumar Ganesh084c6652009-12-07 10:58:18 -080066import java.util.Set;
Irfan Sheriff658772f2011-03-08 14:52:31 -080067import java.util.concurrent.atomic.AtomicInteger;
Irfan Sheriffa2a1b912010-06-07 09:03:04 -070068import java.util.concurrent.atomic.AtomicBoolean;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080069import java.io.FileDescriptor;
70import java.io.PrintWriter;
71
The Android Open Source Project10592532009-03-18 17:39:46 -070072import com.android.internal.app.IBatteryStats;
Irfan Sheriff616f3172011-09-11 19:59:01 -070073import com.android.internal.telephony.TelephonyIntents;
Wink Saville4b7ba092010-10-20 15:37:41 -070074import com.android.internal.util.AsyncChannel;
The Android Open Source Project10592532009-03-18 17:39:46 -070075import com.android.server.am.BatteryStatsService;
Irfan Sheriff9ab518ad2010-03-12 15:48:17 -080076import com.android.internal.R;
The Android Open Source Project10592532009-03-18 17:39:46 -070077
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080078/**
79 * WifiService handles remote WiFi operation requests by implementing
Irfan Sheriffa2a1b912010-06-07 09:03:04 -070080 * the IWifiManager interface.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080081 *
82 * @hide
83 */
Irfan Sheriffa2a1b912010-06-07 09:03:04 -070084//TODO: Clean up multiple locks and implement WifiService
85// as a SM to track soft AP/client/adhoc bring up based
86// on device idle state, airplane mode and boot.
87
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080088public class WifiService extends IWifiManager.Stub {
89 private static final String TAG = "WifiService";
Dianne Hackborn5fd21692011-06-07 14:09:47 -070090 private static final boolean DBG = false;
Irfan Sheriffa2a1b912010-06-07 09:03:04 -070091
Irfan Sheriff0d255342010-07-28 09:35:20 -070092 private final WifiStateMachine mWifiStateMachine;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080093
94 private Context mContext;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080095
96 private AlarmManager mAlarmManager;
97 private PendingIntent mIdleIntent;
98 private static final int IDLE_REQUEST = 0;
99 private boolean mScreenOff;
100 private boolean mDeviceIdle;
Irfan Sheriff616f3172011-09-11 19:59:01 -0700101 private boolean mEmergencyCallbackMode = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800102 private int mPluggedType;
103
Irfan Sherifffcc08452011-02-17 16:44:54 -0800104 /* Chipset supports background scan */
105 private final boolean mBackgroundScanSupported;
106
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800107 private final LockList mLocks = new LockList();
Eric Shienbrood5711fad2009-03-27 20:25:31 -0700108 // some wifi lock statistics
Irfan Sheriff5876a422010-08-12 20:26:23 -0700109 private int mFullHighPerfLocksAcquired;
110 private int mFullHighPerfLocksReleased;
Eric Shienbrood5711fad2009-03-27 20:25:31 -0700111 private int mFullLocksAcquired;
112 private int mFullLocksReleased;
113 private int mScanLocksAcquired;
114 private int mScanLocksReleased;
The Android Open Source Project10592532009-03-18 17:39:46 -0700115
Irfan Sheriff8cef0672011-12-13 17:03:59 -0800116 /* A mapping from UID to scan count */
117 private HashMap<Integer, Integer> mScanCount =
118 new HashMap<Integer, Integer>();
119
Robert Greenwalt58ff0212009-05-19 15:53:54 -0700120 private final List<Multicaster> mMulticasters =
121 new ArrayList<Multicaster>();
Robert Greenwalt5347bd42009-05-13 15:10:16 -0700122 private int mMulticastEnabled;
123 private int mMulticastDisabled;
124
The Android Open Source Project10592532009-03-18 17:39:46 -0700125 private final IBatteryStats mBatteryStats;
Jaikumar Ganesh084c6652009-12-07 10:58:18 -0800126
Irfan Sheriff227bec42011-02-15 19:30:27 -0800127 private boolean mEnableTrafficStatsPoll = false;
128 private int mTrafficStatsPollToken = 0;
129 private long mTxPkts;
130 private long mRxPkts;
131 /* Tracks last reported data activity */
132 private int mDataActivity;
133 private String mInterfaceName;
134
135 /**
136 * Interval in milliseconds between polling for traffic
137 * statistics
138 */
139 private static final int POLL_TRAFFIC_STATS_INTERVAL_MSECS = 1000;
140
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800141 /**
Doug Zongker43866e02010-01-07 12:09:54 -0800142 * See {@link Settings.Secure#WIFI_IDLE_MS}. This is the default value if a
143 * Settings.Secure value is not present. This timeout value is chosen as
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800144 * the approximate point at which the battery drain caused by Wi-Fi
145 * being enabled but not active exceeds the battery drain caused by
146 * re-establishing a connection to the mobile data network.
147 */
Irfan Sheriff4f5f7c92010-10-14 17:01:27 -0700148 private static final long DEFAULT_IDLE_MS = 15 * 60 * 1000; /* 15 minutes */
149
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800150 private static final String ACTION_DEVICE_IDLE =
151 "com.android.server.WifiManager.action.DEVICE_IDLE";
152
Irfan Sheriff658772f2011-03-08 14:52:31 -0800153 private static final int WIFI_DISABLED = 0;
154 private static final int WIFI_ENABLED = 1;
155 /* Wifi enabled while in airplane mode */
156 private static final int WIFI_ENABLED_AIRPLANE_OVERRIDE = 2;
Irfan Sheriff31b92e22011-10-03 12:13:20 -0700157 /* Wifi disabled due to airplane mode on */
158 private static final int WIFI_DISABLED_AIRPLANE_ON = 3;
Irfan Sheriff658772f2011-03-08 14:52:31 -0800159
Irfan Sheriff5401f0b2011-12-07 16:27:49 -0800160 /* Persisted state that tracks the wifi & airplane interaction from settings */
161 private AtomicInteger mPersistWifiState = new AtomicInteger(WIFI_DISABLED);
162 /* Tracks current airplane mode state */
Irfan Sheriff658772f2011-03-08 14:52:31 -0800163 private AtomicBoolean mAirplaneModeOn = new AtomicBoolean(false);
Irfan Sheriff5401f0b2011-12-07 16:27:49 -0800164 /* Tracks whether wifi is enabled from WifiStateMachine's perspective */
165 private boolean mWifiEnabled;
Irfan Sheriff658772f2011-03-08 14:52:31 -0800166
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700167 private boolean mIsReceiverRegistered = false;
168
Irfan Sheriff0d255342010-07-28 09:35:20 -0700169
170 NetworkInfo mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_WIFI, 0, "WIFI", "");
171
172 // Variables relating to the 'available networks' notification
173 /**
174 * The icon to show in the 'available networks' notification. This will also
175 * be the ID of the Notification given to the NotificationManager.
176 */
177 private static final int ICON_NETWORKS_AVAILABLE =
178 com.android.internal.R.drawable.stat_notify_wifi_in_range;
179 /**
180 * When a notification is shown, we wait this amount before possibly showing it again.
181 */
182 private final long NOTIFICATION_REPEAT_DELAY_MS;
183 /**
184 * Whether the user has set the setting to show the 'available networks' notification.
185 */
186 private boolean mNotificationEnabled;
187 /**
188 * Observes the user setting to keep {@link #mNotificationEnabled} in sync.
189 */
190 private NotificationEnabledSettingObserver mNotificationEnabledSettingObserver;
191 /**
192 * The {@link System#currentTimeMillis()} must be at least this value for us
193 * to show the notification again.
194 */
195 private long mNotificationRepeatTime;
196 /**
197 * The Notification object given to the NotificationManager.
198 */
199 private Notification mNotification;
200 /**
201 * Whether the notification is being shown, as set by us. That is, if the
202 * user cancels the notification, we will not receive the callback so this
203 * will still be true. We only guarantee if this is false, then the
204 * notification is not showing.
205 */
206 private boolean mNotificationShown;
207 /**
208 * The number of continuous scans that must occur before consider the
209 * supplicant in a scanning state. This allows supplicant to associate with
210 * remembered networks that are in the scan results.
211 */
212 private static final int NUM_SCANS_BEFORE_ACTUALLY_SCANNING = 3;
213 /**
214 * The number of scans since the last network state change. When this
215 * exceeds {@link #NUM_SCANS_BEFORE_ACTUALLY_SCANNING}, we consider the
216 * supplicant to actually be scanning. When the network state changes to
217 * something other than scanning, we reset this to 0.
218 */
219 private int mNumScansSinceNetworkStateChange;
Jaikumar Ganesh7440fc22010-09-27 17:04:14 -0700220
Dianne Hackborn03f3cb02010-09-17 23:12:26 -0700221 /**
Wink Saville4b7ba092010-10-20 15:37:41 -0700222 * Asynchronous channel to WifiStateMachine
223 */
Irfan Sheriff227bec42011-02-15 19:30:27 -0800224 private AsyncChannel mWifiStateMachineChannel;
Wink Saville4b7ba092010-10-20 15:37:41 -0700225
226 /**
Irfan Sheriff227bec42011-02-15 19:30:27 -0800227 * Clients receiving asynchronous messages
Wink Saville4b7ba092010-10-20 15:37:41 -0700228 */
Irfan Sheriff227bec42011-02-15 19:30:27 -0800229 private List<AsyncChannel> mClients = new ArrayList<AsyncChannel>();
Wink Saville4b7ba092010-10-20 15:37:41 -0700230
Irfan Sheriff227bec42011-02-15 19:30:27 -0800231 /**
232 * Handles client connections
233 */
234 private class AsyncServiceHandler extends Handler {
235
236 AsyncServiceHandler(android.os.Looper looper) {
Wink Saville4b7ba092010-10-20 15:37:41 -0700237 super(looper);
Wink Saville4b7ba092010-10-20 15:37:41 -0700238 }
239
240 @Override
241 public void handleMessage(Message msg) {
242 switch (msg.what) {
243 case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: {
244 if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
Irfan Sheriff227bec42011-02-15 19:30:27 -0800245 Slog.d(TAG, "New client listening to asynchronous messages");
246 mClients.add((AsyncChannel) msg.obj);
Wink Saville4b7ba092010-10-20 15:37:41 -0700247 } else {
Irfan Sheriff227bec42011-02-15 19:30:27 -0800248 Slog.e(TAG, "Client connection failure, error=" + msg.arg1);
249 }
250 break;
251 }
Irfan Sheriffc23971b2011-03-04 17:06:31 -0800252 case AsyncChannel.CMD_CHANNEL_DISCONNECTED: {
253 if (msg.arg1 == AsyncChannel.STATUS_SEND_UNSUCCESSFUL) {
254 Slog.d(TAG, "Send failed, client connection lost");
255 } else {
256 Slog.d(TAG, "Client connection lost with reason: " + msg.arg1);
257 }
258 mClients.remove((AsyncChannel) msg.obj);
259 break;
260 }
Irfan Sheriff227bec42011-02-15 19:30:27 -0800261 case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION: {
262 AsyncChannel ac = new AsyncChannel();
263 ac.connect(mContext, this, msg.replyTo);
264 break;
265 }
Irfan Sheriffebe606f2011-02-24 11:39:15 -0800266 case WifiManager.CMD_ENABLE_TRAFFIC_STATS_POLL: {
Irfan Sheriff227bec42011-02-15 19:30:27 -0800267 mEnableTrafficStatsPoll = (msg.arg1 == 1);
268 mTrafficStatsPollToken++;
269 if (mEnableTrafficStatsPoll) {
270 notifyOnDataActivity();
Irfan Sheriffebe606f2011-02-24 11:39:15 -0800271 sendMessageDelayed(Message.obtain(this, WifiManager.CMD_TRAFFIC_STATS_POLL,
Irfan Sheriff227bec42011-02-15 19:30:27 -0800272 mTrafficStatsPollToken, 0), POLL_TRAFFIC_STATS_INTERVAL_MSECS);
273 }
274 break;
275 }
Irfan Sheriffebe606f2011-02-24 11:39:15 -0800276 case WifiManager.CMD_TRAFFIC_STATS_POLL: {
Irfan Sheriff227bec42011-02-15 19:30:27 -0800277 if (msg.arg1 == mTrafficStatsPollToken) {
278 notifyOnDataActivity();
Irfan Sheriffebe606f2011-02-24 11:39:15 -0800279 sendMessageDelayed(Message.obtain(this, WifiManager.CMD_TRAFFIC_STATS_POLL,
Irfan Sheriff227bec42011-02-15 19:30:27 -0800280 mTrafficStatsPollToken, 0), POLL_TRAFFIC_STATS_INTERVAL_MSECS);
Wink Saville4b7ba092010-10-20 15:37:41 -0700281 }
282 break;
283 }
Irfan Sheriffebe606f2011-02-24 11:39:15 -0800284 case WifiManager.CMD_CONNECT_NETWORK: {
285 if (msg.obj != null) {
286 mWifiStateMachine.connectNetwork((WifiConfiguration)msg.obj);
287 } else {
288 mWifiStateMachine.connectNetwork(msg.arg1);
289 }
290 break;
291 }
292 case WifiManager.CMD_SAVE_NETWORK: {
293 mWifiStateMachine.saveNetwork((WifiConfiguration)msg.obj);
294 break;
295 }
296 case WifiManager.CMD_FORGET_NETWORK: {
297 mWifiStateMachine.forgetNetwork(msg.arg1);
298 break;
299 }
300 case WifiManager.CMD_START_WPS: {
301 //replyTo has the original source
Irfan Sheriff651cdfc2011-09-07 00:31:20 -0700302 mWifiStateMachine.startWps(msg.replyTo, (WpsInfo)msg.obj);
Irfan Sheriffebe606f2011-02-24 11:39:15 -0800303 break;
304 }
Isaac Levy8dc6a1b2011-07-27 08:00:03 -0700305 case WifiManager.CMD_DISABLE_NETWORK: {
306 mWifiStateMachine.disableNetwork(msg.replyTo, msg.arg1, msg.arg2);
307 break;
308 }
Wink Saville4b7ba092010-10-20 15:37:41 -0700309 default: {
310 Slog.d(TAG, "WifiServicehandler.handleMessage ignoring msg=" + msg);
311 break;
312 }
313 }
314 }
315 }
Irfan Sheriff227bec42011-02-15 19:30:27 -0800316 private AsyncServiceHandler mAsyncServiceHandler;
317
318 /**
319 * Handles interaction with WifiStateMachine
320 */
321 private class WifiStateMachineHandler extends Handler {
322 private AsyncChannel mWsmChannel;
323
324 WifiStateMachineHandler(android.os.Looper looper) {
325 super(looper);
326 mWsmChannel = new AsyncChannel();
327 mWsmChannel.connect(mContext, this, mWifiStateMachine.getHandler());
328 }
329
330 @Override
331 public void handleMessage(Message msg) {
332 switch (msg.what) {
333 case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: {
334 if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
335 mWifiStateMachineChannel = mWsmChannel;
336 } else {
337 Slog.e(TAG, "WifiStateMachine connection failure, error=" + msg.arg1);
338 mWifiStateMachineChannel = null;
339 }
340 break;
341 }
Irfan Sheriff6da83d52011-06-06 12:54:06 -0700342 case AsyncChannel.CMD_CHANNEL_DISCONNECTED: {
343 Slog.e(TAG, "WifiStateMachine channel lost, msg.arg1 =" + msg.arg1);
344 mWifiStateMachineChannel = null;
345 //Re-establish connection to state machine
346 mWsmChannel.connect(mContext, this, mWifiStateMachine.getHandler());
347 break;
348 }
Irfan Sheriff227bec42011-02-15 19:30:27 -0800349 default: {
350 Slog.d(TAG, "WifiStateMachineHandler.handleMessage ignoring msg=" + msg);
351 break;
352 }
353 }
354 }
355 }
356 WifiStateMachineHandler mWifiStateMachineHandler;
Wink Saville4b7ba092010-10-20 15:37:41 -0700357
358 /**
Dianne Hackborn03f3cb02010-09-17 23:12:26 -0700359 * Temporary for computing UIDS that are responsible for starting WIFI.
360 * Protected by mWifiStateTracker lock.
361 */
362 private final WorkSource mTmpWorkSource = new WorkSource();
Isaac Levy654f5092011-07-13 17:41:45 -0700363 private WifiWatchdogStateMachine mWifiWatchdogStateMachine;
Irfan Sheriff0d255342010-07-28 09:35:20 -0700364
365 WifiService(Context context) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800366 mContext = context;
Irfan Sheriff227bec42011-02-15 19:30:27 -0800367
368 mInterfaceName = SystemProperties.get("wifi.interface", "wlan0");
369
370 mWifiStateMachine = new WifiStateMachine(mContext, mInterfaceName);
Irfan Sheriff0d255342010-07-28 09:35:20 -0700371 mWifiStateMachine.enableRssiPolling(true);
The Android Open Source Project10592532009-03-18 17:39:46 -0700372 mBatteryStats = BatteryStatsService.getService();
Jaikumar Ganesh084c6652009-12-07 10:58:18 -0800373
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800374 mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
375 Intent idleIntent = new Intent(ACTION_DEVICE_IDLE, null);
376 mIdleIntent = PendingIntent.getBroadcast(mContext, IDLE_REQUEST, idleIntent, 0);
377
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800378 mContext.registerReceiver(
379 new BroadcastReceiver() {
380 @Override
381 public void onReceive(Context context, Intent intent) {
Irfan Sheriff658772f2011-03-08 14:52:31 -0800382 mAirplaneModeOn.set(isAirplaneModeOn());
383 /* On airplane mode disable, restore wifi state if necessary */
384 if (!mAirplaneModeOn.get() && (testAndClearWifiSavedState() ||
Irfan Sheriff5401f0b2011-12-07 16:27:49 -0800385 mPersistWifiState.get() == WIFI_ENABLED_AIRPLANE_OVERRIDE)) {
386 persistWifiState(true);
Irfan Sheriffb2e6c012010-04-05 11:57:56 -0700387 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800388 updateWifiState();
389 }
390 },
391 new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED));
392
Irfan Sheriff0d255342010-07-28 09:35:20 -0700393 IntentFilter filter = new IntentFilter();
394 filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
395 filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
396 filter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
397
398 mContext.registerReceiver(
399 new BroadcastReceiver() {
400 @Override
401 public void onReceive(Context context, Intent intent) {
402 if (intent.getAction().equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) {
Irfan Sheriff5401f0b2011-12-07 16:27:49 -0800403 int wifiState = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
404 WifiManager.WIFI_STATE_DISABLED);
405
406 mWifiEnabled = (wifiState == WifiManager.WIFI_STATE_ENABLED);
407
408 // reset & clear notification on any wifi state change
Irfan Sheriff0d255342010-07-28 09:35:20 -0700409 resetNotification();
410 } else if (intent.getAction().equals(
411 WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
412 mNetworkInfo = (NetworkInfo) intent.getParcelableExtra(
413 WifiManager.EXTRA_NETWORK_INFO);
414 // reset & clear notification on a network connect & disconnect
415 switch(mNetworkInfo.getDetailedState()) {
416 case CONNECTED:
417 case DISCONNECTED:
Irfan Sheriff227bec42011-02-15 19:30:27 -0800418 evaluateTrafficStatsPolling();
Irfan Sheriff0d255342010-07-28 09:35:20 -0700419 resetNotification();
420 break;
421 }
422 } else if (intent.getAction().equals(
423 WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) {
424 checkAndSetNotification();
425 }
426 }
427 }, filter);
428
Irfan Sheriff227bec42011-02-15 19:30:27 -0800429 HandlerThread wifiThread = new HandlerThread("WifiService");
430 wifiThread.start();
431 mAsyncServiceHandler = new AsyncServiceHandler(wifiThread.getLooper());
432 mWifiStateMachineHandler = new WifiStateMachineHandler(wifiThread.getLooper());
433
Irfan Sheriff0d255342010-07-28 09:35:20 -0700434 // Setting is in seconds
435 NOTIFICATION_REPEAT_DELAY_MS = Settings.Secure.getInt(context.getContentResolver(),
436 Settings.Secure.WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY, 900) * 1000l;
437 mNotificationEnabledSettingObserver = new NotificationEnabledSettingObserver(new Handler());
438 mNotificationEnabledSettingObserver.register();
Irfan Sherifffcc08452011-02-17 16:44:54 -0800439
440 mBackgroundScanSupported = mContext.getResources().getBoolean(
441 com.android.internal.R.bool.config_wifi_background_scan_support);
Irfan Sheriff7b009782010-03-11 16:37:45 -0800442 }
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800443
Irfan Sheriff7b009782010-03-11 16:37:45 -0800444 /**
445 * Check if Wi-Fi needs to be enabled and start
446 * if needed
Irfan Sheriff60e3ba02010-04-02 12:18:45 -0700447 *
448 * This function is used only at boot time
Irfan Sheriff7b009782010-03-11 16:37:45 -0800449 */
Irfan Sheriff0d255342010-07-28 09:35:20 -0700450 public void checkAndStartWifi() {
Irfan Sheriff658772f2011-03-08 14:52:31 -0800451 mAirplaneModeOn.set(isAirplaneModeOn());
Irfan Sheriff5401f0b2011-12-07 16:27:49 -0800452 mPersistWifiState.set(getPersistedWifiState());
Irfan Sheriff658772f2011-03-08 14:52:31 -0800453 /* Start if Wi-Fi should be enabled or the saved state indicates Wi-Fi was on */
454 boolean wifiEnabled = shouldWifiBeEnabled() || testAndClearWifiSavedState();
Irfan Sheriff7b009782010-03-11 16:37:45 -0800455 Slog.i(TAG, "WifiService starting up with Wi-Fi " +
456 (wifiEnabled ? "enabled" : "disabled"));
Irfan Sheriffb99fe5e2010-03-26 14:56:07 -0700457 setWifiEnabled(wifiEnabled);
Isaac Levybc7dfb52011-06-06 15:34:01 -0700458
Isaac Levy654f5092011-07-13 17:41:45 -0700459 mWifiWatchdogStateMachine = WifiWatchdogStateMachine.
460 makeWifiWatchdogStateMachine(mContext);
461
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800462 }
463
Irfan Sheriffa3bd4092010-03-24 17:58:59 -0700464 private boolean testAndClearWifiSavedState() {
465 final ContentResolver cr = mContext.getContentResolver();
466 int wifiSavedState = 0;
467 try {
468 wifiSavedState = Settings.Secure.getInt(cr, Settings.Secure.WIFI_SAVED_STATE);
469 if(wifiSavedState == 1)
470 Settings.Secure.putInt(cr, Settings.Secure.WIFI_SAVED_STATE, 0);
471 } catch (Settings.SettingNotFoundException e) {
472 ;
473 }
474 return (wifiSavedState == 1);
475 }
476
Irfan Sheriff658772f2011-03-08 14:52:31 -0800477 private int getPersistedWifiState() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800478 final ContentResolver cr = mContext.getContentResolver();
479 try {
Irfan Sheriff658772f2011-03-08 14:52:31 -0800480 return Settings.Secure.getInt(cr, Settings.Secure.WIFI_ON);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800481 } catch (Settings.SettingNotFoundException e) {
Irfan Sheriff658772f2011-03-08 14:52:31 -0800482 Settings.Secure.putInt(cr, Settings.Secure.WIFI_ON, WIFI_DISABLED);
483 return WIFI_DISABLED;
484 }
485 }
486
487 private boolean shouldWifiBeEnabled() {
488 if (mAirplaneModeOn.get()) {
Irfan Sheriff5401f0b2011-12-07 16:27:49 -0800489 return mPersistWifiState.get() == WIFI_ENABLED_AIRPLANE_OVERRIDE;
Irfan Sheriff658772f2011-03-08 14:52:31 -0800490 } else {
Irfan Sheriff5401f0b2011-12-07 16:27:49 -0800491 return mPersistWifiState.get() != WIFI_DISABLED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800492 }
493 }
494
Irfan Sheriff5401f0b2011-12-07 16:27:49 -0800495 private void persistWifiState(boolean enabled) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800496 final ContentResolver cr = mContext.getContentResolver();
Irfan Sheriff31b92e22011-10-03 12:13:20 -0700497 boolean airplane = mAirplaneModeOn.get() && isAirplaneToggleable();
Irfan Sheriff658772f2011-03-08 14:52:31 -0800498 if (enabled) {
Irfan Sheriff31b92e22011-10-03 12:13:20 -0700499 if (airplane) {
Irfan Sheriff5401f0b2011-12-07 16:27:49 -0800500 mPersistWifiState.set(WIFI_ENABLED_AIRPLANE_OVERRIDE);
Irfan Sheriff658772f2011-03-08 14:52:31 -0800501 } else {
Irfan Sheriff5401f0b2011-12-07 16:27:49 -0800502 mPersistWifiState.set(WIFI_ENABLED);
Irfan Sheriff658772f2011-03-08 14:52:31 -0800503 }
504 } else {
Irfan Sheriff31b92e22011-10-03 12:13:20 -0700505 if (airplane) {
Irfan Sheriff5401f0b2011-12-07 16:27:49 -0800506 mPersistWifiState.set(WIFI_DISABLED_AIRPLANE_ON);
Irfan Sheriff31b92e22011-10-03 12:13:20 -0700507 } else {
Irfan Sheriff5401f0b2011-12-07 16:27:49 -0800508 mPersistWifiState.set(WIFI_DISABLED);
Irfan Sheriff31b92e22011-10-03 12:13:20 -0700509 }
Irfan Sheriff658772f2011-03-08 14:52:31 -0800510 }
Irfan Sheriff5401f0b2011-12-07 16:27:49 -0800511
512 Settings.Secure.putInt(cr, Settings.Secure.WIFI_ON, mPersistWifiState.get());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800513 }
514
Irfan Sheriff658772f2011-03-08 14:52:31 -0800515
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800516 /**
517 * see {@link android.net.wifi.WifiManager#pingSupplicant()}
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700518 * @return {@code true} if the operation succeeds, {@code false} otherwise
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800519 */
520 public boolean pingSupplicant() {
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700521 enforceAccessPermission();
Irfan Sheriff227bec42011-02-15 19:30:27 -0800522 if (mWifiStateMachineChannel != null) {
523 return mWifiStateMachine.syncPingSupplicant(mWifiStateMachineChannel);
Irfan Sheriff1406bcb2010-10-28 14:41:39 -0700524 } else {
Irfan Sheriff227bec42011-02-15 19:30:27 -0800525 Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
Irfan Sheriff1406bcb2010-10-28 14:41:39 -0700526 return false;
527 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800528 }
529
530 /**
531 * see {@link android.net.wifi.WifiManager#startScan()}
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800532 */
Irfan Sheriffe4984752010-08-19 11:29:22 -0700533 public void startScan(boolean forceActive) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800534 enforceChangePermission();
Irfan Sheriff8cef0672011-12-13 17:03:59 -0800535
536 int uid = Binder.getCallingUid();
537 int count = 0;
538 synchronized (mScanCount) {
539 if (mScanCount.containsKey(uid)) {
540 count = mScanCount.get(uid);
541 }
542 mScanCount.put(uid, ++count);
543 }
Irfan Sheriffe4984752010-08-19 11:29:22 -0700544 mWifiStateMachine.startScan(forceActive);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800545 }
546
547 private void enforceAccessPermission() {
548 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_WIFI_STATE,
549 "WifiService");
550 }
551
552 private void enforceChangePermission() {
553 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CHANGE_WIFI_STATE,
554 "WifiService");
555
556 }
557
Robert Greenwaltfc1b15c2009-05-22 15:09:51 -0700558 private void enforceMulticastChangePermission() {
559 mContext.enforceCallingOrSelfPermission(
560 android.Manifest.permission.CHANGE_WIFI_MULTICAST_STATE,
561 "WifiService");
562 }
563
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800564 /**
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700565 * see {@link android.net.wifi.WifiManager#setWifiEnabled(boolean)}
566 * @param enable {@code true} to enable, {@code false} to disable.
567 * @return {@code true} if the enable/disable operation was
568 * started or is already in the queue.
569 */
570 public synchronized boolean setWifiEnabled(boolean enable) {
571 enforceChangePermission();
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700572 if (DBG) {
Irfan Sheriff0d255342010-07-28 09:35:20 -0700573 Slog.e(TAG, "Invoking mWifiStateMachine.setWifiEnabled\n");
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700574 }
575
Dianne Hackborn03f3cb02010-09-17 23:12:26 -0700576 if (enable) {
577 reportStartWorkSource();
578 }
Irfan Sheriff0d255342010-07-28 09:35:20 -0700579 mWifiStateMachine.setWifiEnabled(enable);
Irfan Sheriff61180692010-08-18 16:07:39 -0700580
581 /*
582 * Caller might not have WRITE_SECURE_SETTINGS,
583 * only CHANGE_WIFI_STATE is enforced
584 */
Irfan Sheriff5401f0b2011-12-07 16:27:49 -0800585
586 /* Avoids overriding of airplane state when wifi is already in the expected state */
587 if (enable != mWifiEnabled) {
588 long ident = Binder.clearCallingIdentity();
589 persistWifiState(enable);
590 Binder.restoreCallingIdentity(ident);
591 }
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700592
593 if (enable) {
594 if (!mIsReceiverRegistered) {
595 registerForBroadcasts();
596 mIsReceiverRegistered = true;
597 }
Irfan Sheriff5401f0b2011-12-07 16:27:49 -0800598 } else if (mIsReceiverRegistered) {
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700599 mContext.unregisterReceiver(mReceiver);
600 mIsReceiverRegistered = false;
601 }
602
603 return true;
604 }
605
606 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800607 * see {@link WifiManager#getWifiState()}
608 * @return One of {@link WifiManager#WIFI_STATE_DISABLED},
609 * {@link WifiManager#WIFI_STATE_DISABLING},
610 * {@link WifiManager#WIFI_STATE_ENABLED},
611 * {@link WifiManager#WIFI_STATE_ENABLING},
612 * {@link WifiManager#WIFI_STATE_UNKNOWN}
613 */
614 public int getWifiEnabledState() {
615 enforceAccessPermission();
Irfan Sheriffd8134ff2010-08-22 17:06:34 -0700616 return mWifiStateMachine.syncGetWifiState();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800617 }
618
619 /**
Irfan Sheriffc2f54c22010-03-18 14:02:22 -0700620 * see {@link android.net.wifi.WifiManager#setWifiApEnabled(WifiConfiguration, boolean)}
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800621 * @param wifiConfig SSID, security and channel details as
622 * part of WifiConfiguration
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700623 * @param enabled true to enable and false to disable
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800624 */
Irfan Sheriffffcea7a2011-05-10 16:26:06 -0700625 public void setWifiApEnabled(WifiConfiguration wifiConfig, boolean enabled) {
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800626 enforceChangePermission();
Irfan Sheriff0d255342010-07-28 09:35:20 -0700627 mWifiStateMachine.setWifiApEnabled(wifiConfig, enabled);
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800628 }
629
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700630 /**
631 * see {@link WifiManager#getWifiApState()}
632 * @return One of {@link WifiManager#WIFI_AP_STATE_DISABLED},
633 * {@link WifiManager#WIFI_AP_STATE_DISABLING},
634 * {@link WifiManager#WIFI_AP_STATE_ENABLED},
635 * {@link WifiManager#WIFI_AP_STATE_ENABLING},
636 * {@link WifiManager#WIFI_AP_STATE_FAILED}
637 */
638 public int getWifiApEnabledState() {
Irfan Sheriff17b232b2010-06-24 11:32:26 -0700639 enforceAccessPermission();
Irfan Sheriffd8134ff2010-08-22 17:06:34 -0700640 return mWifiStateMachine.syncGetWifiApState();
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700641 }
642
643 /**
644 * see {@link WifiManager#getWifiApConfiguration()}
645 * @return soft access point configuration
646 */
Irfan Sheriffffcea7a2011-05-10 16:26:06 -0700647 public WifiConfiguration getWifiApConfiguration() {
648 enforceAccessPermission();
Irfan Sheriff9575a1b2011-11-07 10:34:54 -0800649 return mWifiStateMachine.syncGetWifiApConfiguration();
Irfan Sheriff9ab518ad2010-03-12 15:48:17 -0800650 }
651
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700652 /**
653 * see {@link WifiManager#setWifiApConfiguration(WifiConfiguration)}
654 * @param wifiConfig WifiConfiguration details for soft access point
655 */
Irfan Sheriffffcea7a2011-05-10 16:26:06 -0700656 public void setWifiApConfiguration(WifiConfiguration wifiConfig) {
Irfan Sheriff17b232b2010-06-24 11:32:26 -0700657 enforceChangePermission();
Irfan Sheriff9ab518ad2010-03-12 15:48:17 -0800658 if (wifiConfig == null)
659 return;
Irfan Sheriffffcea7a2011-05-10 16:26:06 -0700660 mWifiStateMachine.setWifiApConfiguration(wifiConfig);
Irfan Sheriff9ab518ad2010-03-12 15:48:17 -0800661 }
662
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800663 /**
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700664 * see {@link android.net.wifi.WifiManager#disconnect()}
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800665 */
Irfan Sheriffe4984752010-08-19 11:29:22 -0700666 public void disconnect() {
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700667 enforceChangePermission();
Irfan Sheriffe4984752010-08-19 11:29:22 -0700668 mWifiStateMachine.disconnectCommand();
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800669 }
670
671 /**
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700672 * see {@link android.net.wifi.WifiManager#reconnect()}
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800673 */
Irfan Sheriffe4984752010-08-19 11:29:22 -0700674 public void reconnect() {
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700675 enforceChangePermission();
Irfan Sheriffe4984752010-08-19 11:29:22 -0700676 mWifiStateMachine.reconnectCommand();
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800677 }
678
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700679 /**
680 * see {@link android.net.wifi.WifiManager#reassociate()}
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700681 */
Irfan Sheriffe4984752010-08-19 11:29:22 -0700682 public void reassociate() {
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700683 enforceChangePermission();
Irfan Sheriffe4984752010-08-19 11:29:22 -0700684 mWifiStateMachine.reassociateCommand();
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800685 }
686
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800687 /**
688 * see {@link android.net.wifi.WifiManager#getConfiguredNetworks()}
689 * @return the list of configured networks
690 */
691 public List<WifiConfiguration> getConfiguredNetworks() {
692 enforceAccessPermission();
Irfan Sheriffe744cff2011-12-11 09:17:50 -0800693 if (mWifiStateMachineChannel != null) {
694 return mWifiStateMachine.syncGetConfiguredNetworks(mWifiStateMachineChannel);
695 } else {
696 Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
697 return null;
698 }
Chung-yih Wanga8d15942009-10-09 11:01:49 +0800699 }
700
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800701 /**
702 * see {@link android.net.wifi.WifiManager#addOrUpdateNetwork(WifiConfiguration)}
703 * @return the supplicant-assigned identifier for the new or updated
704 * network if the operation succeeds, or {@code -1} if it fails
705 */
Irfan Sheriff7aac5542009-12-22 21:42:17 -0800706 public int addOrUpdateNetwork(WifiConfiguration config) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800707 enforceChangePermission();
Irfan Sheriff227bec42011-02-15 19:30:27 -0800708 if (mWifiStateMachineChannel != null) {
709 return mWifiStateMachine.syncAddOrUpdateNetwork(mWifiStateMachineChannel, config);
Irfan Sheriff1406bcb2010-10-28 14:41:39 -0700710 } else {
Irfan Sheriff227bec42011-02-15 19:30:27 -0800711 Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
Irfan Sheriff1406bcb2010-10-28 14:41:39 -0700712 return -1;
713 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800714 }
715
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700716 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800717 * See {@link android.net.wifi.WifiManager#removeNetwork(int)}
718 * @param netId the integer that identifies the network configuration
719 * to the supplicant
720 * @return {@code true} if the operation succeeded
721 */
722 public boolean removeNetwork(int netId) {
723 enforceChangePermission();
Irfan Sheriff227bec42011-02-15 19:30:27 -0800724 if (mWifiStateMachineChannel != null) {
725 return mWifiStateMachine.syncRemoveNetwork(mWifiStateMachineChannel, netId);
Wink Saville4b7ba092010-10-20 15:37:41 -0700726 } else {
Irfan Sheriff227bec42011-02-15 19:30:27 -0800727 Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
Wink Saville4b7ba092010-10-20 15:37:41 -0700728 return false;
729 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800730 }
731
732 /**
733 * See {@link android.net.wifi.WifiManager#enableNetwork(int, boolean)}
734 * @param netId the integer that identifies the network configuration
735 * to the supplicant
736 * @param disableOthers if true, disable all other networks.
737 * @return {@code true} if the operation succeeded
738 */
739 public boolean enableNetwork(int netId, boolean disableOthers) {
740 enforceChangePermission();
Irfan Sheriff227bec42011-02-15 19:30:27 -0800741 if (mWifiStateMachineChannel != null) {
742 return mWifiStateMachine.syncEnableNetwork(mWifiStateMachineChannel, netId,
743 disableOthers);
Irfan Sheriff1406bcb2010-10-28 14:41:39 -0700744 } else {
Irfan Sheriff227bec42011-02-15 19:30:27 -0800745 Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
Irfan Sheriff1406bcb2010-10-28 14:41:39 -0700746 return false;
747 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800748 }
749
750 /**
751 * See {@link android.net.wifi.WifiManager#disableNetwork(int)}
752 * @param netId the integer that identifies the network configuration
753 * to the supplicant
754 * @return {@code true} if the operation succeeded
755 */
756 public boolean disableNetwork(int netId) {
757 enforceChangePermission();
Irfan Sheriff227bec42011-02-15 19:30:27 -0800758 if (mWifiStateMachineChannel != null) {
759 return mWifiStateMachine.syncDisableNetwork(mWifiStateMachineChannel, netId);
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 /**
767 * See {@link android.net.wifi.WifiManager#getConnectionInfo()}
768 * @return the Wi-Fi information, contained in {@link WifiInfo}.
769 */
770 public WifiInfo getConnectionInfo() {
771 enforceAccessPermission();
772 /*
773 * Make sure we have the latest information, by sending
774 * a status request to the supplicant.
775 */
Irfan Sheriffd8134ff2010-08-22 17:06:34 -0700776 return mWifiStateMachine.syncRequestConnectionInfo();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800777 }
778
779 /**
780 * Return the results of the most recent access point scan, in the form of
781 * a list of {@link ScanResult} objects.
782 * @return the list of results
783 */
784 public List<ScanResult> getScanResults() {
785 enforceAccessPermission();
Irfan Sheriffd8134ff2010-08-22 17:06:34 -0700786 return mWifiStateMachine.syncGetScanResultsList();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800787 }
788
789 /**
790 * Tell the supplicant to persist the current list of configured networks.
791 * @return {@code true} if the operation succeeded
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700792 *
793 * TODO: deprecate this
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800794 */
795 public boolean saveConfiguration() {
Irfan Sheriffa2a1b912010-06-07 09:03:04 -0700796 boolean result = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800797 enforceChangePermission();
Irfan Sheriff227bec42011-02-15 19:30:27 -0800798 if (mWifiStateMachineChannel != null) {
799 return mWifiStateMachine.syncSaveConfig(mWifiStateMachineChannel);
Irfan Sheriff1406bcb2010-10-28 14:41:39 -0700800 } else {
Irfan Sheriff227bec42011-02-15 19:30:27 -0800801 Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
Irfan Sheriff1406bcb2010-10-28 14:41:39 -0700802 return false;
803 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800804 }
805
806 /**
Irfan Sheriffed4f28b2010-10-29 15:32:10 -0700807 * Set the country code
808 * @param countryCode ISO 3166 country code.
Robert Greenwaltb5010cc2009-05-21 15:11:40 -0700809 * @param persist {@code true} if the setting should be remembered.
Irfan Sheriffed4f28b2010-10-29 15:32:10 -0700810 *
811 * The persist behavior exists so that wifi can fall back to the last
812 * persisted country code on a restart, when the locale information is
813 * not available from telephony.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800814 */
Irfan Sheriffed4f28b2010-10-29 15:32:10 -0700815 public void setCountryCode(String countryCode, boolean persist) {
816 Slog.i(TAG, "WifiService trying to set country code to " + countryCode +
817 " with persist set to " + persist);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800818 enforceChangePermission();
Irfan Sheriffed4f28b2010-10-29 15:32:10 -0700819 mWifiStateMachine.setCountryCode(countryCode, persist);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800820 }
821
822 /**
Irfan Sheriff36f74132010-11-04 16:57:37 -0700823 * Set the operational frequency band
824 * @param band One of
825 * {@link WifiManager#WIFI_FREQUENCY_BAND_AUTO},
826 * {@link WifiManager#WIFI_FREQUENCY_BAND_5GHZ},
827 * {@link WifiManager#WIFI_FREQUENCY_BAND_2GHZ},
828 * @param persist {@code true} if the setting should be remembered.
829 *
830 */
831 public void setFrequencyBand(int band, boolean persist) {
832 enforceChangePermission();
833 if (!isDualBandSupported()) return;
834 Slog.i(TAG, "WifiService trying to set frequency band to " + band +
835 " with persist set to " + persist);
836 mWifiStateMachine.setFrequencyBand(band, persist);
837 }
838
839
840 /**
841 * Get the operational frequency band
842 */
843 public int getFrequencyBand() {
844 enforceAccessPermission();
845 return mWifiStateMachine.getFrequencyBand();
846 }
847
848 public boolean isDualBandSupported() {
849 //TODO: Should move towards adding a driver API that checks at runtime
850 return mContext.getResources().getBoolean(
851 com.android.internal.R.bool.config_wifi_dual_band_support);
852 }
853
854 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800855 * Return the DHCP-assigned addresses from the last successful DHCP request,
856 * if any.
857 * @return the DHCP information
858 */
859 public DhcpInfo getDhcpInfo() {
860 enforceAccessPermission();
Irfan Sheriffd8134ff2010-08-22 17:06:34 -0700861 return mWifiStateMachine.syncGetDhcpInfo();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800862 }
863
Irfan Sheriff0d255342010-07-28 09:35:20 -0700864 /**
865 * see {@link android.net.wifi.WifiManager#startWifi}
866 *
867 */
868 public void startWifi() {
869 enforceChangePermission();
870 /* TODO: may be add permissions for access only to connectivity service
871 * TODO: if a start issued, keep wifi alive until a stop issued irrespective
872 * of WifiLock & device idle status unless wifi enabled status is toggled
873 */
874
Irfan Sheriff4494c902011-12-08 10:47:54 -0800875 mWifiStateMachine.setDriverStart(true, mEmergencyCallbackMode);
Irfan Sheriff0d255342010-07-28 09:35:20 -0700876 mWifiStateMachine.reconnectCommand();
877 }
878
879 /**
880 * see {@link android.net.wifi.WifiManager#stopWifi}
881 *
882 */
883 public void stopWifi() {
884 enforceChangePermission();
885 /* TODO: may be add permissions for access only to connectivity service
886 * TODO: if a stop is issued, wifi is brought up only by startWifi
887 * unless wifi enabled status is toggled
888 */
Irfan Sheriff4494c902011-12-08 10:47:54 -0800889 mWifiStateMachine.setDriverStart(false, mEmergencyCallbackMode);
Irfan Sheriff0d255342010-07-28 09:35:20 -0700890 }
891
892
893 /**
894 * see {@link android.net.wifi.WifiManager#addToBlacklist}
895 *
896 */
897 public void addToBlacklist(String bssid) {
898 enforceChangePermission();
899
900 mWifiStateMachine.addToBlacklist(bssid);
901 }
902
903 /**
904 * see {@link android.net.wifi.WifiManager#clearBlacklist}
905 *
906 */
907 public void clearBlacklist() {
908 enforceChangePermission();
909
910 mWifiStateMachine.clearBlacklist();
911 }
912
Irfan Sheriff227bec42011-02-15 19:30:27 -0800913 /**
914 * Get a reference to handler. This is used by a client to establish
915 * an AsyncChannel communication with WifiService
916 */
917 public Messenger getMessenger() {
Irfan Sheriffebe606f2011-02-24 11:39:15 -0800918 /* Enforce the highest permissions
919 TODO: when we consider exposing the asynchronous API, think about
920 how to provide both access and change permissions seperately
921 */
Irfan Sheriff227bec42011-02-15 19:30:27 -0800922 enforceAccessPermission();
Irfan Sheriffebe606f2011-02-24 11:39:15 -0800923 enforceChangePermission();
Irfan Sheriff227bec42011-02-15 19:30:27 -0800924 return new Messenger(mAsyncServiceHandler);
925 }
926
Irfan Sheriff4aeca7c52011-03-10 16:53:33 -0800927 /**
928 * Get the IP and proxy configuration file
929 */
930 public String getConfigFile() {
931 enforceAccessPermission();
932 return mWifiStateMachine.getConfigFile();
933 }
934
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800935 private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
936 @Override
937 public void onReceive(Context context, Intent intent) {
938 String action = intent.getAction();
939
Doug Zongker43866e02010-01-07 12:09:54 -0800940 long idleMillis =
941 Settings.Secure.getLong(mContext.getContentResolver(),
Irfan Sheriff4f5f7c92010-10-14 17:01:27 -0700942 Settings.Secure.WIFI_IDLE_MS, DEFAULT_IDLE_MS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800943 int stayAwakeConditions =
Doug Zongker43866e02010-01-07 12:09:54 -0800944 Settings.System.getInt(mContext.getContentResolver(),
945 Settings.System.STAY_ON_WHILE_PLUGGED_IN, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800946 if (action.equals(Intent.ACTION_SCREEN_ON)) {
Joe Onorato431bb222010-10-18 19:13:23 -0400947 if (DBG) {
948 Slog.d(TAG, "ACTION_SCREEN_ON");
949 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800950 mAlarmManager.cancel(mIdleIntent);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800951 mScreenOff = false;
Irfan Sheriff227bec42011-02-15 19:30:27 -0800952 evaluateTrafficStatsPolling();
Irfan Sheriff0d255342010-07-28 09:35:20 -0700953 mWifiStateMachine.enableRssiPolling(true);
Irfan Sherifffcc08452011-02-17 16:44:54 -0800954 if (mBackgroundScanSupported) {
Irfan Sheriff2b7f6382011-03-25 14:29:19 -0700955 mWifiStateMachine.enableBackgroundScanCommand(false);
Irfan Sherifffcc08452011-02-17 16:44:54 -0800956 }
Irfan Sheriff8e86b892010-12-22 11:02:20 -0800957 mWifiStateMachine.enableAllNetworks();
Irfan Sheriffe6daca52011-11-03 15:46:50 -0700958 setDeviceIdleAndUpdateWifi(false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800959 } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
Joe Onorato431bb222010-10-18 19:13:23 -0400960 if (DBG) {
961 Slog.d(TAG, "ACTION_SCREEN_OFF");
962 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800963 mScreenOff = true;
Irfan Sheriff227bec42011-02-15 19:30:27 -0800964 evaluateTrafficStatsPolling();
Irfan Sheriff0d255342010-07-28 09:35:20 -0700965 mWifiStateMachine.enableRssiPolling(false);
Irfan Sherifffcc08452011-02-17 16:44:54 -0800966 if (mBackgroundScanSupported) {
Irfan Sheriff2b7f6382011-03-25 14:29:19 -0700967 mWifiStateMachine.enableBackgroundScanCommand(true);
Irfan Sherifffcc08452011-02-17 16:44:54 -0800968 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800969 /*
970 * Set a timer to put Wi-Fi to sleep, but only if the screen is off
971 * AND the "stay on while plugged in" setting doesn't match the
972 * current power conditions (i.e, not plugged in, plugged in to USB,
973 * or plugged in to AC).
974 */
975 if (!shouldWifiStayAwake(stayAwakeConditions, mPluggedType)) {
Irfan Sheriffe6daca52011-11-03 15:46:50 -0700976 //Delayed shutdown if wifi is connected
977 if (mNetworkInfo.getDetailedState() == DetailedState.CONNECTED) {
978 if (DBG) Slog.d(TAG, "setting ACTION_DEVICE_IDLE: " + idleMillis + " ms");
979 mAlarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis()
980 + idleMillis, mIdleIntent);
Mike Lockwoodd9c32bc2009-05-18 14:14:15 -0400981 } else {
Irfan Sheriffe6daca52011-11-03 15:46:50 -0700982 setDeviceIdleAndUpdateWifi(true);
Mike Lockwoodd9c32bc2009-05-18 14:14:15 -0400983 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800984 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800985 } else if (action.equals(ACTION_DEVICE_IDLE)) {
Irfan Sheriffe6daca52011-11-03 15:46:50 -0700986 setDeviceIdleAndUpdateWifi(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800987 } else if (action.equals(Intent.ACTION_BATTERY_CHANGED)) {
988 /*
989 * Set a timer to put Wi-Fi to sleep, but only if the screen is off
990 * AND we are transitioning from a state in which the device was supposed
991 * to stay awake to a state in which it is not supposed to stay awake.
992 * If "stay awake" state is not changing, we do nothing, to avoid resetting
993 * the already-set timer.
994 */
995 int pluggedType = intent.getIntExtra("plugged", 0);
Joe Onorato431bb222010-10-18 19:13:23 -0400996 if (DBG) {
997 Slog.d(TAG, "ACTION_BATTERY_CHANGED pluggedType: " + pluggedType);
998 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800999 if (mScreenOff && shouldWifiStayAwake(stayAwakeConditions, mPluggedType) &&
1000 !shouldWifiStayAwake(stayAwakeConditions, pluggedType)) {
1001 long triggerTime = System.currentTimeMillis() + idleMillis;
Joe Onorato431bb222010-10-18 19:13:23 -04001002 if (DBG) {
1003 Slog.d(TAG, "setting ACTION_DEVICE_IDLE timer for " + idleMillis + "ms");
1004 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001005 mAlarmManager.set(AlarmManager.RTC_WAKEUP, triggerTime, mIdleIntent);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001006 }
Irfan Sheriff8cef0672011-12-13 17:03:59 -08001007
1008 //Start scan stats tracking when device unplugged
1009 if (pluggedType == 0) {
1010 synchronized (mScanCount) {
1011 mScanCount.clear();
1012 }
1013 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001014 mPluggedType = pluggedType;
Irfan Sheriff65eaec82011-01-05 22:00:16 -08001015 } else if (action.equals(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED)) {
1016 int state = intent.getIntExtra(BluetoothAdapter.EXTRA_CONNECTION_STATE,
1017 BluetoothAdapter.STATE_DISCONNECTED);
1018 mWifiStateMachine.sendBluetoothAdapterStateChange(state);
Irfan Sheriff616f3172011-09-11 19:59:01 -07001019 } else if (action.equals(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED)) {
1020 mEmergencyCallbackMode = intent.getBooleanExtra("phoneinECMState", false);
1021 updateWifiState();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001022 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001023 }
1024
1025 /**
1026 * Determines whether the Wi-Fi chipset should stay awake or be put to
1027 * sleep. Looks at the setting for the sleep policy and the current
1028 * conditions.
Jaikumar Ganesh084c6652009-12-07 10:58:18 -08001029 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001030 * @see #shouldDeviceStayAwake(int, int)
1031 */
1032 private boolean shouldWifiStayAwake(int stayAwakeConditions, int pluggedType) {
Irfan Sheriff739f6bc2011-01-28 16:43:12 -08001033 //Never sleep as long as the user has not changed the settings
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001034 int wifiSleepPolicy = Settings.System.getInt(mContext.getContentResolver(),
Irfan Sheriff96b10d62011-01-11 15:40:35 -08001035 Settings.System.WIFI_SLEEP_POLICY,
Irfan Sheriff739f6bc2011-01-28 16:43:12 -08001036 Settings.System.WIFI_SLEEP_POLICY_NEVER);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001037
1038 if (wifiSleepPolicy == Settings.System.WIFI_SLEEP_POLICY_NEVER) {
1039 // Never sleep
1040 return true;
1041 } else if ((wifiSleepPolicy == Settings.System.WIFI_SLEEP_POLICY_NEVER_WHILE_PLUGGED) &&
1042 (pluggedType != 0)) {
1043 // Never sleep while plugged, and we're plugged
1044 return true;
1045 } else {
1046 // Default
1047 return shouldDeviceStayAwake(stayAwakeConditions, pluggedType);
1048 }
1049 }
Jaikumar Ganesh084c6652009-12-07 10:58:18 -08001050
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001051 /**
1052 * Determine whether the bit value corresponding to {@code pluggedType} is set in
1053 * the bit string {@code stayAwakeConditions}. Because a {@code pluggedType} value
1054 * of {@code 0} isn't really a plugged type, but rather an indication that the
1055 * device isn't plugged in at all, there is no bit value corresponding to a
1056 * {@code pluggedType} value of {@code 0}. That is why we shift by
Ben Dodson4e8620f2010-08-25 10:55:47 -07001057 * {@code pluggedType - 1} instead of by {@code pluggedType}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001058 * @param stayAwakeConditions a bit string specifying which "plugged types" should
1059 * keep the device (and hence Wi-Fi) awake.
1060 * @param pluggedType the type of plug (USB, AC, or none) for which the check is
1061 * being made
1062 * @return {@code true} if {@code pluggedType} indicates that the device is
1063 * supposed to stay awake, {@code false} otherwise.
1064 */
1065 private boolean shouldDeviceStayAwake(int stayAwakeConditions, int pluggedType) {
1066 return (stayAwakeConditions & pluggedType) != 0;
1067 }
1068 };
1069
Irfan Sheriffe6daca52011-11-03 15:46:50 -07001070 private void setDeviceIdleAndUpdateWifi(boolean deviceIdle) {
1071 mDeviceIdle = deviceIdle;
1072 reportStartWorkSource();
1073 updateWifiState();
1074 }
1075
Dianne Hackborn03f3cb02010-09-17 23:12:26 -07001076 private synchronized void reportStartWorkSource() {
1077 mTmpWorkSource.clear();
1078 if (mDeviceIdle) {
1079 for (int i=0; i<mLocks.mList.size(); i++) {
1080 mTmpWorkSource.add(mLocks.mList.get(i).mWorkSource);
Dianne Hackborn58e0eef2010-09-16 01:22:10 -07001081 }
Dianne Hackborn58e0eef2010-09-16 01:22:10 -07001082 }
Dianne Hackborn03f3cb02010-09-17 23:12:26 -07001083 mWifiStateMachine.updateBatteryWorkSource(mTmpWorkSource);
Dianne Hackborn58e0eef2010-09-16 01:22:10 -07001084 }
Jaikumar Ganesh7440fc22010-09-27 17:04:14 -07001085
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001086 private void updateWifiState() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001087 boolean lockHeld = mLocks.hasLocks();
Irfan Sheriff5876a422010-08-12 20:26:23 -07001088 int strongestLockMode = WifiManager.WIFI_MODE_FULL;
Irfan Sheriff616f3172011-09-11 19:59:01 -07001089 boolean wifiShouldBeStarted;
1090
1091 if (mEmergencyCallbackMode) {
1092 wifiShouldBeStarted = false;
1093 } else {
1094 wifiShouldBeStarted = !mDeviceIdle || lockHeld;
1095 }
Irfan Sheriff5876a422010-08-12 20:26:23 -07001096
1097 if (lockHeld) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001098 strongestLockMode = mLocks.getStrongestLockMode();
Irfan Sheriff5876a422010-08-12 20:26:23 -07001099 }
1100 /* If device is not idle, lockmode cannot be scan only */
1101 if (!mDeviceIdle && strongestLockMode == WifiManager.WIFI_MODE_SCAN_ONLY) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001102 strongestLockMode = WifiManager.WIFI_MODE_FULL;
1103 }
1104
Irfan Sheriffa2a1b912010-06-07 09:03:04 -07001105 /* Disable tethering when airplane mode is enabled */
Irfan Sheriff658772f2011-03-08 14:52:31 -08001106 if (mAirplaneModeOn.get()) {
Irfan Sheriff0d255342010-07-28 09:35:20 -07001107 mWifiStateMachine.setWifiApEnabled(null, false);
Irfan Sheriffa2a1b912010-06-07 09:03:04 -07001108 }
Irfan Sheriffb2e6c012010-04-05 11:57:56 -07001109
Irfan Sheriff658772f2011-03-08 14:52:31 -08001110 if (shouldWifiBeEnabled()) {
Irfan Sheriffa2a1b912010-06-07 09:03:04 -07001111 if (wifiShouldBeStarted) {
Dianne Hackborn03f3cb02010-09-17 23:12:26 -07001112 reportStartWorkSource();
Irfan Sheriff0d255342010-07-28 09:35:20 -07001113 mWifiStateMachine.setWifiEnabled(true);
1114 mWifiStateMachine.setScanOnlyMode(
Irfan Sheriffa2a1b912010-06-07 09:03:04 -07001115 strongestLockMode == WifiManager.WIFI_MODE_SCAN_ONLY);
Irfan Sheriff4494c902011-12-08 10:47:54 -08001116 mWifiStateMachine.setDriverStart(true, mEmergencyCallbackMode);
Irfan Sheriff5876a422010-08-12 20:26:23 -07001117 mWifiStateMachine.setHighPerfModeEnabled(strongestLockMode
1118 == WifiManager.WIFI_MODE_FULL_HIGH_PERF);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001119 } else {
Irfan Sheriff4494c902011-12-08 10:47:54 -08001120 mWifiStateMachine.setDriverStart(false, mEmergencyCallbackMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001121 }
Irfan Sheriffa2a1b912010-06-07 09:03:04 -07001122 } else {
Irfan Sheriff0d255342010-07-28 09:35:20 -07001123 mWifiStateMachine.setWifiEnabled(false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001124 }
1125 }
1126
1127 private void registerForBroadcasts() {
1128 IntentFilter intentFilter = new IntentFilter();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001129 intentFilter.addAction(Intent.ACTION_SCREEN_ON);
1130 intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
1131 intentFilter.addAction(Intent.ACTION_BATTERY_CHANGED);
1132 intentFilter.addAction(ACTION_DEVICE_IDLE);
Irfan Sheriff65eaec82011-01-05 22:00:16 -08001133 intentFilter.addAction(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED);
Irfan Sheriff616f3172011-09-11 19:59:01 -07001134 intentFilter.addAction(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001135 mContext.registerReceiver(mReceiver, intentFilter);
1136 }
Jaikumar Ganesh084c6652009-12-07 10:58:18 -08001137
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001138 private boolean isAirplaneSensitive() {
1139 String airplaneModeRadios = Settings.System.getString(mContext.getContentResolver(),
1140 Settings.System.AIRPLANE_MODE_RADIOS);
1141 return airplaneModeRadios == null
1142 || airplaneModeRadios.contains(Settings.System.RADIO_WIFI);
1143 }
1144
Mike Lockwoodbd5ddf02009-07-29 21:37:14 -07001145 private boolean isAirplaneToggleable() {
1146 String toggleableRadios = Settings.System.getString(mContext.getContentResolver(),
1147 Settings.System.AIRPLANE_MODE_TOGGLEABLE_RADIOS);
1148 return toggleableRadios != null
1149 && toggleableRadios.contains(Settings.System.RADIO_WIFI);
1150 }
1151
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001152 /**
1153 * Returns true if Wi-Fi is sensitive to airplane mode, and airplane mode is
1154 * currently on.
1155 * @return {@code true} if airplane mode is on.
1156 */
1157 private boolean isAirplaneModeOn() {
1158 return isAirplaneSensitive() && Settings.System.getInt(mContext.getContentResolver(),
1159 Settings.System.AIRPLANE_MODE_ON, 0) == 1;
1160 }
1161
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001162 @Override
1163 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1164 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
1165 != PackageManager.PERMISSION_GRANTED) {
1166 pw.println("Permission Denial: can't dump WifiService from from pid="
1167 + Binder.getCallingPid()
1168 + ", uid=" + Binder.getCallingUid());
1169 return;
1170 }
Irfan Sheriffd8134ff2010-08-22 17:06:34 -07001171 pw.println("Wi-Fi is " + mWifiStateMachine.syncGetWifiStateByName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001172 pw.println("Stay-awake conditions: " +
1173 Settings.System.getInt(mContext.getContentResolver(),
1174 Settings.System.STAY_ON_WHILE_PLUGGED_IN, 0));
1175 pw.println();
1176
1177 pw.println("Internal state:");
Irfan Sheriff0d255342010-07-28 09:35:20 -07001178 pw.println(mWifiStateMachine);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001179 pw.println();
1180 pw.println("Latest scan results:");
Irfan Sheriffd8134ff2010-08-22 17:06:34 -07001181 List<ScanResult> scanResults = mWifiStateMachine.syncGetScanResultsList();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001182 if (scanResults != null && scanResults.size() != 0) {
1183 pw.println(" BSSID Frequency RSSI Flags SSID");
1184 for (ScanResult r : scanResults) {
1185 pw.printf(" %17s %9d %5d %-16s %s%n",
1186 r.BSSID,
1187 r.frequency,
1188 r.level,
1189 r.capabilities,
1190 r.SSID == null ? "" : r.SSID);
1191 }
1192 }
1193 pw.println();
Eric Shienbrood5711fad2009-03-27 20:25:31 -07001194 pw.println("Locks acquired: " + mFullLocksAcquired + " full, " +
Irfan Sheriff5876a422010-08-12 20:26:23 -07001195 mFullHighPerfLocksAcquired + " full high perf, " +
Eric Shienbrood5711fad2009-03-27 20:25:31 -07001196 mScanLocksAcquired + " scan");
1197 pw.println("Locks released: " + mFullLocksReleased + " full, " +
Irfan Sheriff5876a422010-08-12 20:26:23 -07001198 mFullHighPerfLocksReleased + " full high perf, " +
Eric Shienbrood5711fad2009-03-27 20:25:31 -07001199 mScanLocksReleased + " scan");
1200 pw.println();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001201 pw.println("Locks held:");
1202 mLocks.dump(pw);
Isaac Levybc7dfb52011-06-06 15:34:01 -07001203
Irfan Sheriff8cef0672011-12-13 17:03:59 -08001204 pw.println("Scan count since last plugged in");
1205 synchronized (mScanCount) {
1206 for(int sc : mScanCount.keySet()) {
1207 pw.println("UID: " + sc + " Scan count: " + mScanCount.get(sc));
1208 }
1209 }
1210
Isaac Levybc7dfb52011-06-06 15:34:01 -07001211 pw.println();
Isaac Levy654f5092011-07-13 17:41:45 -07001212 pw.println("WifiWatchdogStateMachine dump");
1213 mWifiWatchdogStateMachine.dump(pw);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001214 }
1215
Robert Greenwalt58ff0212009-05-19 15:53:54 -07001216 private class WifiLock extends DeathRecipient {
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001217 WifiLock(int lockMode, String tag, IBinder binder, WorkSource ws) {
1218 super(lockMode, tag, binder, ws);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001219 }
1220
1221 public void binderDied() {
1222 synchronized (mLocks) {
1223 releaseWifiLockLocked(mBinder);
1224 }
1225 }
1226
1227 public String toString() {
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001228 return "WifiLock{" + mTag + " type=" + mMode + " binder=" + mBinder + "}";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001229 }
1230 }
1231
1232 private class LockList {
1233 private List<WifiLock> mList;
1234
1235 private LockList() {
1236 mList = new ArrayList<WifiLock>();
1237 }
1238
1239 private synchronized boolean hasLocks() {
1240 return !mList.isEmpty();
1241 }
1242
1243 private synchronized int getStrongestLockMode() {
1244 if (mList.isEmpty()) {
1245 return WifiManager.WIFI_MODE_FULL;
1246 }
Irfan Sheriff5876a422010-08-12 20:26:23 -07001247
1248 if (mFullHighPerfLocksAcquired > mFullHighPerfLocksReleased) {
1249 return WifiManager.WIFI_MODE_FULL_HIGH_PERF;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001250 }
Irfan Sheriff5876a422010-08-12 20:26:23 -07001251
1252 if (mFullLocksAcquired > mFullLocksReleased) {
1253 return WifiManager.WIFI_MODE_FULL;
1254 }
1255
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001256 return WifiManager.WIFI_MODE_SCAN_ONLY;
1257 }
1258
1259 private void addLock(WifiLock lock) {
1260 if (findLockByBinder(lock.mBinder) < 0) {
1261 mList.add(lock);
1262 }
1263 }
1264
1265 private WifiLock removeLock(IBinder binder) {
1266 int index = findLockByBinder(binder);
1267 if (index >= 0) {
Suchi Amalapurapufff2fda2009-06-30 21:36:16 -07001268 WifiLock ret = mList.remove(index);
1269 ret.unlinkDeathRecipient();
1270 return ret;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001271 } else {
1272 return null;
1273 }
1274 }
1275
1276 private int findLockByBinder(IBinder binder) {
1277 int size = mList.size();
1278 for (int i = size - 1; i >= 0; i--)
1279 if (mList.get(i).mBinder == binder)
1280 return i;
1281 return -1;
1282 }
1283
1284 private void dump(PrintWriter pw) {
1285 for (WifiLock l : mList) {
1286 pw.print(" ");
1287 pw.println(l);
1288 }
1289 }
1290 }
1291
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001292 void enforceWakeSourcePermission(int uid, int pid) {
Dianne Hackborne746f032010-09-13 16:02:57 -07001293 if (uid == android.os.Process.myUid()) {
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001294 return;
1295 }
1296 mContext.enforcePermission(android.Manifest.permission.UPDATE_DEVICE_STATS,
1297 pid, uid, null);
1298 }
1299
1300 public boolean acquireWifiLock(IBinder binder, int lockMode, String tag, WorkSource ws) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001301 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WAKE_LOCK, null);
Irfan Sheriff5876a422010-08-12 20:26:23 -07001302 if (lockMode != WifiManager.WIFI_MODE_FULL &&
1303 lockMode != WifiManager.WIFI_MODE_SCAN_ONLY &&
1304 lockMode != WifiManager.WIFI_MODE_FULL_HIGH_PERF) {
1305 Slog.e(TAG, "Illegal argument, lockMode= " + lockMode);
1306 if (DBG) throw new IllegalArgumentException("lockMode=" + lockMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001307 return false;
1308 }
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001309 if (ws != null && ws.size() == 0) {
1310 ws = null;
1311 }
Dianne Hackbornecfd7f72010-10-08 14:23:40 -07001312 if (ws != null) {
1313 enforceWakeSourcePermission(Binder.getCallingUid(), Binder.getCallingPid());
1314 }
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001315 if (ws == null) {
1316 ws = new WorkSource(Binder.getCallingUid());
1317 }
1318 WifiLock wifiLock = new WifiLock(lockMode, tag, binder, ws);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001319 synchronized (mLocks) {
1320 return acquireWifiLockLocked(wifiLock);
1321 }
1322 }
1323
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001324 private void noteAcquireWifiLock(WifiLock wifiLock) throws RemoteException {
1325 switch(wifiLock.mMode) {
1326 case WifiManager.WIFI_MODE_FULL:
Irfan Sheriff5876a422010-08-12 20:26:23 -07001327 case WifiManager.WIFI_MODE_FULL_HIGH_PERF:
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001328 mBatteryStats.noteFullWifiLockAcquiredFromSource(wifiLock.mWorkSource);
1329 break;
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001330 case WifiManager.WIFI_MODE_SCAN_ONLY:
1331 mBatteryStats.noteScanWifiLockAcquiredFromSource(wifiLock.mWorkSource);
1332 break;
1333 }
1334 }
1335
1336 private void noteReleaseWifiLock(WifiLock wifiLock) throws RemoteException {
1337 switch(wifiLock.mMode) {
1338 case WifiManager.WIFI_MODE_FULL:
Irfan Sheriff5876a422010-08-12 20:26:23 -07001339 case WifiManager.WIFI_MODE_FULL_HIGH_PERF:
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001340 mBatteryStats.noteFullWifiLockReleasedFromSource(wifiLock.mWorkSource);
1341 break;
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001342 case WifiManager.WIFI_MODE_SCAN_ONLY:
1343 mBatteryStats.noteScanWifiLockReleasedFromSource(wifiLock.mWorkSource);
1344 break;
1345 }
1346 }
1347
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001348 private boolean acquireWifiLockLocked(WifiLock wifiLock) {
Irfan Sheriffc89dd542010-09-28 08:40:54 -07001349 if (DBG) Slog.d(TAG, "acquireWifiLockLocked: " + wifiLock);
Robert Greenwaltf1acb2d2009-10-13 08:20:55 -07001350
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001351 mLocks.addLock(wifiLock);
Robert Greenwaltf1acb2d2009-10-13 08:20:55 -07001352
The Android Open Source Project10592532009-03-18 17:39:46 -07001353 long ident = Binder.clearCallingIdentity();
1354 try {
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001355 noteAcquireWifiLock(wifiLock);
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001356 switch(wifiLock.mMode) {
Eric Shienbrood5711fad2009-03-27 20:25:31 -07001357 case WifiManager.WIFI_MODE_FULL:
1358 ++mFullLocksAcquired;
Eric Shienbrood5711fad2009-03-27 20:25:31 -07001359 break;
Irfan Sheriff5876a422010-08-12 20:26:23 -07001360 case WifiManager.WIFI_MODE_FULL_HIGH_PERF:
1361 ++mFullHighPerfLocksAcquired;
1362 break;
1363
Eric Shienbrood5711fad2009-03-27 20:25:31 -07001364 case WifiManager.WIFI_MODE_SCAN_ONLY:
1365 ++mScanLocksAcquired;
Eric Shienbrood5711fad2009-03-27 20:25:31 -07001366 break;
The Android Open Source Project10592532009-03-18 17:39:46 -07001367 }
Dianne Hackbornecfd7f72010-10-08 14:23:40 -07001368
1369 // Be aggressive about adding new locks into the accounted state...
1370 // we want to over-report rather than under-report.
1371 reportStartWorkSource();
1372
1373 updateWifiState();
1374 return true;
The Android Open Source Project10592532009-03-18 17:39:46 -07001375 } catch (RemoteException e) {
Dianne Hackbornecfd7f72010-10-08 14:23:40 -07001376 return false;
The Android Open Source Project10592532009-03-18 17:39:46 -07001377 } finally {
1378 Binder.restoreCallingIdentity(ident);
1379 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001380 }
1381
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001382 public void updateWifiLockWorkSource(IBinder lock, WorkSource ws) {
1383 int uid = Binder.getCallingUid();
1384 int pid = Binder.getCallingPid();
1385 if (ws != null && ws.size() == 0) {
1386 ws = null;
1387 }
1388 if (ws != null) {
1389 enforceWakeSourcePermission(uid, pid);
1390 }
1391 long ident = Binder.clearCallingIdentity();
1392 try {
1393 synchronized (mLocks) {
1394 int index = mLocks.findLockByBinder(lock);
1395 if (index < 0) {
1396 throw new IllegalArgumentException("Wifi lock not active");
1397 }
1398 WifiLock wl = mLocks.mList.get(index);
1399 noteReleaseWifiLock(wl);
1400 wl.mWorkSource = ws != null ? new WorkSource(ws) : new WorkSource(uid);
1401 noteAcquireWifiLock(wl);
1402 }
1403 } catch (RemoteException e) {
1404 } finally {
1405 Binder.restoreCallingIdentity(ident);
1406 }
1407 }
1408
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001409 public boolean releaseWifiLock(IBinder lock) {
1410 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WAKE_LOCK, null);
1411 synchronized (mLocks) {
1412 return releaseWifiLockLocked(lock);
1413 }
1414 }
1415
1416 private boolean releaseWifiLockLocked(IBinder lock) {
Eric Shienbroodd4c5f892009-03-24 18:13:20 -07001417 boolean hadLock;
Robert Greenwaltf1acb2d2009-10-13 08:20:55 -07001418
The Android Open Source Project10592532009-03-18 17:39:46 -07001419 WifiLock wifiLock = mLocks.removeLock(lock);
Robert Greenwaltf1acb2d2009-10-13 08:20:55 -07001420
Irfan Sheriffc89dd542010-09-28 08:40:54 -07001421 if (DBG) Slog.d(TAG, "releaseWifiLockLocked: " + wifiLock);
Robert Greenwaltf1acb2d2009-10-13 08:20:55 -07001422
Eric Shienbroodd4c5f892009-03-24 18:13:20 -07001423 hadLock = (wifiLock != null);
1424
Dianne Hackbornecfd7f72010-10-08 14:23:40 -07001425 long ident = Binder.clearCallingIdentity();
1426 try {
1427 if (hadLock) {
Wink Savillece0ea1f2011-10-13 16:55:20 -07001428 noteReleaseWifiLock(wifiLock);
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001429 switch(wifiLock.mMode) {
Eric Shienbrood5711fad2009-03-27 20:25:31 -07001430 case WifiManager.WIFI_MODE_FULL:
1431 ++mFullLocksReleased;
Eric Shienbrood5711fad2009-03-27 20:25:31 -07001432 break;
Irfan Sheriff5876a422010-08-12 20:26:23 -07001433 case WifiManager.WIFI_MODE_FULL_HIGH_PERF:
1434 ++mFullHighPerfLocksReleased;
1435 break;
Eric Shienbrood5711fad2009-03-27 20:25:31 -07001436 case WifiManager.WIFI_MODE_SCAN_ONLY:
1437 ++mScanLocksReleased;
Eric Shienbrood5711fad2009-03-27 20:25:31 -07001438 break;
Eric Shienbroodd4c5f892009-03-24 18:13:20 -07001439 }
The Android Open Source Project10592532009-03-18 17:39:46 -07001440 }
Dianne Hackbornecfd7f72010-10-08 14:23:40 -07001441
1442 // TODO - should this only happen if you hadLock?
1443 updateWifiState();
1444
1445 } catch (RemoteException e) {
1446 } finally {
1447 Binder.restoreCallingIdentity(ident);
The Android Open Source Project10592532009-03-18 17:39:46 -07001448 }
Dianne Hackbornecfd7f72010-10-08 14:23:40 -07001449
Eric Shienbroodd4c5f892009-03-24 18:13:20 -07001450 return hadLock;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001451 }
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001452
Robert Greenwalt58ff0212009-05-19 15:53:54 -07001453 private abstract class DeathRecipient
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001454 implements IBinder.DeathRecipient {
1455 String mTag;
1456 int mMode;
1457 IBinder mBinder;
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001458 WorkSource mWorkSource;
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001459
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001460 DeathRecipient(int mode, String tag, IBinder binder, WorkSource ws) {
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001461 super();
1462 mTag = tag;
1463 mMode = mode;
1464 mBinder = binder;
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001465 mWorkSource = ws;
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001466 try {
1467 mBinder.linkToDeath(this, 0);
1468 } catch (RemoteException e) {
1469 binderDied();
1470 }
1471 }
Suchi Amalapurapufff2fda2009-06-30 21:36:16 -07001472
1473 void unlinkDeathRecipient() {
1474 mBinder.unlinkToDeath(this, 0);
1475 }
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001476 }
1477
Robert Greenwalt58ff0212009-05-19 15:53:54 -07001478 private class Multicaster extends DeathRecipient {
1479 Multicaster(String tag, IBinder binder) {
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001480 super(Binder.getCallingUid(), tag, binder, null);
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001481 }
1482
1483 public void binderDied() {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001484 Slog.e(TAG, "Multicaster binderDied");
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001485 synchronized (mMulticasters) {
1486 int i = mMulticasters.indexOf(this);
1487 if (i != -1) {
1488 removeMulticasterLocked(i, mMode);
1489 }
1490 }
1491 }
1492
1493 public String toString() {
Robert Greenwalt58ff0212009-05-19 15:53:54 -07001494 return "Multicaster{" + mTag + " binder=" + mBinder + "}";
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001495 }
1496
1497 public int getUid() {
1498 return mMode;
1499 }
1500 }
1501
Robert Greenwalte2d155a2009-10-21 14:58:34 -07001502 public void initializeMulticastFiltering() {
1503 enforceMulticastChangePermission();
Irfan Sheriffa8fbe1f2010-03-09 09:13:58 -08001504
Robert Greenwalte2d155a2009-10-21 14:58:34 -07001505 synchronized (mMulticasters) {
1506 // if anybody had requested filters be off, leave off
1507 if (mMulticasters.size() != 0) {
1508 return;
1509 } else {
Irfan Sheriffb0c1b80f2011-07-19 15:44:25 -07001510 mWifiStateMachine.startFilteringMulticastV4Packets();
Robert Greenwalte2d155a2009-10-21 14:58:34 -07001511 }
1512 }
1513 }
1514
Robert Greenwaltfc1b15c2009-05-22 15:09:51 -07001515 public void acquireMulticastLock(IBinder binder, String tag) {
1516 enforceMulticastChangePermission();
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001517
1518 synchronized (mMulticasters) {
1519 mMulticastEnabled++;
Robert Greenwalt58ff0212009-05-19 15:53:54 -07001520 mMulticasters.add(new Multicaster(tag, binder));
Irfan Sheriffb0c1b80f2011-07-19 15:44:25 -07001521 // Note that we could call stopFilteringMulticastV4Packets only when
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001522 // our new size == 1 (first call), but this function won't
1523 // be called often and by making the stopPacket call each
1524 // time we're less fragile and self-healing.
Irfan Sheriffb0c1b80f2011-07-19 15:44:25 -07001525 mWifiStateMachine.stopFilteringMulticastV4Packets();
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001526 }
1527
1528 int uid = Binder.getCallingUid();
1529 Long ident = Binder.clearCallingIdentity();
1530 try {
1531 mBatteryStats.noteWifiMulticastEnabled(uid);
1532 } catch (RemoteException e) {
1533 } finally {
1534 Binder.restoreCallingIdentity(ident);
1535 }
1536 }
1537
Robert Greenwaltfc1b15c2009-05-22 15:09:51 -07001538 public void releaseMulticastLock() {
1539 enforceMulticastChangePermission();
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001540
1541 int uid = Binder.getCallingUid();
1542 synchronized (mMulticasters) {
1543 mMulticastDisabled++;
1544 int size = mMulticasters.size();
1545 for (int i = size - 1; i >= 0; i--) {
Robert Greenwalt58ff0212009-05-19 15:53:54 -07001546 Multicaster m = mMulticasters.get(i);
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001547 if ((m != null) && (m.getUid() == uid)) {
1548 removeMulticasterLocked(i, uid);
1549 }
1550 }
1551 }
1552 }
1553
1554 private void removeMulticasterLocked(int i, int uid)
1555 {
Suchi Amalapurapufff2fda2009-06-30 21:36:16 -07001556 Multicaster removed = mMulticasters.remove(i);
Irfan Sheriffa8fbe1f2010-03-09 09:13:58 -08001557
Suchi Amalapurapufff2fda2009-06-30 21:36:16 -07001558 if (removed != null) {
1559 removed.unlinkDeathRecipient();
1560 }
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001561 if (mMulticasters.size() == 0) {
Irfan Sheriffb0c1b80f2011-07-19 15:44:25 -07001562 mWifiStateMachine.startFilteringMulticastV4Packets();
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001563 }
1564
1565 Long ident = Binder.clearCallingIdentity();
1566 try {
1567 mBatteryStats.noteWifiMulticastDisabled(uid);
1568 } catch (RemoteException e) {
1569 } finally {
1570 Binder.restoreCallingIdentity(ident);
1571 }
1572 }
1573
Robert Greenwalt58ff0212009-05-19 15:53:54 -07001574 public boolean isMulticastEnabled() {
Robert Greenwalt5347bd42009-05-13 15:10:16 -07001575 enforceAccessPermission();
1576
1577 synchronized (mMulticasters) {
1578 return (mMulticasters.size() > 0);
1579 }
1580 }
Irfan Sheriff0d255342010-07-28 09:35:20 -07001581
Irfan Sheriff227bec42011-02-15 19:30:27 -08001582 /**
1583 * Evaluate if traffic stats polling is needed based on
1584 * connection and screen on status
1585 */
1586 private void evaluateTrafficStatsPolling() {
1587 Message msg;
1588 if (mNetworkInfo.getDetailedState() == DetailedState.CONNECTED && !mScreenOff) {
Irfan Sheriffebe606f2011-02-24 11:39:15 -08001589 msg = Message.obtain(mAsyncServiceHandler,
1590 WifiManager.CMD_ENABLE_TRAFFIC_STATS_POLL, 1, 0);
Irfan Sheriff227bec42011-02-15 19:30:27 -08001591 } else {
Irfan Sheriffebe606f2011-02-24 11:39:15 -08001592 msg = Message.obtain(mAsyncServiceHandler,
1593 WifiManager.CMD_ENABLE_TRAFFIC_STATS_POLL, 0, 0);
Irfan Sheriff227bec42011-02-15 19:30:27 -08001594 }
1595 msg.sendToTarget();
1596 }
1597
1598 private void notifyOnDataActivity() {
1599 long sent, received;
1600 long preTxPkts = mTxPkts, preRxPkts = mRxPkts;
1601 int dataActivity = WifiManager.DATA_ACTIVITY_NONE;
1602
1603 mTxPkts = TrafficStats.getTxPackets(mInterfaceName);
1604 mRxPkts = TrafficStats.getRxPackets(mInterfaceName);
1605
1606 if (preTxPkts > 0 || preRxPkts > 0) {
1607 sent = mTxPkts - preTxPkts;
1608 received = mRxPkts - preRxPkts;
1609 if (sent > 0) {
1610 dataActivity |= WifiManager.DATA_ACTIVITY_OUT;
1611 }
1612 if (received > 0) {
1613 dataActivity |= WifiManager.DATA_ACTIVITY_IN;
1614 }
1615
1616 if (dataActivity != mDataActivity && !mScreenOff) {
1617 mDataActivity = dataActivity;
1618 for (AsyncChannel client : mClients) {
1619 client.sendMessage(WifiManager.DATA_ACTIVITY_NOTIFICATION, mDataActivity);
1620 }
1621 }
1622 }
1623 }
1624
1625
Irfan Sheriff0d255342010-07-28 09:35:20 -07001626 private void checkAndSetNotification() {
1627 // If we shouldn't place a notification on available networks, then
1628 // don't bother doing any of the following
1629 if (!mNotificationEnabled) return;
1630
1631 State state = mNetworkInfo.getState();
1632 if ((state == NetworkInfo.State.DISCONNECTED)
1633 || (state == NetworkInfo.State.UNKNOWN)) {
1634 // Look for an open network
Irfan Sheriffd8134ff2010-08-22 17:06:34 -07001635 List<ScanResult> scanResults = mWifiStateMachine.syncGetScanResultsList();
Irfan Sheriff0d255342010-07-28 09:35:20 -07001636 if (scanResults != null) {
1637 int numOpenNetworks = 0;
1638 for (int i = scanResults.size() - 1; i >= 0; i--) {
1639 ScanResult scanResult = scanResults.get(i);
1640
Irfan Sherifffdd5f952011-08-04 16:55:54 -07001641 //A capability of [ESS] represents an open access point
1642 //that is available for an STA to connect
1643 if (scanResult.capabilities != null &&
1644 scanResult.capabilities.equals("[ESS]")) {
Irfan Sheriff0d255342010-07-28 09:35:20 -07001645 numOpenNetworks++;
1646 }
1647 }
1648
1649 if (numOpenNetworks > 0) {
1650 if (++mNumScansSinceNetworkStateChange >= NUM_SCANS_BEFORE_ACTUALLY_SCANNING) {
1651 /*
1652 * We've scanned continuously at least
1653 * NUM_SCANS_BEFORE_NOTIFICATION times. The user
1654 * probably does not have a remembered network in range,
1655 * since otherwise supplicant would have tried to
1656 * associate and thus resetting this counter.
1657 */
1658 setNotificationVisible(true, numOpenNetworks, false, 0);
1659 }
1660 return;
1661 }
1662 }
1663 }
1664
1665 // No open networks in range, remove the notification
1666 setNotificationVisible(false, 0, false, 0);
1667 }
1668
1669 /**
1670 * Clears variables related to tracking whether a notification has been
1671 * shown recently and clears the current notification.
1672 */
1673 private void resetNotification() {
1674 mNotificationRepeatTime = 0;
1675 mNumScansSinceNetworkStateChange = 0;
1676 setNotificationVisible(false, 0, false, 0);
1677 }
1678
1679 /**
1680 * Display or don't display a notification that there are open Wi-Fi networks.
1681 * @param visible {@code true} if notification should be visible, {@code false} otherwise
1682 * @param numNetworks the number networks seen
1683 * @param force {@code true} to force notification to be shown/not-shown,
1684 * even if it is already shown/not-shown.
1685 * @param delay time in milliseconds after which the notification should be made
1686 * visible or invisible.
1687 */
1688 private void setNotificationVisible(boolean visible, int numNetworks, boolean force,
1689 int delay) {
1690
1691 // Since we use auto cancel on the notification, when the
1692 // mNetworksAvailableNotificationShown is true, the notification may
1693 // have actually been canceled. However, when it is false we know
1694 // for sure that it is not being shown (it will not be shown any other
1695 // place than here)
1696
1697 // If it should be hidden and it is already hidden, then noop
1698 if (!visible && !mNotificationShown && !force) {
1699 return;
1700 }
1701
1702 NotificationManager notificationManager = (NotificationManager) mContext
1703 .getSystemService(Context.NOTIFICATION_SERVICE);
1704
1705 Message message;
1706 if (visible) {
1707
1708 // Not enough time has passed to show the notification again
1709 if (System.currentTimeMillis() < mNotificationRepeatTime) {
1710 return;
1711 }
1712
1713 if (mNotification == null) {
Wink Savillec7a98342010-08-13 16:11:42 -07001714 // Cache the Notification object.
Irfan Sheriff0d255342010-07-28 09:35:20 -07001715 mNotification = new Notification();
1716 mNotification.when = 0;
1717 mNotification.icon = ICON_NETWORKS_AVAILABLE;
1718 mNotification.flags = Notification.FLAG_AUTO_CANCEL;
1719 mNotification.contentIntent = PendingIntent.getActivity(mContext, 0,
1720 new Intent(WifiManager.ACTION_PICK_WIFI_NETWORK), 0);
1721 }
1722
1723 CharSequence title = mContext.getResources().getQuantityText(
1724 com.android.internal.R.plurals.wifi_available, numNetworks);
1725 CharSequence details = mContext.getResources().getQuantityText(
1726 com.android.internal.R.plurals.wifi_available_detailed, numNetworks);
1727 mNotification.tickerText = title;
1728 mNotification.setLatestEventInfo(mContext, title, details, mNotification.contentIntent);
1729
1730 mNotificationRepeatTime = System.currentTimeMillis() + NOTIFICATION_REPEAT_DELAY_MS;
1731
1732 notificationManager.notify(ICON_NETWORKS_AVAILABLE, mNotification);
Irfan Sheriff0d255342010-07-28 09:35:20 -07001733 } else {
Irfan Sheriff0d255342010-07-28 09:35:20 -07001734 notificationManager.cancel(ICON_NETWORKS_AVAILABLE);
Irfan Sheriff0d255342010-07-28 09:35:20 -07001735 }
1736
Irfan Sheriff0d255342010-07-28 09:35:20 -07001737 mNotificationShown = visible;
1738 }
1739
1740 private class NotificationEnabledSettingObserver extends ContentObserver {
1741
1742 public NotificationEnabledSettingObserver(Handler handler) {
1743 super(handler);
1744 }
1745
1746 public void register() {
1747 ContentResolver cr = mContext.getContentResolver();
1748 cr.registerContentObserver(Settings.Secure.getUriFor(
1749 Settings.Secure.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON), true, this);
1750 mNotificationEnabled = getValue();
1751 }
1752
1753 @Override
1754 public void onChange(boolean selfChange) {
1755 super.onChange(selfChange);
1756
1757 mNotificationEnabled = getValue();
1758 resetNotification();
1759 }
1760
1761 private boolean getValue() {
1762 return Settings.Secure.getInt(mContext.getContentResolver(),
1763 Settings.Secure.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON, 1) == 1;
1764 }
1765 }
1766
1767
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001768}