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 Log.i(mTag, "notification canceled"); 267 268 if (mRecommendedNetwork != null) { 269 Log.d(mTag, "Notification with state=" 270 + mState 271 + " was cleared for recommended network: " 272 + "\"" + mRecommendedNetwork.SSID + "\""); 273 } 274 mState = STATE_NO_NOTIFICATION; 275 mRecommendedNetwork = null; 276 } 277 } 278 isSettingEnabled()279 public boolean isSettingEnabled() { 280 return mSettingEnabled; 281 } 282 isControllerEnabled()283 private boolean isControllerEnabled() { 284 UserManager userManager = mContext.getSystemService(UserManager.class); 285 UserHandle currentUser = UserHandle.of(mWifiPermissionsUtil.getCurrentUser()); 286 return mSettingEnabled 287 && !userManager.hasUserRestrictionForUser( 288 UserManager.DISALLOW_CONFIG_WIFI, currentUser) 289 && !(SdkLevel.isAtLeastT() && userManager.hasUserRestrictionForUser( 290 UserManager.DISALLOW_ADD_WIFI_CONFIG, currentUser)); 291 } 292 293 /** 294 * If there are available networks, attempt to post a network notification. 295 * 296 * @param availableNetworks Available networks to choose from and possibly show notification 297 */ handleScanResults(@onNull List<ScanDetail> availableNetworks)298 public void handleScanResults(@NonNull List<ScanDetail> availableNetworks) { 299 if (!isControllerEnabled()) { 300 clearPendingNotification(true /* resetRepeatTime */); 301 return; 302 } 303 if (availableNetworks.isEmpty() && mState == STATE_SHOWING_RECOMMENDATION_NOTIFICATION) { 304 clearPendingNotification(false /* resetRepeatTime */); 305 return; 306 } 307 308 // Not enough time has passed to show a recommendation notification again 309 if (mState == STATE_NO_NOTIFICATION 310 && mClock.getWallClockMillis() < mNotificationRepeatTime) { 311 return; 312 } 313 314 // Do nothing when the screen is off and no notification is showing. 315 if (mState == STATE_NO_NOTIFICATION && !mScreenOn) { 316 return; 317 } 318 319 // Only show a new or update an existing recommendation notification. 320 if (mState == STATE_NO_NOTIFICATION 321 || mState == STATE_SHOWING_RECOMMENDATION_NOTIFICATION) { 322 ScanResult recommendation = 323 recommendNetwork(availableNetworks); 324 325 if (recommendation != null) { 326 postInitialNotification(recommendation); 327 } else { 328 clearPendingNotification(false /* resetRepeatTime */); 329 } 330 } 331 } 332 333 /** 334 * Recommends a network to connect to from a list of available networks, while ignoring the 335 * SSIDs in the blocklist. 336 * 337 * @param networks List of networks to select from 338 */ recommendNetwork(@onNull List<ScanDetail> networks)339 public ScanResult recommendNetwork(@NonNull List<ScanDetail> networks) { 340 ScanResult result = null; 341 int highestRssi = Integer.MIN_VALUE; 342 for (ScanDetail scanDetail : networks) { 343 ScanResult scanResult = scanDetail.getScanResult(); 344 345 if (scanResult.level > highestRssi) { 346 result = scanResult; 347 highestRssi = scanResult.level; 348 } 349 } 350 351 if (result != null && mBlocklistedSsids.contains(result.SSID)) { 352 result = null; 353 } 354 return result; 355 } 356 357 /** Handles screen state changes. */ handleScreenStateChanged(boolean screenOn)358 public void handleScreenStateChanged(boolean screenOn) { 359 mScreenOn = screenOn; 360 } 361 362 /** 363 * Called by {@link WifiConnectivityManager} when Wi-Fi is connected. If the notification 364 * was in the connecting state, update the notification to show that it has connected to the 365 * recommended network. 366 * 367 * @param ssid The connected network's ssid 368 */ handleWifiConnected(String ssid)369 public void handleWifiConnected(String ssid) { 370 removeNetworkFromBlocklist(ssid); 371 if (mState != STATE_CONNECTING_IN_NOTIFICATION) { 372 clearPendingNotification(true /* resetRepeatTime */); 373 return; 374 } 375 376 postNotification(mNotificationBuilder.createNetworkConnectedNotification(mTag, 377 mRecommendedNetwork)); 378 379 Log.d(mTag, "User connected to recommended network: " 380 + "\"" + mRecommendedNetwork.SSID + "\""); 381 mWifiMetrics.incrementConnectToNetworkNotification(mTag, 382 ConnectToNetworkNotificationAndActionCount.NOTIFICATION_CONNECTED_TO_NETWORK); 383 mState = STATE_CONNECTED_NOTIFICATION; 384 mHandler.postDelayed( 385 () -> { 386 if (mState == STATE_CONNECTED_NOTIFICATION) { 387 clearPendingNotification(true /* resetRepeatTime */); 388 } 389 }, 390 TIME_TO_SHOW_CONNECTED_MILLIS); 391 } 392 393 /** 394 * Handles when a Wi-Fi connection attempt failed. 395 */ handleConnectionFailure()396 public void handleConnectionFailure() { 397 if (mState != STATE_CONNECTING_IN_NOTIFICATION) { 398 return; 399 } 400 postNotification(mNotificationBuilder.createNetworkFailedNotification(mTag)); 401 402 Log.d(mTag, "User failed to connect to recommended network: " 403 + "\"" + mRecommendedNetwork.SSID + "\""); 404 mWifiMetrics.incrementConnectToNetworkNotification(mTag, 405 ConnectToNetworkNotificationAndActionCount.NOTIFICATION_FAILED_TO_CONNECT); 406 mState = STATE_CONNECT_FAILED_NOTIFICATION; 407 mHandler.postDelayed( 408 () -> { 409 if (mState == STATE_CONNECT_FAILED_NOTIFICATION) { 410 clearPendingNotification(false /* resetRepeatTime */); 411 } 412 }, 413 TIME_TO_SHOW_FAILED_MILLIS); 414 } 415 postInitialNotification(ScanResult recommendedNetwork)416 private void postInitialNotification(ScanResult recommendedNetwork) { 417 if (mRecommendedNetwork != null 418 && TextUtils.equals(mRecommendedNetwork.SSID, recommendedNetwork.SSID)) { 419 return; 420 } 421 422 postNotification(mNotificationBuilder.createConnectToAvailableNetworkNotification(mTag, 423 recommendedNetwork)); 424 425 if (mState == STATE_NO_NOTIFICATION) { 426 mWifiMetrics.incrementConnectToNetworkNotification(mTag, 427 ConnectToNetworkNotificationAndActionCount.NOTIFICATION_RECOMMEND_NETWORK); 428 } else { 429 mWifiMetrics.incrementNumNetworkRecommendationUpdates(mTag); 430 } 431 mState = STATE_SHOWING_RECOMMENDATION_NOTIFICATION; 432 mRecommendedNetwork = recommendedNetwork; 433 mNotificationRepeatTime = mClock.getWallClockMillis() + mNotificationRepeatDelay; 434 } 435 postNotification(Notification notification)436 private void postNotification(Notification notification) { 437 mWifiNotificationManager.notify(mSystemMessageNotificationId, notification); 438 Log.i(mTag, "notification send"); 439 } 440 handleConnectToNetworkAction()441 private void handleConnectToNetworkAction() { 442 mWifiMetrics.incrementConnectToNetworkNotificationAction(mTag, mState, 443 ConnectToNetworkNotificationAndActionCount.ACTION_CONNECT_TO_NETWORK); 444 if (mState != STATE_SHOWING_RECOMMENDATION_NOTIFICATION) { 445 return; 446 } 447 postNotification(mNotificationBuilder.createNetworkConnectingNotification(mTag, 448 mRecommendedNetwork)); 449 mWifiMetrics.incrementConnectToNetworkNotification(mTag, 450 ConnectToNetworkNotificationAndActionCount.NOTIFICATION_CONNECTING_TO_NETWORK); 451 452 Log.d(mTag, 453 "User initiated connection to recommended network: " 454 + "\"" + mRecommendedNetwork.SSID + "\""); 455 WifiConfiguration network = createRecommendedNetworkConfig(mRecommendedNetwork); 456 if (null == network) { 457 Log.e(mTag, "Cannot create the network from the scan result."); 458 return; 459 } 460 461 NetworkUpdateResult result = mConfigManager.addOrUpdateNetwork(network, Process.WIFI_UID); 462 if (result.isSuccess()) { 463 mWifiMetrics.setNominatorForNetwork(result.getNetworkId(), mNominatorId); 464 ConnectActionListener listener = new ConnectActionListener(); 465 mMakeBeforeBreakManager.stopAllSecondaryTransientClientModeManagers(() -> 466 mConnectHelper.connectToNetwork( 467 // only keep netId, discard other fields 468 new NetworkUpdateResult(result.getNetworkId()), 469 new ActionListenerWrapper(listener), 470 Process.SYSTEM_UID, mContext.getOpPackageName(), null)); 471 addNetworkToBlocklist(mRecommendedNetwork.SSID); 472 } 473 474 mState = STATE_CONNECTING_IN_NOTIFICATION; 475 mHandler.postDelayed( 476 () -> { 477 if (mState == STATE_CONNECTING_IN_NOTIFICATION) { 478 handleConnectionFailure(); 479 } 480 }, 481 TIME_TO_SHOW_CONNECTING_MILLIS); 482 } 483 addNetworkToBlocklist(String ssid)484 private void addNetworkToBlocklist(String ssid) { 485 mBlocklistedSsids.add(ssid); 486 mWifiMetrics.setNetworkRecommenderBlocklistSize(mTag, mBlocklistedSsids.size()); 487 mConfigManager.saveToStore(); 488 Log.d(mTag, "Network is added to the network notification blocklist: " 489 + "\"" + ssid + "\""); 490 } 491 removeNetworkFromBlocklist(String ssid)492 private void removeNetworkFromBlocklist(String ssid) { 493 if (ssid == null) { 494 return; 495 } 496 if (!mBlocklistedSsids.remove(ssid)) { 497 return; 498 } 499 mWifiMetrics.setNetworkRecommenderBlocklistSize(mTag, mBlocklistedSsids.size()); 500 mConfigManager.saveToStore(); 501 Log.d(mTag, "Network is removed from the network notification blocklist: " 502 + "\"" + ssid + "\""); 503 } 504 createRecommendedNetworkConfig(ScanResult recommendedNetwork)505 @Nullable WifiConfiguration createRecommendedNetworkConfig(ScanResult recommendedNetwork) { 506 return ScanResultUtil.createNetworkFromScanResult(recommendedNetwork); 507 } 508 handleSeeAllNetworksAction()509 private void handleSeeAllNetworksAction() { 510 mWifiMetrics.incrementConnectToNetworkNotificationAction(mTag, mState, 511 ConnectToNetworkNotificationAndActionCount.ACTION_PICK_WIFI_NETWORK); 512 startWifiSettings(); 513 } 514 startWifiSettings()515 private void startWifiSettings() { 516 // Close notification drawer before opening the picker. 517 mContext.sendBroadcast(new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)); 518 mContext.startActivityAsUser( 519 new Intent(Settings.ACTION_WIFI_SETTINGS) 520 .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK), 521 UserHandle.CURRENT); 522 clearPendingNotification(false /* resetRepeatTime */); 523 } 524 handleConnectionAttemptFailedToSend()525 private void handleConnectionAttemptFailedToSend() { 526 handleConnectionFailure(); 527 mWifiMetrics.incrementNumNetworkConnectMessageFailedToSend(mTag); 528 } 529 handlePickWifiNetworkAfterConnectFailure()530 private void handlePickWifiNetworkAfterConnectFailure() { 531 mWifiMetrics.incrementConnectToNetworkNotificationAction(mTag, mState, 532 ConnectToNetworkNotificationAndActionCount 533 .ACTION_PICK_WIFI_NETWORK_AFTER_CONNECT_FAILURE); 534 startWifiSettings(); 535 } 536 handleUserDismissedAction()537 private void handleUserDismissedAction() { 538 Log.d(mTag, "User dismissed notification with state=" + mState); 539 mWifiMetrics.incrementConnectToNetworkNotificationAction(mTag, mState, 540 ConnectToNetworkNotificationAndActionCount.ACTION_USER_DISMISSED_NOTIFICATION); 541 if (mState == STATE_SHOWING_RECOMMENDATION_NOTIFICATION) { 542 // blocklist dismissed network 543 addNetworkToBlocklist(mRecommendedNetwork.SSID); 544 } 545 resetStateAndDelayNotification(); 546 } 547 resetStateAndDelayNotification()548 private void resetStateAndDelayNotification() { 549 mState = STATE_NO_NOTIFICATION; 550 mNotificationRepeatTime = System.currentTimeMillis() + mNotificationRepeatDelay; 551 mRecommendedNetwork = null; 552 } 553 554 /** Dump this network notifier's state. */ dump(FileDescriptor fd, PrintWriter pw, String[] args)555 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 556 pw.println(mTag + ": "); 557 pw.println("mSettingEnabled " + mSettingEnabled); 558 pw.println("currentTime: " + mClock.getWallClockMillis()); 559 pw.println("mNotificationRepeatTime: " + mNotificationRepeatTime); 560 pw.println("mState: " + mState); 561 pw.println("mBlocklistedSsids: " + mBlocklistedSsids.toString()); 562 } 563 564 private class AvailableNetworkNotifierStoreData implements SsidSetStoreData.DataSource { 565 @Override getSsids()566 public Set<String> getSsids() { 567 return new ArraySet<>(mBlocklistedSsids); 568 } 569 570 @Override setSsids(Set<String> ssidList)571 public void setSsids(Set<String> ssidList) { 572 mBlocklistedSsids.addAll(ssidList); 573 mWifiMetrics.setNetworkRecommenderBlocklistSize(mTag, mBlocklistedSsids.size()); 574 } 575 } 576 577 private class NotificationEnabledSettingObserver extends ContentObserver { NotificationEnabledSettingObserver(Handler handler)578 NotificationEnabledSettingObserver(Handler handler) { 579 super(handler); 580 } 581 register()582 public void register() { 583 mFrameworkFacade.registerContentObserver(mContext, 584 Settings.Global.getUriFor(mToggleSettingsName), true, this); 585 mSettingEnabled = getValue(); 586 } 587 588 @Override onChange(boolean selfChange)589 public void onChange(boolean selfChange) { 590 super.onChange(selfChange); 591 mSettingEnabled = getValue(); 592 clearPendingNotification(true /* resetRepeatTime */); 593 } 594 getValue()595 private boolean getValue() { 596 boolean enabled = 597 mFrameworkFacade.getIntegerSetting(mContext, mToggleSettingsName, 1) == 1; 598 mWifiMetrics.setIsWifiNetworksAvailableNotificationEnabled(mTag, enabled); 599 Log.d(mTag, "Settings toggle enabled=" + enabled); 600 return enabled; 601 } 602 } 603 } 604