1b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff/* 2b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff * Copyright (C) 2013 The Android Open Source Project 3b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff * 4b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff * Licensed under the Apache License, Version 2.0 (the "License"); 5b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff * you may not use this file except in compliance with the License. 6b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff * You may obtain a copy of the License at 7b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff * 8b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff * http://www.apache.org/licenses/LICENSE-2.0 9b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff * 10b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff * Unless required by applicable law or agreed to in writing, software 11b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff * distributed under the License is distributed on an "AS IS" BASIS, 12b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff * See the License for the specific language governing permissions and 14b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff * limitations under the License. 15b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff */ 16b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff 17b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriffpackage com.android.server.wifi; 18b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff 19b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriffimport android.app.Notification; 20b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriffimport android.app.NotificationManager; 21b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriffimport android.app.TaskStackBuilder; 22b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriffimport android.content.BroadcastReceiver; 23b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriffimport android.content.ContentResolver; 24b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriffimport android.content.Context; 25b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriffimport android.content.Intent; 26b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriffimport android.content.IntentFilter; 27b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriffimport android.database.ContentObserver; 28b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriffimport android.net.NetworkInfo; 29b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriffimport android.net.wifi.ScanResult; 30b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriffimport android.net.wifi.WifiManager; 31b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriffimport android.net.wifi.WifiStateMachine; 32b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriffimport android.os.Handler; 33b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriffimport android.os.Message; 34b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriffimport android.os.UserHandle; 35b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriffimport android.provider.Settings; 36b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff 37b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriffimport java.io.FileDescriptor; 38b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriffimport java.io.PrintWriter; 39b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriffimport java.util.List; 40b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff 41b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff/* Takes care of handling the "open wi-fi network available" notification @hide */ 42b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sherifffinal class WifiNotificationController { 43b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff /** 44b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff * The icon to show in the 'available networks' notification. This will also 45b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff * be the ID of the Notification given to the NotificationManager. 46b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff */ 47b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff private static final int ICON_NETWORKS_AVAILABLE = 48b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff com.android.internal.R.drawable.stat_notify_wifi_in_range; 49b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff /** 50b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff * When a notification is shown, we wait this amount before possibly showing it again. 51b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff */ 52b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff private final long NOTIFICATION_REPEAT_DELAY_MS; 53b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff /** 54b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff * Whether the user has set the setting to show the 'available networks' notification. 55b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff */ 56b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff private boolean mNotificationEnabled; 57b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff /** 58b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff * Observes the user setting to keep {@link #mNotificationEnabled} in sync. 59b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff */ 60b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff private NotificationEnabledSettingObserver mNotificationEnabledSettingObserver; 61b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff /** 62b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff * The {@link System#currentTimeMillis()} must be at least this value for us 63b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff * to show the notification again. 64b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff */ 65b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff private long mNotificationRepeatTime; 66b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff /** 67b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff * The Notification object given to the NotificationManager. 68b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff */ 69b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff private Notification mNotification; 70b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff /** 71b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff * Whether the notification is being shown, as set by us. That is, if the 72b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff * user cancels the notification, we will not receive the callback so this 73b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff * will still be true. We only guarantee if this is false, then the 74b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff * notification is not showing. 75b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff */ 76b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff private boolean mNotificationShown; 77b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff /** 78b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff * The number of continuous scans that must occur before consider the 79b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff * supplicant in a scanning state. This allows supplicant to associate with 80b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff * remembered networks that are in the scan results. 81b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff */ 82b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff private static final int NUM_SCANS_BEFORE_ACTUALLY_SCANNING = 3; 83b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff /** 84b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff * The number of scans since the last network state change. When this 85b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff * exceeds {@link #NUM_SCANS_BEFORE_ACTUALLY_SCANNING}, we consider the 86b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff * supplicant to actually be scanning. When the network state changes to 87b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff * something other than scanning, we reset this to 0. 88b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff */ 89b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff private int mNumScansSinceNetworkStateChange; 90b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff 91b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff private final Context mContext; 92b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff private final WifiStateMachine mWifiStateMachine; 93b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff private NetworkInfo mNetworkInfo; 948c776925540d6deec2bf7a3eab6bf4b11f6d2747Robert Greenwalt private volatile int mWifiState; 95b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff 96b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff WifiNotificationController(Context context, WifiStateMachine wsm) { 97b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff mContext = context; 98b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff mWifiStateMachine = wsm; 998c776925540d6deec2bf7a3eab6bf4b11f6d2747Robert Greenwalt mWifiState = WifiManager.WIFI_STATE_UNKNOWN; 100b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff 101b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff IntentFilter filter = new IntentFilter(); 102b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION); 103b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION); 104b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff filter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION); 105b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff 106b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff mContext.registerReceiver( 107b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff new BroadcastReceiver() { 108b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff @Override 109b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff public void onReceive(Context context, Intent intent) { 110b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff if (intent.getAction().equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) { 1118c776925540d6deec2bf7a3eab6bf4b11f6d2747Robert Greenwalt mWifiState = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, 1128c776925540d6deec2bf7a3eab6bf4b11f6d2747Robert Greenwalt WifiManager.WIFI_STATE_UNKNOWN); 113b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff resetNotification(); 114b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff } else if (intent.getAction().equals( 115b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff WifiManager.NETWORK_STATE_CHANGED_ACTION)) { 116b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff mNetworkInfo = (NetworkInfo) intent.getParcelableExtra( 117b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff WifiManager.EXTRA_NETWORK_INFO); 118b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff // reset & clear notification on a network connect & disconnect 119b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff switch(mNetworkInfo.getDetailedState()) { 120b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff case CONNECTED: 121b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff case DISCONNECTED: 122b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff case CAPTIVE_PORTAL_CHECK: 123b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff resetNotification(); 124b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff break; 125b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff } 126b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff } else if (intent.getAction().equals( 127b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) { 128b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff checkAndSetNotification(mNetworkInfo, 129b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff mWifiStateMachine.syncGetScanResultsList()); 130b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff } 131b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff } 132b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff }, filter); 133b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff 134b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff // Setting is in seconds 135b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff NOTIFICATION_REPEAT_DELAY_MS = Settings.Global.getInt(context.getContentResolver(), 136b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff Settings.Global.WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY, 900) * 1000l; 137b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff mNotificationEnabledSettingObserver = new NotificationEnabledSettingObserver(new Handler()); 138b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff mNotificationEnabledSettingObserver.register(); 139b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff } 140b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff 141b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff private synchronized void checkAndSetNotification(NetworkInfo networkInfo, 142b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff List<ScanResult> scanResults) { 143b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff // TODO: unregister broadcast so we do not have to check here 144b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff // If we shouldn't place a notification on available networks, then 145b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff // don't bother doing any of the following 146b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff if (!mNotificationEnabled) return; 147b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff if (networkInfo == null) return; 1488c776925540d6deec2bf7a3eab6bf4b11f6d2747Robert Greenwalt if (mWifiState != WifiManager.WIFI_STATE_ENABLED) return; 149b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff 150b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff NetworkInfo.State state = networkInfo.getState(); 151b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff if ((state == NetworkInfo.State.DISCONNECTED) 152b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff || (state == NetworkInfo.State.UNKNOWN)) { 153b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff if (scanResults != null) { 154b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff int numOpenNetworks = 0; 155b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff for (int i = scanResults.size() - 1; i >= 0; i--) { 156b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff ScanResult scanResult = scanResults.get(i); 157b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff 158b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff //A capability of [ESS] represents an open access point 159b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff //that is available for an STA to connect 160b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff if (scanResult.capabilities != null && 161b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff scanResult.capabilities.equals("[ESS]")) { 162b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff numOpenNetworks++; 163b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff } 164b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff } 165b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff 166b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff if (numOpenNetworks > 0) { 167b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff if (++mNumScansSinceNetworkStateChange >= NUM_SCANS_BEFORE_ACTUALLY_SCANNING) { 168b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff /* 169b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff * We've scanned continuously at least 170b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff * NUM_SCANS_BEFORE_NOTIFICATION times. The user 171b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff * probably does not have a remembered network in range, 172b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff * since otherwise supplicant would have tried to 173b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff * associate and thus resetting this counter. 174b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff */ 175b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff setNotificationVisible(true, numOpenNetworks, false, 0); 176b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff } 177b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff return; 178b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff } 179b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff } 180b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff } 181b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff 182b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff // No open networks in range, remove the notification 183b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff setNotificationVisible(false, 0, false, 0); 184b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff } 185b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff 186b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff /** 187b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff * Clears variables related to tracking whether a notification has been 188b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff * shown recently and clears the current notification. 189b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff */ 190b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff private synchronized void resetNotification() { 191b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff mNotificationRepeatTime = 0; 192b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff mNumScansSinceNetworkStateChange = 0; 193b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff setNotificationVisible(false, 0, false, 0); 194b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff } 195b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff 196b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff /** 197b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff * Display or don't display a notification that there are open Wi-Fi networks. 198b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff * @param visible {@code true} if notification should be visible, {@code false} otherwise 199b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff * @param numNetworks the number networks seen 200b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff * @param force {@code true} to force notification to be shown/not-shown, 201b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff * even if it is already shown/not-shown. 202b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff * @param delay time in milliseconds after which the notification should be made 203b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff * visible or invisible. 204b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff */ 205b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff private void setNotificationVisible(boolean visible, int numNetworks, boolean force, 206b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff int delay) { 207b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff 208b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff // Since we use auto cancel on the notification, when the 209b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff // mNetworksAvailableNotificationShown is true, the notification may 210b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff // have actually been canceled. However, when it is false we know 211b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff // for sure that it is not being shown (it will not be shown any other 212b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff // place than here) 213b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff 214b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff // If it should be hidden and it is already hidden, then noop 215b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff if (!visible && !mNotificationShown && !force) { 216b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff return; 217b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff } 218b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff 219b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff NotificationManager notificationManager = (NotificationManager) mContext 220b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff .getSystemService(Context.NOTIFICATION_SERVICE); 221b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff 222b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff Message message; 223b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff if (visible) { 224b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff 225b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff // Not enough time has passed to show the notification again 226b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff if (System.currentTimeMillis() < mNotificationRepeatTime) { 227b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff return; 228b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff } 229b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff 230b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff if (mNotification == null) { 231b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff // Cache the Notification object. 232b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff mNotification = new Notification(); 233b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff mNotification.when = 0; 234b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff mNotification.icon = ICON_NETWORKS_AVAILABLE; 235b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff mNotification.flags = Notification.FLAG_AUTO_CANCEL; 236b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff mNotification.contentIntent = TaskStackBuilder.create(mContext) 237b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff .addNextIntentWithParentStack( 238b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff new Intent(WifiManager.ACTION_PICK_WIFI_NETWORK)) 239b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff .getPendingIntent(0, 0, null, UserHandle.CURRENT); 240b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff } 241b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff 242b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff CharSequence title = mContext.getResources().getQuantityText( 243b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff com.android.internal.R.plurals.wifi_available, numNetworks); 244b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff CharSequence details = mContext.getResources().getQuantityText( 245b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff com.android.internal.R.plurals.wifi_available_detailed, numNetworks); 246b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff mNotification.tickerText = title; 247b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff mNotification.setLatestEventInfo(mContext, title, details, mNotification.contentIntent); 248b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff 249b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff mNotificationRepeatTime = System.currentTimeMillis() + NOTIFICATION_REPEAT_DELAY_MS; 250b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff 251b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff notificationManager.notifyAsUser(null, ICON_NETWORKS_AVAILABLE, mNotification, 252b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff UserHandle.ALL); 253b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff } else { 254b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff notificationManager.cancelAsUser(null, ICON_NETWORKS_AVAILABLE, UserHandle.ALL); 255b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff } 256b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff 257b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff mNotificationShown = visible; 258b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff } 259b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff 260b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 261b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff pw.println("mNotificationEnabled " + mNotificationEnabled); 262b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff pw.println("mNotificationRepeatTime " + mNotificationRepeatTime); 263b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff pw.println("mNotificationShown " + mNotificationShown); 264b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff pw.println("mNumScansSinceNetworkStateChange " + mNumScansSinceNetworkStateChange); 265b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff } 266b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff 267b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff private class NotificationEnabledSettingObserver extends ContentObserver { 268b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff public NotificationEnabledSettingObserver(Handler handler) { 269b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff super(handler); 270b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff } 271b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff 272b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff public void register() { 273b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff ContentResolver cr = mContext.getContentResolver(); 274b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff cr.registerContentObserver(Settings.Global.getUriFor( 275b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff Settings.Global.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON), true, this); 276b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff synchronized (WifiNotificationController.this) { 277b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff mNotificationEnabled = getValue(); 278b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff } 279b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff } 280b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff 281b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff @Override 282b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff public void onChange(boolean selfChange) { 283b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff super.onChange(selfChange); 284b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff 285b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff synchronized (WifiNotificationController.this) { 286b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff mNotificationEnabled = getValue(); 287b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff resetNotification(); 288b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff } 289b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff } 290b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff 291b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff private boolean getValue() { 292b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff return Settings.Global.getInt(mContext.getContentResolver(), 293b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff Settings.Global.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON, 1) == 1; 294b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff } 295b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff } 296b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff 297b8c0e009a74ac2eaee8946fbe0bb3b3fe2749c9aIrfan Sheriff} 298