Add Wi-Fi Enabled notification. am: f61eea388f am: 1ea05f9f3f
am: e66a2cd7ae

Change-Id: Ice0addbb63f547021196a8808ec2d4eb3d83cbfe
diff --git a/res/drawable/ic_wifi_signal_4.xml b/res/drawable/ic_wifi_signal_4.xml
new file mode 100644
index 0000000..aca4551
--- /dev/null
+++ b/res/drawable/ic_wifi_signal_4.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+    Copyright (C) 2015 The Android Open Source Project
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="26dp"
+    android:height="24dp"
+    android:viewportWidth="26"
+    android:viewportHeight="24">
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M13.0,22.0L25.6,6.5C25.1,6.1 20.3,2.1 13.0,2.1S0.9,6.1 0.4,6.5L13.0,22.0L13.0,22.0L13.0,22.0L13.0,22.0L13.0,22.0z"/>
+</vector>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 3453343..c70c1d2 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -26,4 +26,8 @@
     <string name="wifi_available_failed">FAILED TO CONNECT</string>
 
     <string name="android_system_label">Android System</string>
+
+    <!-- A notification is shown when Wi-Fi Wakeup enables Wi-Fi. -->
+    <string name="wifi_wakeup_enabled_notification_title">Wi\u2011Fi was turned on automatically</string>
+    <string name="wifi_wakeup_enabled_notification_context">"Wi\u2011Fi turned on because you are near saved network, %1$s."</string>
 </resources>
diff --git a/src/com/android/networkrecommendation/DefaultNetworkRecommendationService.java b/src/com/android/networkrecommendation/DefaultNetworkRecommendationService.java
index b35f8d8..64e4f13 100644
--- a/src/com/android/networkrecommendation/DefaultNetworkRecommendationService.java
+++ b/src/com/android/networkrecommendation/DefaultNetworkRecommendationService.java
@@ -18,12 +18,15 @@
 
 import android.app.NotificationManager;
 import android.app.Service;
+import android.content.ContentResolver;
 import android.content.Intent;
+import android.content.res.Resources;
 import android.net.NetworkScoreManager;
 import android.net.wifi.WifiManager;
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.IBinder;
+import android.os.Looper;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -43,17 +46,26 @@
     public void onCreate() {
         mHandlerThread = new HandlerThread("RecommendationProvider");
         mHandlerThread.start();
-        mHandler = new Handler(mHandlerThread.getLooper());
+        Looper looper = mHandlerThread.getLooper();
+        mHandler = new Handler(looper);
         NetworkScoreManager networkScoreManager = getSystemService(NetworkScoreManager.class);
         mProvider = new DefaultNetworkRecommendationProvider(mHandler,
                 networkScoreManager, new DefaultNetworkRecommendationProvider.ScoreStorage());
+        NotificationManager notificationManager = getSystemService(NotificationManager.class);
+        WifiManager wifiManager = getSystemService(WifiManager.class);
+        Resources resources = getResources();
+        ContentResolver contentResolver = getContentResolver();
         mWifiNotificationController = new WifiNotificationController(
-                this, getContentResolver(), mHandler, mProvider,
-                getSystemService(WifiManager.class), getSystemService(NotificationManager.class),
+                this, contentResolver, new Handler(looper), mProvider,
+                wifiManager, notificationManager,
                 new WifiNotificationHelper(this, mProvider));
-        mWifiWakeupController = new WifiWakeupController(this, getContentResolver(),
-                mHandlerThread.getLooper(), getSystemService(WifiManager.class),
-                new WifiWakeupNetworkSelector(getResources()));
+        WifiWakeupNetworkSelector wifiWakeupNetworkSelector =
+                new WifiWakeupNetworkSelector(resources);
+        WifiWakeupNotificationHelper wifiWakeupNotificationHelper =
+                new WifiWakeupNotificationHelper(this, resources, new Handler(looper),
+                        notificationManager, wifiManager);
+        mWifiWakeupController = new WifiWakeupController(this, contentResolver, looper,
+                wifiManager, wifiWakeupNetworkSelector, wifiWakeupNotificationHelper);
     }
 
     @Override
