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