1 /* 2 * Copyright (C) 2018 The Android Open Source Project 3 * 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 17 package com.android.server.wifi; 18 19 import static com.android.server.wifi.ConnectToNetworkNotificationBuilder.ACTION_CONNECT_TO_NETWORK; 20 import static com.android.server.wifi.ConnectToNetworkNotificationBuilder.ACTION_PICK_WIFI_NETWORK; 21 import static com.android.server.wifi.ConnectToNetworkNotificationBuilder.ACTION_PICK_WIFI_NETWORK_AFTER_CONNECT_FAILURE; 22 import static com.android.server.wifi.ConnectToNetworkNotificationBuilder.ACTION_USER_DISMISSED_NOTIFICATION; 23 import static com.android.server.wifi.ConnectToNetworkNotificationBuilder.AVAILABLE_NETWORK_NOTIFIER_TAG; 24 25 import android.annotation.IntDef; 26 import android.annotation.NonNull; 27 import android.annotation.Nullable; 28 import android.app.Notification; 29 import android.content.BroadcastReceiver; 30 import android.content.Context; 31 import android.content.Intent; 32 import android.content.IntentFilter; 33 import android.database.ContentObserver; 34 import android.net.wifi.IActionListener; 35 import android.net.wifi.ScanResult; 36 import android.net.wifi.WifiConfiguration; 37 import android.os.Handler; 38 import android.os.Looper; 39 import android.os.Process; 40 import android.os.UserHandle; 41 import android.os.UserManager; 42 import android.provider.Settings; 43 import android.text.TextUtils; 44 import android.util.ArraySet; 45 import android.util.Log; 46 47 import com.android.internal.annotations.VisibleForTesting; 48 import com.android.server.wifi.proto.nano.WifiMetricsProto.ConnectToNetworkNotificationAndActionCount; 49 import com.android.server.wifi.util.ActionListenerWrapper; 50 import com.android.server.wifi.util.ScanResultUtil; 51 52 import java.io.FileDescriptor; 53 import java.io.PrintWriter; 54 import java.lang.annotation.Retention; 55 import java.lang.annotation.RetentionPolicy; 56 import java.util.List; 57 import java.util.Set; 58 59 /** 60 * Base class for all network notifiers (e.g. OpenNetworkNotifier). 61 * 62 * NOTE: These API's are not thread safe and should only be used from WifiCoreThread. 63 */ 64 public class AvailableNetworkNotifier { 65 66 /** Time in milliseconds to display the Connecting notification. */ 67 private static final int TIME_TO_SHOW_CONNECTING_MILLIS = 10000; 68 69 /** Time in milliseconds to display the Connected notification. */ 70 private static final int TIME_TO_SHOW_CONNECTED_MILLIS = 5000; 71 72 /** Time in milliseconds to display the Failed To Connect notification. */ 73 private static final int TIME_TO_SHOW_FAILED_MILLIS = 5000; 74 75 /** The state of the notification */ 76 @IntDef({ 77 STATE_NO_NOTIFICATION, 78 STATE_SHOWING_RECOMMENDATION_NOTIFICATION, 79 STATE_CONNECTING_IN_NOTIFICATION, 80 STATE_CONNECTED_NOTIFICATION, 81 STATE_CONNECT_FAILED_NOTIFICATION 82 }) 83 @Retention(RetentionPolicy.SOURCE) 84 private @interface State {} 85 86 /** No recommendation is made and no notifications are shown. */ 87 private static final int STATE_NO_NOTIFICATION = 0; 88 /** The initial notification recommending a network to connect to is shown. */ 89 @VisibleForTesting 90 static final int STATE_SHOWING_RECOMMENDATION_NOTIFICATION = 1; 91 /** The notification of status of connecting to the recommended network is shown. */ 92 private static final int STATE_CONNECTING_IN_NOTIFICATION = 2; 93 /** The notification that the connection to the recommended network was successful is shown. */ 94 private static final int STATE_CONNECTED_NOTIFICATION = 3; 95 /** The notification to show that connection to the recommended network failed is shown. */ 96 private static final int STATE_CONNECT_FAILED_NOTIFICATION = 4; 97 98 /** Current state of the notification. */ 99 @VisibleForTesting 100 @State int mState = STATE_NO_NOTIFICATION; 101 102 /** 103 * The {@link Clock#getWallClockMillis()} must be at least this value for us 104 * to show the notification again. 105 */ 106 private long mNotificationRepeatTime; 107 /** 108 * When a notification is shown, we wait this amount before possibly showing it again. 109 */ 110 private final long mNotificationRepeatDelay; 111 /** Default repeat delay in seconds. */ 112 @VisibleForTesting 113 static final int DEFAULT_REPEAT_DELAY_SEC = 900; 114 115 /** Whether the user has set the setting to show the 'available networks' notification. */ 116 private boolean mSettingEnabled; 117 /** Whether the screen is on or not. */ 118 private boolean mScreenOn; 119 120 /** List of SSIDs blocklisted from recommendation. */ 121 private final Set<String> mBlocklistedSsids = new ArraySet<>(); 122 123 private final WifiContext mContext; 124 private final Handler mHandler; 125 private final FrameworkFacade mFrameworkFacade; 126 private final WifiMetrics mWifiMetrics; 127 private final Clock mClock; 128 private final WifiConfigManager mConfigManager; 129 private final ConnectHelper mConnectHelper; 130 private final ConnectToNetworkNotificationBuilder mNotificationBuilder; 131 private final MakeBeforeBreakManager mMakeBeforeBreakManager; 132 private final WifiNotificationManager mWifiNotificationManager; 133 134 @VisibleForTesting 135 ScanResult mRecommendedNetwork; 136 137 /** Tag used for logs and metrics */ 138 private final String mTag; 139 /** Identifier of the {@link SsidSetStoreData}. */ 140 private final String mStoreDataIdentifier; 141 /** Identifier for the settings toggle, used for registering ContentObserver */ 142 private final String mToggleSettingsName; 143 144 /** System wide identifier for notification in Notification Manager */ 145 private final int mSystemMessageNotificationId; 146 147 /** 148 * The nominator id for this class, from 149 * {@link com.android.server.wifi.proto.nano.WifiMetricsProto.ConnectionEvent. 150 * ConnectionNominator} 151 */ 152 private final int mNominatorId; 153 AvailableNetworkNotifier( String tag, String storeDataIdentifier, String toggleSettingsName, int notificationIdentifier, int nominatorId, WifiContext context, Looper looper, FrameworkFacade framework, Clock clock, WifiMetrics wifiMetrics, WifiConfigManager wifiConfigManager, WifiConfigStore wifiConfigStore, ConnectHelper connectHelper, ConnectToNetworkNotificationBuilder connectToNetworkNotificationBuilder, MakeBeforeBreakManager makeBeforeBreakManager, WifiNotificationManager wifiNotificationManager)154 public AvailableNetworkNotifier( 155 String tag, 156 String storeDataIdentifier, 157 String toggleSettingsName, 158 int notificationIdentifier, 159 int nominatorId, 160 WifiContext context, 161 Looper looper, 162 FrameworkFacade framework, 163 Clock clock, 164 WifiMetrics wifiMetrics, 165 WifiConfigManager wifiConfigManager, 166 WifiConfigStore wifiConfigStore, 167 ConnectHelper connectHelper, 168 ConnectToNetworkNotificationBuilder connectToNetworkNotificationBuilder, 169 MakeBeforeBreakManager makeBeforeBreakManager, 170 WifiNotificationManager wifiNotificationManager) { 171 mTag = tag; 172 mStoreDataIdentifier = storeDataIdentifier; 173 mToggleSettingsName = toggleSettingsName; 174 mSystemMessageNotificationId = notificationIdentifier; 175 mNominatorId = nominatorId; 176 mContext = context; 177 mHandler = new Handler(looper); 178 mFrameworkFacade = framework; 179 mWifiMetrics = wifiMetrics; 180 mClock = clock; 181 mConfigManager = wifiConfigManager; 182 mConnectHelper = connectHelper; 183 mNotificationBuilder = connectToNetworkNotificationBuilder; 184 mMakeBeforeBreakManager = makeBeforeBreakManager; 185 mWifiNotificationManager = wifiNotificationManager; 186 mScreenOn = false; 187 wifiConfigStore.registerStoreData(new SsidSetStoreData(mStoreDataIdentifier, 188 new AvailableNetworkNotifierStoreData())); 189 190 // Setting is in seconds 191 mNotificationRepeatDelay = mFrameworkFacade.getIntegerSetting(context, 192 Settings.Global.WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY, 193 DEFAULT_REPEAT_DELAY_SEC) * 1000L; 194 NotificationEnabledSettingObserver settingObserver = new NotificationEnabledSettingObserver( 195 mHandler); 196 settingObserver.register(); 197 198 IntentFilter filter = new IntentFilter(); 199 filter.addAction(ACTION_USER_DISMISSED_NOTIFICATION); 200 filter.addAction(ACTION_CONNECT_TO_NETWORK); 201 filter.addAction(ACTION_PICK_WIFI_NETWORK); 202 filter.addAction(ACTION_PICK_WIFI_NETWORK_AFTER_CONNECT_FAILURE); 203 mContext.registerReceiver( 204 mBroadcastReceiver, filter, null /* broadcastPermission */, mHandler); 205 } 206 207 private final BroadcastReceiver mBroadcastReceiver = 208 new BroadcastReceiver() { 209 @Override 210 public void onReceive(Context context, Intent intent) { 211 if (!mTag.equals(intent.getStringExtra(AVAILABLE_NETWORK_NOTIFIER_TAG))) { 212 return; 213 } 214 switch (intent.getAction()) { 215 case ACTION_USER_DISMISSED_NOTIFICATION: 216 handleUserDismissedAction(); 217 break; 218 case ACTION_CONNECT_TO_NETWORK: 219 handleConnectToNetworkAction(); 220 break; 221 case ACTION_PICK_WIFI_NETWORK: 222 handleSeeAllNetworksAction(); 223 break; 224 case ACTION_PICK_WIFI_NETWORK_AFTER_CONNECT_FAILURE: 225 handlePickWifiNetworkAfterConnectFailure(); 226 break; 227 default: 228 Log.e(mTag, "Unknown action " + intent.getAction()); 229 } 230 } 231 }; 232 233 private final class ConnectActionListener extends IActionListener.Stub { 234 @Override onSuccess()235 public void onSuccess() { 236 // Success here means that an attempt to connect to the network has been initiated. 237 // Successful connection updates are received via the 238 // WifiConnectivityManager#handleConnectionStateChanged() callback. 239 } 240 241 @Override onFailure(int reason)242 public void onFailure(int reason) { 243 handleConnectionAttemptFailedToSend(); 244 } 245 } 246 247 /** 248 * Clears the pending notification. This is called by {@link WifiConnectivityManager} on stop. 249 * 250 * @param resetRepeatTime resets the time delay for repeated notification if true. 251 */ clearPendingNotification(boolean resetRepeatTime)252 public void clearPendingNotification(boolean resetRepeatTime) { 253 if (resetRepeatTime) { 254 mNotificationRepeatTime = 0; 255 } 256 257 if (mState != STATE_NO_NOTIFICATION) { 258 mWifiNotificationManager.cancel(mSystemMessageNotificationId); 259 260 if (mRecommendedNetwork != null) { 261 Log.d(mTag, "Notification with state=" 262 + mState 263 + " was cleared for recommended network: " 264 + "\"" + mRecommendedNetwork.SSID + "\""); 265 } 266 mState = STATE_NO_NOTIFICATION; 267 mRecommendedNetwork = null; 268 } 269 } 270 isControllerEnabled()271 private boolean isControllerEnabled() { 272 return mSettingEnabled && !mContext.getSystemService(UserManager.class) 273 .hasUserRestrictionForUser(UserManager.DISALLOW_CONFIG_WIFI, 274 UserHandle.CURRENT); 275 } 276 277 /** 278 * If there are available networks, attempt to post a network notification. 279 * 280 * @param availableNetworks Available networks to choose from and possibly show notification 281 */ handleScanResults(@onNull List<ScanDetail> availableNetworks)282 public void handleScanResults(@NonNull List<ScanDetail> availableNetworks) { 283 if (!isControllerEnabled()) { 284 clearPendingNotification(true /* resetRepeatTime */); 285 return; 286 } 287 if (availableNetworks.isEmpty() && mState == STATE_SHOWING_RECOMMENDATION_NOTIFICATION) { 288 clearPendingNotification(false /* resetRepeatTime */); 289 return; 290 } 291 292 // Not enough time has passed to show a recommendation notification again 293 if (mState == STATE_NO_NOTIFICATION 294 && mClock.getWallClockMillis() < mNotificationRepeatTime) { 295 return; 296 } 297 298 // Do nothing when the screen is off and no notification is showing. 299 if (mState == STATE_NO_NOTIFICATION && !mScreenOn) { 300 return; 301 } 302 303 // Only show a new or update an existing recommendation notification. 304 if (mState == STATE_NO_NOTIFICATION 305 || mState == STATE_SHOWING_RECOMMENDATION_NOTIFICATION) { 306 ScanResult recommendation = 307 recommendNetwork(availableNetworks); 308 309 if (recommendation != null) { 310 postInitialNotification(recommendation); 311 } else { 312 clearPendingNotification(false /* resetRepeatTime */); 313 } 314 } 315 } 316 317 /** 318 * Recommends a network to connect to from a list of available networks, while ignoring the 319 * SSIDs in the blocklist. 320 * 321 * @param networks List of networks to select from 322 */ recommendNetwork(@onNull List<ScanDetail> networks)323 public ScanResult recommendNetwork(@NonNull List<ScanDetail> networks) { 324 ScanResult result = null; 325 int highestRssi = Integer.MIN_VALUE; 326 for (ScanDetail scanDetail : networks) { 327 ScanResult scanResult = scanDetail.getScanResult(); 328 329 if (scanResult.level > highestRssi) { 330 result = scanResult; 331 highestRssi = scanResult.level; 332 } 333 } 334 335 if (result != null && mBlocklistedSsids.contains(result.SSID)) { 336 result = null; 337 } 338 return result; 339 } 340 341 /** Handles screen state changes. */ handleScreenStateChanged(boolean screenOn)342 public void handleScreenStateChanged(boolean screenOn) { 343 mScreenOn = screenOn; 344 } 345 346 /** 347 * Called by {@link WifiConnectivityManager} when Wi-Fi is connected. If the notification 348 * was in the connecting state, update the notification to show that it has connected to the 349 * recommended network. 350 * 351 * @param ssid The connected network's ssid 352 */ handleWifiConnected(String ssid)353 public void handleWifiConnected(String ssid) { 354 removeNetworkFromBlocklist(ssid); 355 if (mState != STATE_CONNECTING_IN_NOTIFICATION) { 356 clearPendingNotification(true /* resetRepeatTime */); 357 return; 358 } 359 360 postNotification(mNotificationBuilder.createNetworkConnectedNotification(mTag, 361 mRecommendedNetwork)); 362 363 Log.d(mTag, "User connected to recommended network: " 364 + "\"" + mRecommendedNetwork.SSID + "\""); 365 mWifiMetrics.incrementConnectToNetworkNotification(mTag, 366 ConnectToNetworkNotificationAndActionCount.NOTIFICATION_CONNECTED_TO_NETWORK); 367 mState = STATE_CONNECTED_NOTIFICATION; 368 mHandler.postDelayed( 369 () -> { 370 if (mState == STATE_CONNECTED_NOTIFICATION) { 371 clearPendingNotification(true /* resetRepeatTime */); 372 } 373 }, 374 TIME_TO_SHOW_CONNECTED_MILLIS); 375 } 376 377 /** 378 * Handles when a Wi-Fi connection attempt failed. 379 */ handleConnectionFailure()380 public void handleConnectionFailure() { 381 if (mState != STATE_CONNECTING_IN_NOTIFICATION) { 382 return; 383 } 384 postNotification(mNotificationBuilder.createNetworkFailedNotification(mTag)); 385 386 Log.d(mTag, "User failed to connect to recommended network: " 387 + "\"" + mRecommendedNetwork.SSID + "\""); 388 mWifiMetrics.incrementConnectToNetworkNotification(mTag, 389 ConnectToNetworkNotificationAndActionCount.NOTIFICATION_FAILED_TO_CONNECT); 390 mState = STATE_CONNECT_FAILED_NOTIFICATION; 391 mHandler.postDelayed( 392 () -> { 393 if (mState == STATE_CONNECT_FAILED_NOTIFICATION) { 394 clearPendingNotification(false /* resetRepeatTime */); 395 } 396 }, 397 TIME_TO_SHOW_FAILED_MILLIS); 398 } 399 postInitialNotification(ScanResult recommendedNetwork)400 private void postInitialNotification(ScanResult recommendedNetwork) { 401 if (mRecommendedNetwork != null 402 && TextUtils.equals(mRecommendedNetwork.SSID, recommendedNetwork.SSID)) { 403 return; 404 } 405 406 postNotification(mNotificationBuilder.createConnectToAvailableNetworkNotification(mTag, 407 recommendedNetwork)); 408 409 if (mState == STATE_NO_NOTIFICATION) { 410 mWifiMetrics.incrementConnectToNetworkNotification(mTag, 411 ConnectToNetworkNotificationAndActionCount.NOTIFICATION_RECOMMEND_NETWORK); 412 } else { 413 mWifiMetrics.incrementNumNetworkRecommendationUpdates(mTag); 414 } 415 mState = STATE_SHOWING_RECOMMENDATION_NOTIFICATION; 416 mRecommendedNetwork = recommendedNetwork; 417 mNotificationRepeatTime = mClock.getWallClockMillis() + mNotificationRepeatDelay; 418 } 419 postNotification(Notification notification)420 private void postNotification(Notification notification) { 421 mWifiNotificationManager.notify(mSystemMessageNotificationId, notification); 422 } 423 handleConnectToNetworkAction()424 private void handleConnectToNetworkAction() { 425 mWifiMetrics.incrementConnectToNetworkNotificationAction(mTag, mState, 426 ConnectToNetworkNotificationAndActionCount.ACTION_CONNECT_TO_NETWORK); 427 if (mState != STATE_SHOWING_RECOMMENDATION_NOTIFICATION) { 428 return; 429 } 430 postNotification(mNotificationBuilder.createNetworkConnectingNotification(mTag, 431 mRecommendedNetwork)); 432 mWifiMetrics.incrementConnectToNetworkNotification(mTag, 433 ConnectToNetworkNotificationAndActionCount.NOTIFICATION_CONNECTING_TO_NETWORK); 434 435 Log.d(mTag, 436 "User initiated connection to recommended network: " 437 + "\"" + mRecommendedNetwork.SSID + "\""); 438 WifiConfiguration network = createRecommendedNetworkConfig(mRecommendedNetwork); 439 if (null == network) { 440 Log.e(mTag, "Cannot create the network from the scan result."); 441 return; 442 } 443 444 NetworkUpdateResult result = mConfigManager.addOrUpdateNetwork(network, Process.WIFI_UID); 445 if (result.isSuccess()) { 446 mWifiMetrics.setNominatorForNetwork(result.getNetworkId(), mNominatorId); 447 ConnectActionListener listener = new ConnectActionListener(); 448 mMakeBeforeBreakManager.stopAllSecondaryTransientClientModeManagers(() -> 449 mConnectHelper.connectToNetwork( 450 // only keep netId, discard other fields 451 new NetworkUpdateResult(result.getNetworkId()), 452 new ActionListenerWrapper(listener), 453 Process.SYSTEM_UID)); 454 addNetworkToBlocklist(mRecommendedNetwork.SSID); 455 } 456 457 mState = STATE_CONNECTING_IN_NOTIFICATION; 458 mHandler.postDelayed( 459 () -> { 460 if (mState == STATE_CONNECTING_IN_NOTIFICATION) { 461 handleConnectionFailure(); 462 } 463 }, 464 TIME_TO_SHOW_CONNECTING_MILLIS); 465 } 466 addNetworkToBlocklist(String ssid)467 private void addNetworkToBlocklist(String ssid) { 468 mBlocklistedSsids.add(ssid); 469 mWifiMetrics.setNetworkRecommenderBlocklistSize(mTag, mBlocklistedSsids.size()); 470 mConfigManager.saveToStore(false /* forceWrite */); 471 Log.d(mTag, "Network is added to the network notification blocklist: " 472 + "\"" + ssid + "\""); 473 } 474 removeNetworkFromBlocklist(String ssid)475 private void removeNetworkFromBlocklist(String ssid) { 476 if (ssid == null) { 477 return; 478 } 479 if (!mBlocklistedSsids.remove(ssid)) { 480 return; 481 } 482 mWifiMetrics.setNetworkRecommenderBlocklistSize(mTag, mBlocklistedSsids.size()); 483 mConfigManager.saveToStore(false /* forceWrite */); 484 Log.d(mTag, "Network is removed from the network notification blocklist: " 485 + "\"" + ssid + "\""); 486 } 487 createRecommendedNetworkConfig(ScanResult recommendedNetwork)488 @Nullable WifiConfiguration createRecommendedNetworkConfig(ScanResult recommendedNetwork) { 489 return ScanResultUtil.createNetworkFromScanResult(recommendedNetwork); 490 } 491 handleSeeAllNetworksAction()492 private void handleSeeAllNetworksAction() { 493 mWifiMetrics.incrementConnectToNetworkNotificationAction(mTag, mState, 494 ConnectToNetworkNotificationAndActionCount.ACTION_PICK_WIFI_NETWORK); 495 startWifiSettings(); 496 } 497 startWifiSettings()498 private void startWifiSettings() { 499 // Close notification drawer before opening the picker. 500 mContext.sendBroadcast(new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)); 501 mContext.startActivity( 502 new Intent(Settings.ACTION_WIFI_SETTINGS) 503 .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)); 504 clearPendingNotification(false /* resetRepeatTime */); 505 } 506 handleConnectionAttemptFailedToSend()507 private void handleConnectionAttemptFailedToSend() { 508 handleConnectionFailure(); 509 mWifiMetrics.incrementNumNetworkConnectMessageFailedToSend(mTag); 510 } 511 handlePickWifiNetworkAfterConnectFailure()512 private void handlePickWifiNetworkAfterConnectFailure() { 513 mWifiMetrics.incrementConnectToNetworkNotificationAction(mTag, mState, 514 ConnectToNetworkNotificationAndActionCount 515 .ACTION_PICK_WIFI_NETWORK_AFTER_CONNECT_FAILURE); 516 startWifiSettings(); 517 } 518 handleUserDismissedAction()519 private void handleUserDismissedAction() { 520 Log.d(mTag, "User dismissed notification with state=" + mState); 521 mWifiMetrics.incrementConnectToNetworkNotificationAction(mTag, mState, 522 ConnectToNetworkNotificationAndActionCount.ACTION_USER_DISMISSED_NOTIFICATION); 523 if (mState == STATE_SHOWING_RECOMMENDATION_NOTIFICATION) { 524 // blocklist dismissed network 525 addNetworkToBlocklist(mRecommendedNetwork.SSID); 526 } 527 resetStateAndDelayNotification(); 528 } 529 resetStateAndDelayNotification()530 private void resetStateAndDelayNotification() { 531 mState = STATE_NO_NOTIFICATION; 532 mNotificationRepeatTime = System.currentTimeMillis() + mNotificationRepeatDelay; 533 mRecommendedNetwork = null; 534 } 535 536 /** Dump this network notifier's state. */ dump(FileDescriptor fd, PrintWriter pw, String[] args)537 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 538 pw.println(mTag + ": "); 539 pw.println("mSettingEnabled " + mSettingEnabled); 540 pw.println("currentTime: " + mClock.getWallClockMillis()); 541 pw.println("mNotificationRepeatTime: " + mNotificationRepeatTime); 542 pw.println("mState: " + mState); 543 pw.println("mBlocklistedSsids: " + mBlocklistedSsids.toString()); 544 } 545 546 private class AvailableNetworkNotifierStoreData implements SsidSetStoreData.DataSource { 547 @Override getSsids()548 public Set<String> getSsids() { 549 return new ArraySet<>(mBlocklistedSsids); 550 } 551 552 @Override setSsids(Set<String> ssidList)553 public void setSsids(Set<String> ssidList) { 554 mBlocklistedSsids.addAll(ssidList); 555 mWifiMetrics.setNetworkRecommenderBlocklistSize(mTag, mBlocklistedSsids.size()); 556 } 557 } 558 559 private class NotificationEnabledSettingObserver extends ContentObserver { NotificationEnabledSettingObserver(Handler handler)560 NotificationEnabledSettingObserver(Handler handler) { 561 super(handler); 562 } 563 register()564 public void register() { 565 mFrameworkFacade.registerContentObserver(mContext, 566 Settings.Global.getUriFor(mToggleSettingsName), true, this); 567 mSettingEnabled = getValue(); 568 } 569 570 @Override onChange(boolean selfChange)571 public void onChange(boolean selfChange) { 572 super.onChange(selfChange); 573 mSettingEnabled = getValue(); 574 clearPendingNotification(true /* resetRepeatTime */); 575 } 576 getValue()577 private boolean getValue() { 578 boolean enabled = 579 mFrameworkFacade.getIntegerSetting(mContext, mToggleSettingsName, 1) == 1; 580 mWifiMetrics.setIsWifiNetworksAvailableNotificationEnabled(mTag, enabled); 581 Log.d(mTag, "Settings toggle enabled=" + enabled); 582 return enabled; 583 } 584 } 585 } 586