• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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