1155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande/* 2155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande * Copyright (C) 2013 The Android Open Source Project 3155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande * 4155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande * Licensed under the Apache License, Version 2.0 (the "License"); 5155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande * you may not use this file except in compliance with the License. 6155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande * You may obtain a copy of the License at 7155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande * 8155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande * http://www.apache.org/licenses/LICENSE-2.0 9155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande * 10155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande * Unless required by applicable law or agreed to in writing, software 11155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande * distributed under the License is distributed on an "AS IS" BASIS, 12155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande * See the License for the specific language governing permissions and 14155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande * limitations under the License. 15155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande */ 16155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande 17155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpandepackage com.android.server.wifi; 18155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande 19155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpandeimport android.app.Notification; 20155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpandeimport android.app.NotificationManager; 21155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpandeimport android.app.TaskStackBuilder; 22155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpandeimport android.content.BroadcastReceiver; 23155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpandeimport android.content.ContentResolver; 24155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpandeimport android.content.Context; 25155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpandeimport android.content.Intent; 26155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpandeimport android.content.IntentFilter; 27155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpandeimport android.database.ContentObserver; 28155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpandeimport android.net.NetworkInfo; 29155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpandeimport android.net.wifi.ScanResult; 30155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpandeimport android.net.wifi.WifiManager; 31155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpandeimport android.os.Handler; 32155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpandeimport android.os.Message; 33155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpandeimport android.os.UserHandle; 34155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpandeimport android.provider.Settings; 35155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande 36155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpandeimport java.io.FileDescriptor; 37155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpandeimport java.io.PrintWriter; 38155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpandeimport java.util.List; 39155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande 40155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande/* Takes care of handling the "open wi-fi network available" notification @hide */ 41155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpandefinal class WifiNotificationController { 42155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande /** 43155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande * The icon to show in the 'available networks' notification. This will also 44155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande * be the ID of the Notification given to the NotificationManager. 45155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande */ 46155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande private static final int ICON_NETWORKS_AVAILABLE = 47155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande com.android.internal.R.drawable.stat_notify_wifi_in_range; 48155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande /** 49155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande * When a notification is shown, we wait this amount before possibly showing it again. 50155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande */ 51155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande private final long NOTIFICATION_REPEAT_DELAY_MS; 52155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande /** 53155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande * Whether the user has set the setting to show the 'available networks' notification. 54155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande */ 55155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande private boolean mNotificationEnabled; 56155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande /** 57155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande * Observes the user setting to keep {@link #mNotificationEnabled} in sync. 58155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande */ 59155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande private NotificationEnabledSettingObserver mNotificationEnabledSettingObserver; 60155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande /** 61155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande * The {@link System#currentTimeMillis()} must be at least this value for us 62155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande * to show the notification again. 63155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande */ 64155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande private long mNotificationRepeatTime; 65155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande /** 66155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande * The Notification object given to the NotificationManager. 67155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande */ 68155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande private Notification mNotification; 69155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande /** 70155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande * Whether the notification is being shown, as set by us. That is, if the 71155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande * user cancels the notification, we will not receive the callback so this 72155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande * will still be true. We only guarantee if this is false, then the 73155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande * notification is not showing. 74155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande */ 75155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande private boolean mNotificationShown; 76155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande /** 77155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande * The number of continuous scans that must occur before consider the 78155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande * supplicant in a scanning state. This allows supplicant to associate with 79155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande * remembered networks that are in the scan results. 80155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande */ 81155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande private static final int NUM_SCANS_BEFORE_ACTUALLY_SCANNING = 3; 82155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande /** 83155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande * The number of scans since the last network state change. When this 84155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande * exceeds {@link #NUM_SCANS_BEFORE_ACTUALLY_SCANNING}, we consider the 85155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande * supplicant to actually be scanning. When the network state changes to 86155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande * something other than scanning, we reset this to 0. 87155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande */ 88155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande private int mNumScansSinceNetworkStateChange; 89155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande 90155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande private final Context mContext; 91155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande private final WifiStateMachine mWifiStateMachine; 92155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande private NetworkInfo mNetworkInfo; 93155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande private volatile int mWifiState; 94155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande 95155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande WifiNotificationController(Context context, WifiStateMachine wsm) { 96155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande mContext = context; 97155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande mWifiStateMachine = wsm; 98155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande mWifiState = WifiManager.WIFI_STATE_UNKNOWN; 99155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande 100155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande IntentFilter filter = new IntentFilter(); 101155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION); 102155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION); 103155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande filter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION); 104155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande 105155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande mContext.registerReceiver( 106155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande new BroadcastReceiver() { 107155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande @Override 108155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande public void onReceive(Context context, Intent intent) { 109155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande if (intent.getAction().equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) { 110155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande mWifiState = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, 111155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande WifiManager.WIFI_STATE_UNKNOWN); 112155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande resetNotification(); 113155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande } else if (intent.getAction().equals( 114155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande WifiManager.NETWORK_STATE_CHANGED_ACTION)) { 115155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande mNetworkInfo = (NetworkInfo) intent.getParcelableExtra( 116155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande WifiManager.EXTRA_NETWORK_INFO); 117155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande // reset & clear notification on a network connect & disconnect 118155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande switch(mNetworkInfo.getDetailedState()) { 119155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande case CONNECTED: 120155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande case DISCONNECTED: 121155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande case CAPTIVE_PORTAL_CHECK: 122155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande resetNotification(); 123155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande break; 124155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande } 125155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande } else if (intent.getAction().equals( 126155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) { 127155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande checkAndSetNotification(mNetworkInfo, 128155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande mWifiStateMachine.syncGetScanResultsList()); 129155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande } 130155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande } 131155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande }, filter); 132155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande 133155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande // Setting is in seconds 134155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande NOTIFICATION_REPEAT_DELAY_MS = Settings.Global.getInt(context.getContentResolver(), 135155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande Settings.Global.WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY, 900) * 1000l; 136155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande mNotificationEnabledSettingObserver = new NotificationEnabledSettingObserver(new Handler()); 137155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande mNotificationEnabledSettingObserver.register(); 138155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande } 139155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande 140155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande private synchronized void checkAndSetNotification(NetworkInfo networkInfo, 141155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande List<ScanResult> scanResults) { 142c5e82ad2600416d7eafdde5d1d02400ece28e48aVinit Deshpande 143155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande // TODO: unregister broadcast so we do not have to check here 144155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande // If we shouldn't place a notification on available networks, then 145155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande // don't bother doing any of the following 146155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande if (!mNotificationEnabled) return; 147155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande if (mWifiState != WifiManager.WIFI_STATE_ENABLED) return; 148155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande 149c5e82ad2600416d7eafdde5d1d02400ece28e48aVinit Deshpande NetworkInfo.State state = NetworkInfo.State.DISCONNECTED; 150c5e82ad2600416d7eafdde5d1d02400ece28e48aVinit Deshpande if (networkInfo != null) 151c5e82ad2600416d7eafdde5d1d02400ece28e48aVinit Deshpande state = networkInfo.getState(); 152c5e82ad2600416d7eafdde5d1d02400ece28e48aVinit Deshpande 153155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande if ((state == NetworkInfo.State.DISCONNECTED) 154155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande || (state == NetworkInfo.State.UNKNOWN)) { 155155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande if (scanResults != null) { 156155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande int numOpenNetworks = 0; 157155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande for (int i = scanResults.size() - 1; i >= 0; i--) { 158155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande ScanResult scanResult = scanResults.get(i); 159155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande 160155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande //A capability of [ESS] represents an open access point 161155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande //that is available for an STA to connect 162155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande if (scanResult.capabilities != null && 163155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande scanResult.capabilities.equals("[ESS]")) { 164155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande numOpenNetworks++; 165155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande } 166155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande } 167155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande 168155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande if (numOpenNetworks > 0) { 169155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande if (++mNumScansSinceNetworkStateChange >= NUM_SCANS_BEFORE_ACTUALLY_SCANNING) { 170155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande /* 171155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande * We've scanned continuously at least 172155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande * NUM_SCANS_BEFORE_NOTIFICATION times. The user 173155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande * probably does not have a remembered network in range, 174155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande * since otherwise supplicant would have tried to 175155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande * associate and thus resetting this counter. 176155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande */ 177155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande setNotificationVisible(true, numOpenNetworks, false, 0); 178155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande } 179155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande return; 180155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande } 181155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande } 182155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande } 183155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande 184155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande // No open networks in range, remove the notification 185155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande setNotificationVisible(false, 0, false, 0); 186155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande } 187155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande 188155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande /** 189155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande * Clears variables related to tracking whether a notification has been 190155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande * shown recently and clears the current notification. 191155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande */ 192155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande private synchronized void resetNotification() { 193155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande mNotificationRepeatTime = 0; 194155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande mNumScansSinceNetworkStateChange = 0; 195155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande setNotificationVisible(false, 0, false, 0); 196155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande } 197155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande 198155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande /** 199155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande * Display or don't display a notification that there are open Wi-Fi networks. 200155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande * @param visible {@code true} if notification should be visible, {@code false} otherwise 201155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande * @param numNetworks the number networks seen 202155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande * @param force {@code true} to force notification to be shown/not-shown, 203155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande * even if it is already shown/not-shown. 204155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande * @param delay time in milliseconds after which the notification should be made 205155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande * visible or invisible. 206155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande */ 207155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande private void setNotificationVisible(boolean visible, int numNetworks, boolean force, 208155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande int delay) { 209155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande 210155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande // Since we use auto cancel on the notification, when the 211155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande // mNetworksAvailableNotificationShown is true, the notification may 212155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande // have actually been canceled. However, when it is false we know 213155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande // for sure that it is not being shown (it will not be shown any other 214155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande // place than here) 215155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande 216155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande // If it should be hidden and it is already hidden, then noop 217155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande if (!visible && !mNotificationShown && !force) { 218155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande return; 219155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande } 220155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande 221155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande NotificationManager notificationManager = (NotificationManager) mContext 222155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande .getSystemService(Context.NOTIFICATION_SERVICE); 223155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande 224155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande Message message; 225155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande if (visible) { 226155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande 227155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande // Not enough time has passed to show the notification again 228155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande if (System.currentTimeMillis() < mNotificationRepeatTime) { 229155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande return; 230155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande } 231155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande 232155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande if (mNotification == null) { 233155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande // Cache the Notification object. 234155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande mNotification = new Notification(); 235155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande mNotification.when = 0; 236155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande mNotification.icon = ICON_NETWORKS_AVAILABLE; 237155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande mNotification.flags = Notification.FLAG_AUTO_CANCEL; 238155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande mNotification.contentIntent = TaskStackBuilder.create(mContext) 239155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande .addNextIntentWithParentStack( 240155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande new Intent(WifiManager.ACTION_PICK_WIFI_NETWORK)) 241155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande .getPendingIntent(0, 0, null, UserHandle.CURRENT); 242155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande } 243155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande 244155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande CharSequence title = mContext.getResources().getQuantityText( 245155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande com.android.internal.R.plurals.wifi_available, numNetworks); 246155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande CharSequence details = mContext.getResources().getQuantityText( 247155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande com.android.internal.R.plurals.wifi_available_detailed, numNetworks); 248155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande mNotification.tickerText = title; 2490d647da4a502c1d3679d700144469460acab3d73Selim Cinek mNotification.color = mContext.getResources().getColor( 2500d647da4a502c1d3679d700144469460acab3d73Selim Cinek com.android.internal.R.color.system_notification_accent_color); 251155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande mNotification.setLatestEventInfo(mContext, title, details, mNotification.contentIntent); 252155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande 253155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande mNotificationRepeatTime = System.currentTimeMillis() + NOTIFICATION_REPEAT_DELAY_MS; 254155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande 255155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande notificationManager.notifyAsUser(null, ICON_NETWORKS_AVAILABLE, mNotification, 256155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande UserHandle.ALL); 257155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande } else { 258155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande notificationManager.cancelAsUser(null, ICON_NETWORKS_AVAILABLE, UserHandle.ALL); 259155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande } 260155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande 261155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande mNotificationShown = visible; 262155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande } 263155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande 264155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 265155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande pw.println("mNotificationEnabled " + mNotificationEnabled); 266155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande pw.println("mNotificationRepeatTime " + mNotificationRepeatTime); 267155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande pw.println("mNotificationShown " + mNotificationShown); 268155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande pw.println("mNumScansSinceNetworkStateChange " + mNumScansSinceNetworkStateChange); 269155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande } 270155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande 271155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande private class NotificationEnabledSettingObserver extends ContentObserver { 272155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande public NotificationEnabledSettingObserver(Handler handler) { 273155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande super(handler); 274155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande } 275155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande 276155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande public void register() { 277155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande ContentResolver cr = mContext.getContentResolver(); 278155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande cr.registerContentObserver(Settings.Global.getUriFor( 279155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande Settings.Global.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON), true, this); 280155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande synchronized (WifiNotificationController.this) { 281155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande mNotificationEnabled = getValue(); 282155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande } 283155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande } 284155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande 285155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande @Override 286155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande public void onChange(boolean selfChange) { 287155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande super.onChange(selfChange); 288155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande 289155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande synchronized (WifiNotificationController.this) { 290155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande mNotificationEnabled = getValue(); 291155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande resetNotification(); 292155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande } 293155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande } 294155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande 295155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande private boolean getValue() { 296155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande return Settings.Global.getInt(mContext.getContentResolver(), 297155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande Settings.Global.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON, 1) == 1; 298155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande } 299155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande } 300155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande 301155b9d09ef9b8ead3ca617afdd91e74070d3f0cbVinit Deshpande} 302