diff --git a/src/com/android/networkrecommendation/WifiNotificationController.java b/src/com/android/networkrecommendation/WifiNotificationController.java
index 76302a5..9dbb665 100644
--- a/src/com/android/networkrecommendation/WifiNotificationController.java
+++ b/src/com/android/networkrecommendation/WifiNotificationController.java
@@ -200,8 +200,7 @@
         @Override
         public void onReceive(Context context, Intent intent) {
             if (intent.getAction().equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) {
-                mWifiState = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
-                        WifiManager.WIFI_STATE_UNKNOWN);
+                mWifiState = mWifiManager.getWifiState();
                 resetNotification();
             } else if (intent.getAction().equals(
                     WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
diff --git a/src/com/android/networkrecommendation/WifiWakeupController.java b/src/com/android/networkrecommendation/WifiWakeupController.java
index d1ac74a..5fe65ef 100644
--- a/src/com/android/networkrecommendation/WifiWakeupController.java
+++ b/src/com/android/networkrecommendation/WifiWakeupController.java
@@ -55,6 +55,7 @@
 public class WifiWakeupController {
     private static final String TAG = "WifiWakeupController";
     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+    private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);
 
     /** Number of scans to ensure that a previously in range AP is now out of range. */
     private static final int NUM_SCANS_TO_CONFIRM_AP_LOSS = 3;
@@ -64,6 +65,7 @@
     private final WifiManager mWifiManager;
     private final WifiWakeupNetworkSelector mWifiWakeupNetworkSelector;
     private final Handler mHandler;
+    private final WifiWakeupNotificationHelper mWifiWakeupNotificationHelper;
     private final AtomicBoolean mStarted;
     @VisibleForTesting final ContentObserver mContentObserver;
 
@@ -77,10 +79,12 @@
     private boolean mAirplaneModeEnabled;
 
     WifiWakeupController(Context context, ContentResolver contentResolver, Looper looper,
-            WifiManager wifiManager, WifiWakeupNetworkSelector wifiWakeupNetworkSelector) {
+            WifiManager wifiManager, WifiWakeupNetworkSelector wifiWakeupNetworkSelector,
+            WifiWakeupNotificationHelper wifiWakeupNotificationHelper) {
         mContext = context;
         mContentResolver = contentResolver;
         mHandler = new Handler(looper);
+        mWifiWakeupNotificationHelper = wifiWakeupNotificationHelper;
         mStarted = new AtomicBoolean(false);
         mWifiManager = wifiManager;
         mWifiWakeupNetworkSelector = wifiWakeupNetworkSelector;
@@ -103,9 +107,9 @@
             }
 
             if (WifiManager.WIFI_AP_STATE_CHANGED_ACTION.equals(intent.getAction())) {
-                handleWifiApStateChanged(intent);
+                handleWifiApStateChanged();
             } else if (WifiManager.WIFI_STATE_CHANGED_ACTION.equals(intent.getAction())) {
-                handleWifiStateChanged(intent);
+                handleWifiStateChanged();
             } else if (WifiManager.SCAN_RESULTS_AVAILABLE_ACTION.equals(intent.getAction())) {
                 handleScanResultsAvailable();
             } else if (WifiManager.CONFIGURED_NETWORKS_CHANGED_ACTION.equals(intent.getAction())) {
@@ -119,6 +123,9 @@
         if (!mStarted.compareAndSet(false, true)) {
             return;
         }
+        if (DEBUG) {
+            Log.d(TAG, "Starting WifiWakeupController.");
+        }
         IntentFilter filter = new IntentFilter();
         filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
         filter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
@@ -131,7 +138,10 @@
         mContentResolver.registerContentObserver(Settings.Global.getUriFor(
                 Settings.Global.AIRPLANE_MODE_ON), true, mContentObserver);
         mContentObserver.onChange(true);
+        handleWifiStateChanged();
+        handleWifiApStateChanged();
         handleConfiguredNetworksChanged();
+        handleScanResultsAvailable();
     }
 
     /** Stops {@link WifiWakeupController}. */
@@ -139,13 +149,18 @@
         if (!mStarted.compareAndSet(true, false)) {
             return;
         }
+        if (DEBUG) {
+            Log.d(TAG, "Stopping WifiWakeupController.");
+        }
         mContext.unregisterReceiver(mBroadcastReceiver);
         mContentResolver.unregisterContentObserver(mContentObserver);
     }
 
-    private void handleWifiApStateChanged(Intent intent) {
-        mWifiApState = intent.getIntExtra(WifiManager.EXTRA_WIFI_AP_STATE,
-                WifiManager.WIFI_AP_STATE_DISABLED);
+    private void handleWifiApStateChanged() {
+        mWifiApState = mWifiManager.getWifiApState();
+        if (VERBOSE) {
+            Log.v(TAG, "handleWifiApStateChanged: " + mWifiApState);
+        }
     }
 
     private void handleConfiguredNetworksChanged() {
@@ -153,14 +168,20 @@
         if (wifiConfigurations == null) {
             return;
         }
+        if (VERBOSE) {
+            Log.v(TAG, "handleConfiguredNetworksChanged: " + wifiConfigurations.size());
+        }
 
         mSavedNetworks.clear();
         mSavedSsids.clear();
         for (int i = 0; i < wifiConfigurations.size(); i++) {
             WifiConfiguration wifiConfiguration = wifiConfigurations.get(i);
             if (wifiConfiguration.status != WifiConfiguration.Status.ENABLED
-                    || wifiConfiguration.useExternalScores) {
-                continue; // Ignore disabled and externally scored networks.
+                    && wifiConfiguration.status != WifiConfiguration.Status.CURRENT) {
+                continue; // Ignore networks that are not connected or enabled.
+            }
+            if (wifiConfiguration.useExternalScores) {
+                continue; // Ignore externally scored networks.
             }
             if (wifiConfiguration.hasNoInternetAccess()
                     || wifiConfiguration.isNoInternetAccessExpected()) {
@@ -176,8 +197,11 @@
         mSavedSsidsInLastScan.retainAll(mSavedSsids);
     }
 
-    private void handleWifiStateChanged(Intent intent) {
-        mWifiState = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, -1);
+    private void handleWifiStateChanged() {
+        mWifiState = mWifiManager.getWifiState();
+        if (VERBOSE) {
+            Log.v(TAG, "handleWifiStateChanged: " + mWifiState);
+        }
         switch (mWifiState) {
             case WifiManager.WIFI_STATE_ENABLED:
                 mSavedSsidsOnDisable.clear();
@@ -192,6 +216,13 @@
 
     private void handleScanResultsAvailable() {
         List<ScanResult> scanResults = mWifiManager.getScanResults();
+        if (scanResults == null) {
+            return;
+        }
+        if (VERBOSE) {
+            Log.v(TAG, "handleScanResultsAvailable: " + scanResults.size());
+        }
+
         mSavedSsidsInLastScan.clear();
         for (int i = 0; i < scanResults.size(); i++) {
             String ssid = scanResults.get(i).SSID;
@@ -230,11 +261,11 @@
         WifiConfiguration selectedNetwork = mWifiWakeupNetworkSelector.selectNetwork(mSavedNetworks,
                 scanResults);
         if (selectedNetwork != null) {
-            // TODO(b/33677088): show notification for wifi enablement
             if (DEBUG) {
                 Log.d(TAG, "Enabling wifi for ssid: " + selectedNetwork.SSID);
             }
             mWifiManager.setWifiEnabled(true /* enabled */);
+            mWifiWakeupNotificationHelper.maybeShowWifiEnabledNotification(selectedNetwork);
         }
     }
 
diff --git a/src/com/android/networkrecommendation/WifiWakeupNotificationHelper.java b/src/com/android/networkrecommendation/WifiWakeupNotificationHelper.java
new file mode 100644
index 0000000..e044555
--- /dev/null
+++ b/src/com/android/networkrecommendation/WifiWakeupNotificationHelper.java
@@ -0,0 +1,190 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.networkrecommendation;
+
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.SharedPreferences;
+import android.content.res.Resources;
+import android.net.wifi.WifiConfiguration;
+import android.net.wifi.WifiInfo;
+import android.net.wifi.WifiManager;
+import android.os.Bundle;
+import android.os.Handler;
+import android.provider.Settings;
+import android.support.annotation.NonNull;
+import android.support.annotation.VisibleForTesting;
+import android.text.TextUtils;
+import android.util.ArraySet;
+import android.util.Log;
+
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Helper class for building and showing notifications for {@link WifiWakeupController}.
+ */
+public class WifiWakeupNotificationHelper {
+    private static final String TAG = "WifiWakeupNotifHelper";
+    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+
+    /** Unique ID used for the Wi-Fi Enabled notification. */
+    private static final int NOTIFICATION_ID = R.string.wifi_wakeup_enabled_notification_title;
+    @VisibleForTesting
+    static final String KEY_SHOWN_SSIDS = "key_shown_ssids";
+    private static final String ACTION_DISMISS_WIFI_ENABLED_NOTIFICATION =
+            "com.android.networkrecommendation.ACTION_DISMISS_WIFI_ENABLED_NOTIFICATION";
+    private static final IntentFilter INTENT_FILTER = new IntentFilter();
+    private static final long NETWORK_CONNECTED_TIMEOUT_MILLIS = TimeUnit.SECONDS.toMillis(30);
+
+    static {
+        INTENT_FILTER.addAction(ACTION_DISMISS_WIFI_ENABLED_NOTIFICATION);
+        INTENT_FILTER.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
+    }
+
+    private final Context mContext;
+    private final Resources mResources;
+    private final NotificationManager mNotificationManager;
+    private final Handler mHandler;
+    private final WifiManager mWifiManager;
+    private final SharedPreferences mSharedPreferences;
+
+    @VisibleForTesting
+    final Runnable mCancelNotification = new Runnable() {
+        @Override
+        public void run() {
+            cancelNotificationAndUnregisterReceiver();
+        }
+    };
+
+    @VisibleForTesting
+    final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (ACTION_DISMISS_WIFI_ENABLED_NOTIFICATION.equals(intent.getAction())) {
+                cancelNotificationAndUnregisterReceiver();
+            } else if (WifiManager.WIFI_STATE_CHANGED_ACTION.equals(intent.getAction())) {
+                networkStateChanged();
+            }
+        }
+    };
+    private boolean mNotificationShown;
+    private String mConnectedSsid;
+
+    public WifiWakeupNotificationHelper(Context context, Resources resources, Handler handler,
+            NotificationManager notificationManager, WifiManager wifiManager) {
+        this(context, resources, handler, notificationManager, wifiManager,
+                context.getSharedPreferences("wifi_wakeup", Context.MODE_PRIVATE));
+    }
+
+    @VisibleForTesting
+    WifiWakeupNotificationHelper(Context context, Resources resources, Handler handler,
+            NotificationManager notificationManager, WifiManager wifiManager,
+            SharedPreferences sharedPreferences) {
+        mContext = context;
+        mResources = resources;
+        mNotificationManager = notificationManager;
+        mHandler = handler;
+        mWifiManager = wifiManager;
+        mSharedPreferences = sharedPreferences;
+        mNotificationShown = false;
+        mConnectedSsid = null;
+    }
+
+    /**
+     * Show a notification that Wi-Fi has been enabled by Wi-Fi Wakeup.
+     *
+     * @param wifiConfiguration the {@link WifiConfiguration} that triggered Wi-Fi to wakeup
+     */
+    public void maybeShowWifiEnabledNotification(@NonNull WifiConfiguration wifiConfiguration) {
+        Set<String> ssidSet = mSharedPreferences.getStringSet(KEY_SHOWN_SSIDS, null);
+        if (ssidSet == null) {
+            ssidSet = new ArraySet<>();
+        } else if (ssidSet.contains(wifiConfiguration.SSID)) {
+            if (DEBUG) {
+                Log.d(TAG, "Already showed Wi-Fi Enabled notification for ssid: "
+                        + wifiConfiguration.SSID);
+            }
+            return;
+        }
+        ssidSet.add(wifiConfiguration.SSID);
+        mSharedPreferences.edit().putStringSet(KEY_SHOWN_SSIDS, ssidSet).apply();
+
+        String title = mResources.getString(
+                R.string.wifi_wakeup_enabled_notification_title);
+        String summary = mResources.getString(
+                R.string.wifi_wakeup_enabled_notification_context, wifiConfiguration.SSID);
+        PendingIntent savedNetworkSettingsPendingIntent = PendingIntent.getActivity(mContext, 0,
+                // TODO(b/34135303): update action
+                new Intent(Settings.ACTION_WIFI_SETTINGS),
+                PendingIntent.FLAG_UPDATE_CURRENT);
+        PendingIntent deletePendingIntent = PendingIntent.getActivity(mContext, 0,
+                new Intent(ACTION_DISMISS_WIFI_ENABLED_NOTIFICATION),
+                PendingIntent.FLAG_UPDATE_CURRENT);
+        Bundle extras = new Bundle();
+        extras.putString(Notification.EXTRA_SUBSTITUTE_APP_NAME,
+                mResources.getString(R.string.android_system_label));
+        Notification notification = new Notification.Builder(mContext)
+                .setContentTitle(title)
+                .setSmallIcon(R.drawable.ic_wifi_signal_4)
+                .setStyle(new Notification.BigTextStyle().bigText(summary))
+                .setAutoCancel(true)
+                .setDeleteIntent(deletePendingIntent)
+                .setPriority(Notification.PRIORITY_LOW)
+                .setVisibility(Notification.VISIBILITY_PUBLIC)
+                .setCategory(Notification.CATEGORY_STATUS)
+                .setContentIntent(savedNetworkSettingsPendingIntent)
+                .addExtras(extras)
+                .build();
+        mNotificationManager.notify(TAG, NOTIFICATION_ID, notification);
+        mNotificationShown = true;
+        mContext.registerReceiver(mBroadcastReceiver, INTENT_FILTER, null /* broadcastPermission*/,
+                mHandler);
+        mHandler.postDelayed(mCancelNotification, NETWORK_CONNECTED_TIMEOUT_MILLIS);
+    }
+
+    private void cancelNotificationAndUnregisterReceiver() {
+        if (mNotificationShown) {
+            mNotificationShown = false;
+            mConnectedSsid = null;
+            mNotificationManager.cancel(TAG, NOTIFICATION_ID);
+            mContext.unregisterReceiver(mBroadcastReceiver);
+        }
+    }
+
+    private void networkStateChanged() {
+        if (!mWifiManager.isWifiEnabled()) {
+            cancelNotificationAndUnregisterReceiver();
+            return;
+        }
+
+        WifiInfo wifiInfo = mWifiManager.getConnectionInfo();
+        String ssid = wifiInfo == null ? null : wifiInfo.getSSID();
+        if (mConnectedSsid == null) {
+            mConnectedSsid = ssid;
+            mHandler.removeCallbacks(mCancelNotification);
+        } else {
+            if (!TextUtils.equals(ssid, mConnectedSsid)) {
+                cancelNotificationAndUnregisterReceiver();
+            }
+        }
+    }
+}
diff --git a/tests/src/com/android/networkrecommendation/TestUtil.java b/tests/src/com/android/networkrecommendation/TestUtil.java
index 24551fb..77d7aa7 100644
--- a/tests/src/com/android/networkrecommendation/TestUtil.java
+++ b/tests/src/com/android/networkrecommendation/TestUtil.java
@@ -53,10 +53,9 @@
     }
 
     /** Send {@link WifiManager#WIFI_AP_STATE_CHANGED_ACTION} broadcast. */
-    public static void sendWifiApStateChanged(BroadcastReceiver broadcastReceiver, Context context,
-            int wifiApState) {
+    public static void sendWifiApStateChanged(BroadcastReceiver broadcastReceiver,
+            Context context) {
         Intent intent = new Intent(WifiManager.WIFI_AP_STATE_CHANGED_ACTION);
-        intent.putExtra(WifiManager.EXTRA_WIFI_AP_STATE, wifiApState);
         broadcastReceiver.onReceive(context, intent);
     }
 
@@ -75,10 +74,8 @@
     }
 
     /** Send {@link WifiManager#WIFI_STATE_CHANGED_ACTION} broadcast. */
-    public static void sendWifiStateChanged(BroadcastReceiver broadcastReceiver,
-            Context context, int wifiState) {
+    public static void sendWifiStateChanged(BroadcastReceiver broadcastReceiver, Context context) {
         Intent intent = new Intent(WifiManager.WIFI_STATE_CHANGED_ACTION);
-        intent.putExtra(WifiManager.EXTRA_WIFI_STATE, wifiState);
         broadcastReceiver.onReceive(context, intent);
     }
 }
diff --git a/tests/src/com/android/networkrecommendation/WifiNotificationControllerTest.java b/tests/src/com/android/networkrecommendation/WifiNotificationControllerTest.java
index a8ef979..d902e68 100644
--- a/tests/src/com/android/networkrecommendation/WifiNotificationControllerTest.java
+++ b/tests/src/com/android/networkrecommendation/WifiNotificationControllerTest.java
@@ -146,7 +146,9 @@
     /** Verifies that a notification is displayed (and retracted) given system events. */
     @Test
     public void verifyNotificationDisplayedWhenNetworkRecommended() throws Exception {
-        TestUtil.sendWifiStateChanged(mBroadcastReceiver, mContext, WifiManager.WIFI_STATE_ENABLED);
+        when(mWifiManager.getWifiState()).thenReturn(WifiManager.WIFI_STATE_ENABLED);
+
+        TestUtil.sendWifiStateChanged(mBroadcastReceiver, mContext);
         TestUtil.sendNetworkStateChanged(mBroadcastReceiver, mContext,
                 NetworkInfo.DetailedState.DISCONNECTED);
         setOpenAccessPoints(3);
@@ -182,7 +184,9 @@
     /** Verifies that a notification is not displayed for bad networks. */
     @Test
     public void verifyNotificationNotDisplayedWhenNoNetworkRecommended() throws Exception {
-        TestUtil.sendWifiStateChanged(mBroadcastReceiver, mContext, WifiManager.WIFI_STATE_ENABLED);
+        when(mWifiManager.getWifiState()).thenReturn(WifiManager.WIFI_STATE_ENABLED);
+
+        TestUtil.sendWifiStateChanged(mBroadcastReceiver, mContext);
         TestUtil.sendNetworkStateChanged(mBroadcastReceiver, mContext,
                 NetworkInfo.DetailedState.DISCONNECTED);
         setOpenAccessPoints(3);
@@ -213,7 +217,9 @@
      */
     @Test
     public void verifyNotificationsFlowOnConnectToNetwork() {
-        TestUtil.sendWifiStateChanged(mBroadcastReceiver, mContext, WifiManager.WIFI_STATE_ENABLED);
+        when(mWifiManager.getWifiState()).thenReturn(WifiManager.WIFI_STATE_ENABLED);
+
+        TestUtil.sendWifiStateChanged(mBroadcastReceiver, mContext);
         TestUtil.sendNetworkStateChanged(mBroadcastReceiver, mContext,
                 NetworkInfo.DetailedState.DISCONNECTED);
         setOpenAccessPoints(3);
diff --git a/tests/src/com/android/networkrecommendation/WifiWakeupControllerTest.java b/tests/src/com/android/networkrecommendation/WifiWakeupControllerTest.java
index f481055..3869a71 100644
--- a/tests/src/com/android/networkrecommendation/WifiWakeupControllerTest.java
+++ b/tests/src/com/android/networkrecommendation/WifiWakeupControllerTest.java
@@ -71,17 +71,15 @@
 
     static {
         SAVED_WIFI_CONFIGURATION.SSID = "\"" + SAVED_SCAN_RESULT.SSID + "\"";
-        makeConnectable(SAVED_WIFI_CONFIGURATION);
+        SAVED_WIFI_CONFIGURATION.status = WifiConfiguration.Status.CURRENT;
+        SAVED_WIFI_CONFIGURATION.validatedInternetAccess = true;
         SAVED_WIFI_CONFIGURATION2.SSID = "\"" + SAVED_SCAN_RESULT.SSID + "\"";
-        makeConnectable(SAVED_WIFI_CONFIGURATION2);
+        SAVED_WIFI_CONFIGURATION2.status = WifiConfiguration.Status.ENABLED;
+        SAVED_WIFI_CONFIGURATION2.validatedInternetAccess = true;
         SAVED_WIFI_CONFIGURATION_EXTERNAL.SSID = "\"" + SAVED_SCAN_RESULT_EXTERNAL.SSID + "\"";
         SAVED_WIFI_CONFIGURATION_EXTERNAL.useExternalScores = true;
-        makeConnectable(SAVED_WIFI_CONFIGURATION_EXTERNAL);
-    }
-
-    private static void makeConnectable(WifiConfiguration wifiConfiguration) {
-        wifiConfiguration.status = WifiConfiguration.Status.ENABLED;
-        wifiConfiguration.validatedInternetAccess = true;
+        SAVED_WIFI_CONFIGURATION_EXTERNAL.status = WifiConfiguration.Status.ENABLED;
+        SAVED_WIFI_CONFIGURATION_EXTERNAL.validatedInternetAccess = true;
     }
 
     private static ScanResult buildScanResult(String ssid) {
@@ -95,6 +93,7 @@
     @Mock private NotificationManager mNotificationManager;
     @Mock private ContentResolver mContentResolver;
     @Mock private WifiWakeupNetworkSelector mWifiWakeupNetworkSelector;
+    @Mock private WifiWakeupNotificationHelper mWifiWakeupNotificationHelper;
     @Mock private WifiManager mWifiManager;
     @Captor private ArgumentCaptor<BroadcastReceiver> mBroadcastReceiverCaptor;
 
@@ -114,16 +113,16 @@
                 Settings.Global.getInt(mContentResolver, Settings.Global.AIRPLANE_MODE_ON, 0);
         Settings.Global.putInt(mContentResolver, Settings.Global.WIFI_WAKEUP_ENABLED, 1);
         Settings.Global.putInt(mContentResolver, Settings.Global.AIRPLANE_MODE_ON, 0);
+        when(mWifiManager.getWifiApState()).thenReturn(WifiManager.WIFI_AP_STATE_DISABLED);
 
         mWifiWakeupController = new WifiWakeupController(mContext, mContentResolver,
-                Looper.getMainLooper(), mWifiManager, mWifiWakeupNetworkSelector);
+                Looper.getMainLooper(), mWifiManager, mWifiWakeupNetworkSelector,
+                mWifiWakeupNotificationHelper);
         mWifiWakeupController.start();
 
         verify(mContext).registerReceiver(mBroadcastReceiverCaptor.capture(),
                 any(IntentFilter.class), anyString(), any(Handler.class));
         mBroadcastReceiver = mBroadcastReceiverCaptor.getValue();
-        TestUtil.sendWifiApStateChanged(mBroadcastReceiver, mContext,
-                WifiManager.WIFI_AP_STATE_DISABLED);
     }
 
     @After
@@ -161,13 +160,13 @@
                 Lists.newArrayList(SAVED_SCAN_RESULT));
         when(mWifiWakeupNetworkSelector.selectNetwork(anyMap(), anyList()))
                 .thenReturn(null, SAVED_WIFI_CONFIGURATION);
+        when(mWifiManager.getWifiState())
+                .thenReturn(WifiManager.WIFI_STATE_ENABLED, WifiManager.WIFI_STATE_DISABLED);
 
-        TestUtil.sendWifiStateChanged(mBroadcastReceiver, mContext,
-                WifiManager.WIFI_STATE_ENABLED);
+        TestUtil.sendWifiStateChanged(mBroadcastReceiver, mContext);
         TestUtil.sendConfiguredNetworksChanged(mBroadcastReceiver, mContext);
         TestUtil.sendScanResultsAvailable(mBroadcastReceiver, mContext);
-        TestUtil.sendWifiStateChanged(mBroadcastReceiver, mContext,
-                WifiManager.WIFI_STATE_DISABLED);
+        TestUtil.sendWifiStateChanged(mBroadcastReceiver, mContext);
         TestUtil.sendScanResultsAvailable(mBroadcastReceiver, mContext);
         TestUtil.sendScanResultsAvailable(mBroadcastReceiver, mContext);
         TestUtil.sendScanResultsAvailable(mBroadcastReceiver, mContext);
@@ -177,6 +176,8 @@
         TestUtil.sendScanResultsAvailable(mBroadcastReceiver, mContext);
 
         verify(mWifiManager).setWifiEnabled(true);
+        verify(mWifiWakeupNotificationHelper)
+                .maybeShowWifiEnabledNotification(SAVED_WIFI_CONFIGURATION);
     }
 
     /**
@@ -192,13 +193,13 @@
                 Lists.newArrayList(SAVED_SCAN_RESULT2));
         when(mWifiWakeupNetworkSelector.selectNetwork(anyMap(), anyList()))
                 .thenReturn(SAVED_WIFI_CONFIGURATION2);
+        when(mWifiManager.getWifiState())
+                .thenReturn(WifiManager.WIFI_STATE_ENABLED, WifiManager.WIFI_STATE_DISABLED);
 
-        TestUtil.sendWifiStateChanged(mBroadcastReceiver, mContext,
-                WifiManager.WIFI_STATE_ENABLED);
+        TestUtil.sendWifiStateChanged(mBroadcastReceiver, mContext);
         TestUtil.sendConfiguredNetworksChanged(mBroadcastReceiver, mContext);
         TestUtil.sendScanResultsAvailable(mBroadcastReceiver, mContext);
-        TestUtil.sendWifiStateChanged(mBroadcastReceiver, mContext,
-                WifiManager.WIFI_STATE_DISABLED);
+        TestUtil.sendWifiStateChanged(mBroadcastReceiver, mContext);
 
         verify(mWifiManager, never()).setWifiEnabled(true);
 
@@ -207,6 +208,8 @@
         TestUtil.sendScanResultsAvailable(mBroadcastReceiver, mContext);
 
         verify(mWifiManager).setWifiEnabled(true);
+        verify(mWifiWakeupNotificationHelper)
+                .maybeShowWifiEnabledNotification(SAVED_WIFI_CONFIGURATION2);
     }
 
     /**
@@ -226,10 +229,10 @@
                 .thenReturn(Lists.newArrayList(SAVED_SCAN_RESULT_EXTERNAL));
         when(mWifiWakeupNetworkSelector.selectNetwork(anyMap(), anyList()))
                 .thenReturn(null, SAVED_WIFI_CONFIGURATION_EXTERNAL);
+        when(mWifiManager.getWifiState()).thenReturn(WifiManager.WIFI_STATE_DISABLED);
 
         TestUtil.sendConfiguredNetworksChanged(mBroadcastReceiver, mContext);
-        TestUtil.sendWifiStateChanged(mBroadcastReceiver, mContext,
-                WifiManager.WIFI_STATE_DISABLED);
+        TestUtil.sendWifiStateChanged(mBroadcastReceiver, mContext);
         TestUtil.sendScanResultsAvailable(mBroadcastReceiver, mContext);
 
         verify(mWifiManager, never()).setWifiEnabled(true);
@@ -237,6 +240,8 @@
         TestUtil.sendScanResultsAvailable(mBroadcastReceiver, mContext);
 
         verify(mWifiManager).setWifiEnabled(true);
+        verify(mWifiWakeupNotificationHelper)
+                .maybeShowWifiEnabledNotification(SAVED_WIFI_CONFIGURATION_EXTERNAL);
     }
 
     /**
@@ -248,10 +253,10 @@
                 Lists.newArrayList(SAVED_WIFI_CONFIGURATION, SAVED_WIFI_CONFIGURATION_EXTERNAL));
         when(mWifiManager.getScanResults())
                 .thenReturn(Lists.newArrayList(SAVED_SCAN_RESULT));
+        when(mWifiManager.getWifiState()).thenReturn(WifiManager.WIFI_STATE_ENABLED);
 
         TestUtil.sendConfiguredNetworksChanged(mBroadcastReceiver, mContext);
-        TestUtil.sendWifiStateChanged(mBroadcastReceiver, mContext,
-                WifiManager.WIFI_STATE_ENABLED);
+        TestUtil.sendWifiStateChanged(mBroadcastReceiver, mContext);
         TestUtil.sendScanResultsAvailable(mBroadcastReceiver, mContext);
 
         verifyZeroInteractions(mWifiWakeupNetworkSelector);
@@ -269,10 +274,10 @@
         when(mWifiManager.getScanResults())
                 .thenReturn(Lists.newArrayList(SAVED_SCAN_RESULT));
         when(mWifiWakeupNetworkSelector.selectNetwork(anyMap(), anyList())).thenReturn(null);
+        when(mWifiManager.getWifiState()).thenReturn(WifiManager.WIFI_STATE_DISABLED);
 
         TestUtil.sendConfiguredNetworksChanged(mBroadcastReceiver, mContext);
-        TestUtil.sendWifiStateChanged(mBroadcastReceiver, mContext,
-                WifiManager.WIFI_STATE_DISABLED);
+        TestUtil.sendWifiStateChanged(mBroadcastReceiver, mContext);
         TestUtil.sendScanResultsAvailable(mBroadcastReceiver, mContext);
 
         verify(mWifiManager, never()).setWifiEnabled(true);
@@ -289,11 +294,11 @@
                 Lists.newArrayList(SAVED_WIFI_CONFIGURATION, SAVED_WIFI_CONFIGURATION_EXTERNAL));
         when(mWifiManager.getScanResults())
                 .thenReturn(Lists.newArrayList(SAVED_SCAN_RESULT));
+        when(mWifiManager.getWifiState()).thenReturn(WifiManager.WIFI_STATE_DISABLED);
 
         mWifiWakeupController.mContentObserver.onChange(true);
         TestUtil.sendConfiguredNetworksChanged(mBroadcastReceiver, mContext);
-        TestUtil.sendWifiStateChanged(mBroadcastReceiver, mContext,
-                WifiManager.WIFI_STATE_DISABLED);
+        TestUtil.sendWifiStateChanged(mBroadcastReceiver, mContext);
         TestUtil.sendScanResultsAvailable(mBroadcastReceiver, mContext);
 
         verifyZeroInteractions(mWifiWakeupNetworkSelector);
@@ -311,11 +316,11 @@
                 Lists.newArrayList(SAVED_WIFI_CONFIGURATION, SAVED_WIFI_CONFIGURATION_EXTERNAL));
         when(mWifiManager.getScanResults())
                 .thenReturn(Lists.newArrayList(SAVED_SCAN_RESULT));
+        when(mWifiManager.getWifiState()).thenReturn(WifiManager.WIFI_STATE_DISABLED);
 
         mWifiWakeupController.mContentObserver.onChange(true);
         TestUtil.sendConfiguredNetworksChanged(mBroadcastReceiver, mContext);
-        TestUtil.sendWifiStateChanged(mBroadcastReceiver, mContext,
-                WifiManager.WIFI_STATE_DISABLED);
+        TestUtil.sendWifiStateChanged(mBroadcastReceiver, mContext);
         TestUtil.sendScanResultsAvailable(mBroadcastReceiver, mContext);
 
         verifyZeroInteractions(mWifiWakeupNetworkSelector);
@@ -332,13 +337,13 @@
                 Lists.newArrayList(SAVED_WIFI_CONFIGURATION, SAVED_WIFI_CONFIGURATION_EXTERNAL));
         when(mWifiManager.getScanResults())
                 .thenReturn(Lists.newArrayList(SAVED_SCAN_RESULT));
+        when(mWifiManager.getWifiState()).thenReturn(WifiManager.WIFI_STATE_DISABLED);
+        when(mWifiManager.getWifiApState()).thenReturn(WifiManager.WIFI_AP_STATE_ENABLED);
 
         mWifiWakeupController.mContentObserver.onChange(true);
         TestUtil.sendConfiguredNetworksChanged(mBroadcastReceiver, mContext);
-        TestUtil.sendWifiStateChanged(mBroadcastReceiver, mContext,
-                WifiManager.WIFI_STATE_DISABLED);
-        TestUtil.sendWifiApStateChanged(mBroadcastReceiver, mContext,
-                WifiManager.WIFI_AP_STATE_ENABLED);
+        TestUtil.sendWifiStateChanged(mBroadcastReceiver, mContext);
+        TestUtil.sendWifiApStateChanged(mBroadcastReceiver, mContext);
         TestUtil.sendScanResultsAvailable(mBroadcastReceiver, mContext);
 
         verifyZeroInteractions(mWifiWakeupNetworkSelector);
@@ -356,12 +361,10 @@
         when(mWifiManager.getScanResults())
                 .thenReturn(Lists.newArrayList(SAVED_SCAN_RESULT));
 
-        TestUtil.sendWifiStateChanged(mBroadcastReceiver, mContext,
-                WifiManager.WIFI_STATE_ENABLED);
+        TestUtil.sendWifiStateChanged(mBroadcastReceiver, mContext);
         TestUtil.sendConfiguredNetworksChanged(mBroadcastReceiver, mContext);
         TestUtil.sendScanResultsAvailable(mBroadcastReceiver, mContext);
-        TestUtil.sendWifiStateChanged(mBroadcastReceiver, mContext,
-                WifiManager.WIFI_STATE_DISABLED);
+        TestUtil.sendWifiStateChanged(mBroadcastReceiver, mContext);
         TestUtil.sendScanResultsAvailable(mBroadcastReceiver, mContext);
         TestUtil.sendScanResultsAvailable(mBroadcastReceiver, mContext);
         TestUtil.sendScanResultsAvailable(mBroadcastReceiver, mContext);
@@ -384,13 +387,13 @@
                 .thenReturn(Lists.<ScanResult>newArrayList())
                 .thenReturn(Lists.newArrayList(SAVED_SCAN_RESULT));
         when(mWifiWakeupNetworkSelector.selectNetwork(anyMap(), anyList())).thenReturn(null);
+        when(mWifiManager.getWifiState())
+                .thenReturn(WifiManager.WIFI_STATE_ENABLED, WifiManager.WIFI_STATE_DISABLED);
 
-        TestUtil.sendWifiStateChanged(mBroadcastReceiver, mContext,
-                WifiManager.WIFI_STATE_ENABLED);
+        TestUtil.sendWifiStateChanged(mBroadcastReceiver, mContext);
         TestUtil.sendConfiguredNetworksChanged(mBroadcastReceiver, mContext);
         TestUtil.sendScanResultsAvailable(mBroadcastReceiver, mContext);
-        TestUtil.sendWifiStateChanged(mBroadcastReceiver, mContext,
-                WifiManager.WIFI_STATE_DISABLED);
+        TestUtil.sendWifiStateChanged(mBroadcastReceiver, mContext);
         TestUtil.sendConfiguredNetworksChanged(mBroadcastReceiver, mContext);
         TestUtil.sendScanResultsAvailable(mBroadcastReceiver, mContext);
         TestUtil.sendScanResultsAvailable(mBroadcastReceiver, mContext);
@@ -410,13 +413,13 @@
                 Lists.newArrayList(SAVED_SCAN_RESULT,
                         SAVED_SCAN_RESULT2),
                 Lists.newArrayList(SAVED_SCAN_RESULT));
+        when(mWifiManager.getWifiState())
+                .thenReturn(WifiManager.WIFI_STATE_ENABLED, WifiManager.WIFI_STATE_DISABLED);
 
-        TestUtil.sendWifiStateChanged(mBroadcastReceiver, mContext,
-                WifiManager.WIFI_STATE_ENABLED);
+        TestUtil.sendWifiStateChanged(mBroadcastReceiver, mContext);
         TestUtil.sendConfiguredNetworksChanged(mBroadcastReceiver, mContext);
         TestUtil.sendScanResultsAvailable(mBroadcastReceiver, mContext);
-        TestUtil.sendWifiStateChanged(mBroadcastReceiver, mContext,
-                WifiManager.WIFI_STATE_DISABLED);
+        TestUtil.sendWifiStateChanged(mBroadcastReceiver, mContext);
         TestUtil.sendScanResultsAvailable(mBroadcastReceiver, mContext);
         TestUtil.sendScanResultsAvailable(mBroadcastReceiver, mContext);
         TestUtil.sendScanResultsAvailable(mBroadcastReceiver, mContext);
diff --git a/tests/src/com/android/networkrecommendation/WifiWakeupNotificationHelperTest.java b/tests/src/com/android/networkrecommendation/WifiWakeupNotificationHelperTest.java
new file mode 100644
index 0000000..2091335
--- /dev/null
+++ b/tests/src/com/android/networkrecommendation/WifiWakeupNotificationHelperTest.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.networkrecommendation;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.net.wifi.WifiConfiguration;
+import android.net.wifi.WifiInfo;
+import android.net.wifi.WifiManager;
+import android.net.wifi.WifiSsid;
+import android.os.Handler;
+import android.os.Looper;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.Set;
+
+/**
+ * Unit tests for {@link WifiWakeupNetworkSelector}
+ */
+@RunWith(AndroidJUnit4.class)
+public class WifiWakeupNotificationHelperTest {
+    private static final String SSID = "ssid";
+    private static final WifiConfiguration WIFI_CONFIGURATION = new WifiConfiguration();
+
+    static {
+        WIFI_CONFIGURATION.SSID = "\"" + SSID + "\"";
+    }
+
+    private Context mContext;
+    @Mock private NotificationManager mNotificationManager;
+    @Mock private WifiManager mWifiManager;
+    private SharedPreferences mSharedPreferences;
+    private String mSharedPreferenceName;
+
+    private WifiWakeupNotificationHelper mWifiWakeupNotificationHelper;
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+
+        mContext = InstrumentationRegistry.getTargetContext();
+        mSharedPreferenceName = "WifiWakeupNotificationHelperTest";
+        mSharedPreferences = mContext.getSharedPreferences(mSharedPreferenceName,
+                Context.MODE_PRIVATE);
+
+        mWifiWakeupNotificationHelper = new WifiWakeupNotificationHelper(mContext,
+                mContext.getResources(), new Handler(Looper.getMainLooper()), mNotificationManager,
+                mWifiManager, mSharedPreferences);
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        mContext.deleteSharedPreferences(mSharedPreferenceName);
+    }
+
+    @Test
+    public void notificationShowsOncePerSsid() {
+        mWifiWakeupNotificationHelper.maybeShowWifiEnabledNotification(WIFI_CONFIGURATION);
+        mWifiWakeupNotificationHelper.maybeShowWifiEnabledNotification(WIFI_CONFIGURATION);
+
+        verify(mNotificationManager, times(1))
+                .notify(anyString(), anyInt(), any(Notification.class));
+        Set<String> ssidSet = mSharedPreferences.getStringSet(
+                WifiWakeupNotificationHelper.KEY_SHOWN_SSIDS, null);
+        assertEquals(1, ssidSet.size());
+        assertTrue(ssidSet.contains(WIFI_CONFIGURATION.SSID));
+    }
+
+    @Test
+    public void notificationCanceledWhenNeverConnected() {
+        mWifiWakeupNotificationHelper.maybeShowWifiEnabledNotification(WIFI_CONFIGURATION);
+
+        mWifiWakeupNotificationHelper.mCancelNotification.run();
+
+        verify(mNotificationManager).cancel(anyString(), anyInt());
+    }
+
+    @Test
+    public void notificationCanceledWhenWifiDisabled() {
+        mWifiWakeupNotificationHelper.maybeShowWifiEnabledNotification(WIFI_CONFIGURATION);
+
+        when(mWifiManager.isWifiEnabled()).thenReturn(false);
+
+        mWifiWakeupNotificationHelper.mBroadcastReceiver.onReceive(mContext,
+                new Intent(WifiManager.WIFI_STATE_CHANGED_ACTION));
+
+        verify(mNotificationManager).cancel(anyString(), anyInt());
+    }
+
+    @Test
+    public void notificationCanceledWhenSsidChanged() {
+        WifiInfo firstWifiInfo = new WifiInfo();
+        firstWifiInfo.setSSID(WifiSsid.createFromAsciiEncoded(SSID));
+        WifiInfo secondWifiInfo = new WifiInfo();
+        firstWifiInfo.setSSID(WifiSsid.createFromAsciiEncoded("blah"));
+
+        mWifiWakeupNotificationHelper.maybeShowWifiEnabledNotification(WIFI_CONFIGURATION);
+
+        when(mWifiManager.isWifiEnabled()).thenReturn(true);
+        when(mWifiManager.getConnectionInfo()).thenReturn(firstWifiInfo, secondWifiInfo);
+
+        mWifiWakeupNotificationHelper.mBroadcastReceiver.onReceive(mContext,
+                new Intent(WifiManager.WIFI_STATE_CHANGED_ACTION));
+
+        verify(mNotificationManager, never()).cancel(anyString(), anyInt());
+
+        mWifiWakeupNotificationHelper.mBroadcastReceiver.onReceive(mContext,
+                new Intent(WifiManager.WIFI_STATE_CHANGED_ACTION));
+
+        verify(mNotificationManager).cancel(anyString(), anyInt());
+    }
+}