summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTreeHugger Robot <treehugger-gerrit@google.com>2017-08-16 20:31:41 +0000
committerAndroid (Google) Code Review <android-gerrit@google.com>2017-08-16 20:31:41 +0000
commit69fa2e7fa12b8f4c24a27b3291a0744cd808a324 (patch)
treeba39a6d972ed25f35ed653e3b1308a6a74811b19
parent0af8182c7a421108aff122440724ecc5d1e4c6d7 (diff)
parent579066a6f282b9d6729a93b7cce3b18980a0a61d (diff)
Merge changes Ifa1eef1f,If59ecbd3,Ie3e640f6 into oc-mr1-dev
* changes: ONA: Refactor notification builder and register broadcast receiver. ONA: Rename WifiNotificationController to OpenNetworkNotifier ONA: Recommend a network using rssi strength.
-rw-r--r--service/java/com/android/server/wifi/OpenNetworkNotificationBuilder.java91
-rw-r--r--service/java/com/android/server/wifi/OpenNetworkNotifier.java241
-rw-r--r--service/java/com/android/server/wifi/OpenNetworkRecommender.java62
-rw-r--r--service/java/com/android/server/wifi/WifiConnectivityManager.java16
-rw-r--r--service/java/com/android/server/wifi/WifiInjector.java9
-rw-r--r--service/java/com/android/server/wifi/WifiNotificationController.java252
-rw-r--r--tests/wifitests/src/com/android/server/wifi/OpenNetworkNotifierTest.java322
-rw-r--r--tests/wifitests/src/com/android/server/wifi/OpenNetworkRecommenderTest.java98
-rw-r--r--tests/wifitests/src/com/android/server/wifi/WifiConnectivityManagerTest.java26
-rw-r--r--tests/wifitests/src/com/android/server/wifi/WifiNotificationControllerTest.java208
10 files changed, 840 insertions, 485 deletions
diff --git a/service/java/com/android/server/wifi/OpenNetworkNotificationBuilder.java b/service/java/com/android/server/wifi/OpenNetworkNotificationBuilder.java
new file mode 100644
index 000000000..5963b57a3
--- /dev/null
+++ b/service/java/com/android/server/wifi/OpenNetworkNotificationBuilder.java
@@ -0,0 +1,91 @@
+/*
+ * 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.server.wifi;
+
+import static com.android.server.wifi.OpenNetworkNotifier.ACTION_USER_DISMISSED_NOTIFICATION;
+import static com.android.server.wifi.OpenNetworkNotifier.ACTION_USER_TAPPED_CONTENT;
+
+import android.app.Notification;
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.Intent;
+import android.content.res.Resources;
+
+import com.android.internal.R;
+import com.android.internal.notification.SystemNotificationChannels;
+
+/**
+ * Helper to create notifications for {@link OpenNetworkNotifier}.
+ */
+public class OpenNetworkNotificationBuilder {
+
+ private Context mContext;
+ private Resources mResources;
+ private FrameworkFacade mFrameworkFacade;
+
+ public OpenNetworkNotificationBuilder(
+ Context context,
+ FrameworkFacade framework) {
+ mContext = context;
+ mResources = context.getResources();
+ mFrameworkFacade = framework;
+ }
+
+ /**
+ * Creates the open network available notification that alerts users there are open networks
+ * nearby.
+ */
+ public Notification createOpenNetworkAvailableNotification(int numNetworks) {
+
+ CharSequence title = mResources.getQuantityText(
+ com.android.internal.R.plurals.wifi_available, numNetworks);
+ CharSequence content = mResources.getQuantityText(
+ com.android.internal.R.plurals.wifi_available_detailed, numNetworks);
+
+ PendingIntent contentIntent =
+ mFrameworkFacade.getBroadcast(
+ mContext,
+ 0,
+ new Intent(ACTION_USER_TAPPED_CONTENT),
+ PendingIntent.FLAG_UPDATE_CURRENT);
+ return createNotificationBuilder(title, content)
+ .setContentIntent(contentIntent)
+ .build();
+ }
+
+ private Notification.Builder createNotificationBuilder(
+ CharSequence title, CharSequence content) {
+ PendingIntent deleteIntent =
+ mFrameworkFacade.getBroadcast(
+ mContext,
+ 0,
+ new Intent(ACTION_USER_DISMISSED_NOTIFICATION),
+ PendingIntent.FLAG_UPDATE_CURRENT);
+ return mFrameworkFacade.makeNotificationBuilder(mContext,
+ SystemNotificationChannels.NETWORK_AVAILABLE)
+ .setSmallIcon(R.drawable.stat_notify_wifi_in_range)
+ .setAutoCancel(true)
+ .setTicker(title)
+ .setContentTitle(title)
+ .setContentText(content)
+ .setDeleteIntent(deleteIntent)
+ .setShowWhen(false)
+ .setLocalOnly(true)
+ .setColor(mResources.getColor(R.color.system_notification_accent_color,
+ mContext.getTheme()));
+ }
+}
diff --git a/service/java/com/android/server/wifi/OpenNetworkNotifier.java b/service/java/com/android/server/wifi/OpenNetworkNotifier.java
new file mode 100644
index 000000000..fc144c139
--- /dev/null
+++ b/service/java/com/android/server/wifi/OpenNetworkNotifier.java
@@ -0,0 +1,241 @@
+/*
+ * Copyright (C) 2013 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.server.wifi;
+
+import android.annotation.NonNull;
+import android.app.NotificationManager;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.database.ContentObserver;
+import android.net.wifi.ScanResult;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.provider.Settings;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.List;
+
+/**
+ * Takes care of handling the "open wi-fi network available" notification
+ * @hide
+ */
+public class OpenNetworkNotifier {
+
+ static final String ACTION_USER_DISMISSED_NOTIFICATION =
+ "com.android.server.wifi.OpenNetworkNotifier.USER_DISMISSED_NOTIFICATION";
+ static final String ACTION_USER_TAPPED_CONTENT =
+ "com.android.server.wifi.OpenNetworkNotifier.USER_TAPPED_CONTENT";
+
+ /**
+ * The {@link Clock#getWallClockMillis()} must be at least this value for us
+ * to show the notification again.
+ */
+ private long mNotificationRepeatTime;
+ /**
+ * When a notification is shown, we wait this amount before possibly showing it again.
+ */
+ private final long mNotificationRepeatDelay;
+ /** Default repeat delay in seconds. */
+ @VisibleForTesting
+ static final int DEFAULT_REPEAT_DELAY_SEC = 900;
+
+ /** Whether the user has set the setting to show the 'available networks' notification. */
+ private boolean mSettingEnabled;
+ /** Whether the notification is being shown. */
+ private boolean mNotificationShown;
+ /** Whether the screen is on or not. */
+ private boolean mScreenOn;
+
+ private final Context mContext;
+ private final Handler mHandler;
+ private final FrameworkFacade mFrameworkFacade;
+ private final Clock mClock;
+ private final OpenNetworkRecommender mOpenNetworkRecommender;
+ private final OpenNetworkNotificationBuilder mOpenNetworkNotificationBuilder;
+
+ private ScanResult mRecommendedNetwork;
+
+ OpenNetworkNotifier(
+ Context context,
+ Looper looper,
+ FrameworkFacade framework,
+ Clock clock,
+ OpenNetworkRecommender openNetworkRecommender) {
+ mContext = context;
+ mHandler = new Handler(looper);
+ mFrameworkFacade = framework;
+ mClock = clock;
+ mOpenNetworkRecommender = openNetworkRecommender;
+ mOpenNetworkNotificationBuilder = new OpenNetworkNotificationBuilder(context, framework);
+ mScreenOn = false;
+
+ // Setting is in seconds
+ mNotificationRepeatDelay = mFrameworkFacade.getIntegerSetting(context,
+ Settings.Global.WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY,
+ DEFAULT_REPEAT_DELAY_SEC) * 1000L;
+ NotificationEnabledSettingObserver settingObserver = new NotificationEnabledSettingObserver(
+ mHandler);
+ settingObserver.register();
+
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(ACTION_USER_DISMISSED_NOTIFICATION);
+ filter.addAction(ACTION_USER_TAPPED_CONTENT);
+ mContext.registerReceiver(
+ mBroadcastReceiver, filter, null /* broadcastPermission */, mHandler);
+ }
+
+ private final BroadcastReceiver mBroadcastReceiver =
+ new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (ACTION_USER_TAPPED_CONTENT.equals(intent.getAction())) {
+ handleUserClickedContentAction();
+ } else if (ACTION_USER_DISMISSED_NOTIFICATION.equals(intent.getAction())) {
+ handleUserDismissedAction();
+ }
+ }
+ };
+
+ /**
+ * Clears the pending notification. This is called by {@link WifiConnectivityManager} on stop.
+ *
+ * @param resetRepeatDelay resets the time delay for repeated notification if true.
+ */
+ public void clearPendingNotification(boolean resetRepeatDelay) {
+ if (resetRepeatDelay) {
+ mNotificationRepeatTime = 0;
+ }
+
+ if (mNotificationShown) {
+ getNotificationManager().cancel(SystemMessage.NOTE_NETWORK_AVAILABLE);
+ mRecommendedNetwork = null;
+ mNotificationShown = false;
+ }
+ }
+
+ private boolean isControllerEnabled() {
+ return mSettingEnabled && !UserManager.get(mContext)
+ .hasUserRestriction(UserManager.DISALLOW_CONFIG_WIFI, UserHandle.CURRENT);
+ }
+
+ /**
+ * If there are open networks, attempt to post an open network notification.
+ *
+ * @param availableNetworks Available networks from
+ * {@link WifiNetworkSelector.NetworkEvaluator#getFilteredScanDetailsForOpenUnsavedNetworks()}.
+ */
+ public void handleScanResults(@NonNull List<ScanDetail> availableNetworks) {
+ if (!isControllerEnabled()) {
+ clearPendingNotification(true /* resetRepeatDelay */);
+ return;
+ }
+ if (availableNetworks.isEmpty()) {
+ clearPendingNotification(false /* resetRepeatDelay */);
+ return;
+ }
+
+ // Do not show or update the notification if screen is off. We want to avoid a race that
+ // could occur between a user picking a network in settings and a network candidate picked
+ // through network selection, which will happen because screen on triggers a new
+ // connectivity scan.
+ if (mNotificationShown || !mScreenOn) {
+ return;
+ }
+
+ mRecommendedNetwork = mOpenNetworkRecommender.recommendNetwork(
+ availableNetworks, mRecommendedNetwork);
+
+ postNotification(availableNetworks.size());
+ }
+
+ /** Handles screen state changes. */
+ public void handleScreenStateChanged(boolean screenOn) {
+ mScreenOn = screenOn;
+ }
+
+ private NotificationManager getNotificationManager() {
+ return (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
+ }
+
+ private void postNotification(int numNetworks) {
+ // Not enough time has passed to show the notification again
+ if (mClock.getWallClockMillis() < mNotificationRepeatTime) {
+ return;
+ }
+
+ getNotificationManager().notify(
+ SystemMessage.NOTE_NETWORK_AVAILABLE,
+ mOpenNetworkNotificationBuilder.createOpenNetworkAvailableNotification(
+ numNetworks));
+ mNotificationShown = true;
+ mNotificationRepeatTime = mClock.getWallClockMillis() + mNotificationRepeatDelay;
+ }
+
+ /** Opens Wi-Fi picker. */
+ private void handleUserClickedContentAction() {
+ mNotificationShown = false;
+ mContext.startActivity(
+ new Intent(Settings.ACTION_WIFI_SETTINGS)
+ .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
+ }
+
+ /** A delay is set before the next shown notification after user dismissal. */
+ private void handleUserDismissedAction() {
+ mNotificationShown = false;
+ }
+
+ /** Dump ONA controller state. */
+ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ pw.println("OpenNetworkNotifier: ");
+ pw.println("mSettingEnabled " + mSettingEnabled);
+ pw.println("currentTime: " + mClock.getWallClockMillis());
+ pw.println("mNotificationRepeatTime: " + mNotificationRepeatTime);
+ pw.println("mNotificationShown: " + mNotificationShown);
+ }
+
+ private class NotificationEnabledSettingObserver extends ContentObserver {
+ NotificationEnabledSettingObserver(Handler handler) {
+ super(handler);
+ }
+
+ public void register() {
+ mFrameworkFacade.registerContentObserver(mContext, Settings.Global.getUriFor(
+ Settings.Global.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON), true, this);
+ mSettingEnabled = getValue();
+ }
+
+ @Override
+ public void onChange(boolean selfChange) {
+ super.onChange(selfChange);
+ mSettingEnabled = getValue();
+ clearPendingNotification(true /* resetRepeatDelay */);
+ }
+
+ private boolean getValue() {
+ return mFrameworkFacade.getIntegerSetting(mContext,
+ Settings.Global.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON, 1) == 1;
+ }
+ }
+}
diff --git a/service/java/com/android/server/wifi/OpenNetworkRecommender.java b/service/java/com/android/server/wifi/OpenNetworkRecommender.java
new file mode 100644
index 000000000..cd460e58b
--- /dev/null
+++ b/service/java/com/android/server/wifi/OpenNetworkRecommender.java
@@ -0,0 +1,62 @@
+/*
+ * 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.server.wifi;
+
+import android.annotation.NonNull;
+import android.net.wifi.ScanResult;
+
+import java.util.List;
+
+/**
+ * Helps recommend the best available network for {@link OpenNetworkNotifier}.
+ * @hide
+ */
+public class OpenNetworkRecommender {
+
+ /**
+ * Recommends the network with the best signal strength.
+ *
+ * @param networks List of scan details to pick a recommendation. This list should not be null
+ * or empty.
+ * @param currentRecommendation The currently recommended network.
+ */
+ public ScanResult recommendNetwork(
+ @NonNull List<ScanDetail> networks, ScanResult currentRecommendation) {
+ ScanResult currentUpdatedRecommendation = null;
+ ScanResult result = null;
+ int highestRssi = Integer.MIN_VALUE;
+ for (ScanDetail scanDetail : networks) {
+ ScanResult scanResult = scanDetail.getScanResult();
+
+ if (currentRecommendation != null
+ && currentRecommendation.SSID.equals(scanResult.SSID)) {
+ currentUpdatedRecommendation = scanResult;
+ }
+
+ if (scanResult.level > highestRssi) {
+ result = scanResult;
+ highestRssi = scanResult.level;
+ }
+ }
+ if (currentUpdatedRecommendation != null
+ && currentUpdatedRecommendation.level >= result.level) {
+ return currentUpdatedRecommendation;
+ } else {
+ return result;
+ }
+ }
+}
diff --git a/service/java/com/android/server/wifi/WifiConnectivityManager.java b/service/java/com/android/server/wifi/WifiConnectivityManager.java
index 1cdc549ca..9603357a1 100644
--- a/service/java/com/android/server/wifi/WifiConnectivityManager.java
+++ b/service/java/com/android/server/wifi/WifiConnectivityManager.java
@@ -133,7 +133,7 @@ public class WifiConnectivityManager {
private final WifiConnectivityHelper mConnectivityHelper;
private final WifiNetworkSelector mNetworkSelector;
private final WifiLastResortWatchdog mWifiLastResortWatchdog;
- private final WifiNotificationController mWifiNotificationController;
+ private final OpenNetworkNotifier mOpenNetworkNotifier;
private final WifiMetrics mWifiMetrics;
private final AlarmManager mAlarmManager;
private final Handler mEventHandler;
@@ -270,7 +270,7 @@ public class WifiConnectivityManager {
return true;
} else {
if (mWifiState == WIFI_STATE_DISCONNECTED) {
- mWifiNotificationController.handleScanResults(
+ mOpenNetworkNotifier.handleScanResults(
mNetworkSelector.getFilteredScanDetailsForOpenUnsavedNetworks());
}
return false;
@@ -540,7 +540,7 @@ public class WifiConnectivityManager {
WifiScanner scanner, WifiConfigManager configManager, WifiInfo wifiInfo,
WifiNetworkSelector networkSelector, WifiConnectivityHelper connectivityHelper,
WifiLastResortWatchdog wifiLastResortWatchdog,
- WifiNotificationController wifiNotificationController, WifiMetrics wifiMetrics,
+ OpenNetworkNotifier openNetworkNotifier, WifiMetrics wifiMetrics,
Looper looper, Clock clock, LocalLog localLog, boolean enable,
FrameworkFacade frameworkFacade,
SavedNetworkEvaluator savedNetworkEvaluator,
@@ -554,7 +554,7 @@ public class WifiConnectivityManager {
mConnectivityHelper = connectivityHelper;
mLocalLog = localLog;
mWifiLastResortWatchdog = wifiLastResortWatchdog;
- mWifiNotificationController = wifiNotificationController;
+ mOpenNetworkNotifier = openNetworkNotifier;
mWifiMetrics = wifiMetrics;
mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
mEventHandler = new Handler(looper);
@@ -1041,7 +1041,7 @@ public class WifiConnectivityManager {
mScreenOn = screenOn;
- mWifiNotificationController.handleScreenStateChanged(screenOn);
+ mOpenNetworkNotifier.handleScreenStateChanged(screenOn);
startConnectivityScan(SCAN_ON_SCHEDULE);
}
@@ -1071,7 +1071,7 @@ public class WifiConnectivityManager {
mWifiState = state;
if (mWifiState == WIFI_STATE_CONNECTED) {
- mWifiNotificationController.clearPendingNotification(false /* resetRepeatDelay */);
+ mOpenNetworkNotifier.clearPendingNotification(false /* resetRepeatDelay */);
}
// Reset BSSID of last connection attempt and kick off
@@ -1307,7 +1307,7 @@ public class WifiConnectivityManager {
stopConnectivityScan();
clearBssidBlacklist();
resetLastPeriodicSingleScanTimeStamp();
- mWifiNotificationController.clearPendingNotification(true /* resetRepeatDelay */);
+ mOpenNetworkNotifier.clearPendingNotification(true /* resetRepeatDelay */);
mLastConnectionAttemptBssid = null;
mWaitForFullBandScanResults = false;
}
@@ -1367,6 +1367,6 @@ public class WifiConnectivityManager {
pw.println("WifiConnectivityManager - Log Begin ----");
mLocalLog.dump(fd, pw, args);
pw.println("WifiConnectivityManager - Log End ----");
- mWifiNotificationController.dump(fd, pw, args);
+ mOpenNetworkNotifier.dump(fd, pw, args);
}
}
diff --git a/service/java/com/android/server/wifi/WifiInjector.java b/service/java/com/android/server/wifi/WifiInjector.java
index 241873824..60c5d2fb9 100644
--- a/service/java/com/android/server/wifi/WifiInjector.java
+++ b/service/java/com/android/server/wifi/WifiInjector.java
@@ -87,7 +87,7 @@ public class WifiInjector {
private final WifiStateMachine mWifiStateMachine;
private final WifiSettingsStore mSettingsStore;
private final WifiCertManager mCertManager;
- private final WifiNotificationController mNotificationController;
+ private final OpenNetworkNotifier mOpenNetworkNotifier;
private final WifiLockManager mLockManager;
private final WifiController mWifiController;
private final WificondControl mWificondControl;
@@ -231,8 +231,9 @@ public class WifiInjector {
this, mBackupManagerProxy, mCountryCode, mWifiNative,
new WrongPasswordNotifier(mContext, mFrameworkFacade));
mCertManager = new WifiCertManager(mContext);
- mNotificationController = new WifiNotificationController(mContext,
- mWifiStateMachineHandlerThread.getLooper(), mFrameworkFacade, null);
+ mOpenNetworkNotifier = new OpenNetworkNotifier(mContext,
+ mWifiStateMachineHandlerThread.getLooper(), mFrameworkFacade, mClock,
+ new OpenNetworkRecommender());
mLockManager = new WifiLockManager(mContext, BatteryStatsService.getService());
mWifiController = new WifiController(mContext, mWifiStateMachine, mSettingsStore,
mLockManager, mWifiServiceHandlerThread.getLooper(), mFrameworkFacade);
@@ -431,7 +432,7 @@ public class WifiInjector {
boolean hasConnectionRequests) {
return new WifiConnectivityManager(mContext, mWifiStateMachine, getWifiScanner(),
mWifiConfigManager, wifiInfo, mWifiNetworkSelector, mWifiConnectivityHelper,
- mWifiLastResortWatchdog, mNotificationController, mWifiMetrics,
+ mWifiLastResortWatchdog, mOpenNetworkNotifier, mWifiMetrics,
mWifiStateMachineHandlerThread.getLooper(), mClock, mConnectivityLocalLog,
hasConnectionRequests, mFrameworkFacade, mSavedNetworkEvaluator,
mScoredNetworkEvaluator, mPasspointNetworkEvaluator);
diff --git a/service/java/com/android/server/wifi/WifiNotificationController.java b/service/java/com/android/server/wifi/WifiNotificationController.java
deleted file mode 100644
index 797fd438b..000000000
--- a/service/java/com/android/server/wifi/WifiNotificationController.java
+++ /dev/null
@@ -1,252 +0,0 @@
-/*
- * Copyright (C) 2013 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.server.wifi;
-
-import android.annotation.NonNull;
-import android.app.Notification;
-import android.app.NotificationManager;
-import android.app.TaskStackBuilder;
-import android.content.Context;
-import android.content.Intent;
-import android.database.ContentObserver;
-import android.net.wifi.WifiManager;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
-import android.os.UserHandle;
-import android.os.UserManager;
-import android.provider.Settings;
-
-import com.android.internal.notification.SystemNotificationChannels;
-
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-import java.util.List;
-
-/**
- * Takes care of handling the "open wi-fi network available" notification
- * @hide
- */
-public class WifiNotificationController {
- /**
- * The icon to show in the 'available networks' notification. This will also
- * be the ID of the Notification given to the NotificationManager.
- */
- private static final int ICON_NETWORKS_AVAILABLE =
- com.android.internal.R.drawable.stat_notify_wifi_in_range;
- /**
- * When a notification is shown, we wait this amount before possibly showing it again.
- */
- private final long NOTIFICATION_REPEAT_DELAY_MS;
-
- /** Whether the user has set the setting to show the 'available networks' notification. */
- private boolean mSettingEnabled;
-
- /**
- * Observes the user setting to keep {@link #mSettingEnabled} in sync.
- */
- private NotificationEnabledSettingObserver mNotificationEnabledSettingObserver;
-
- /**
- * The {@link System#currentTimeMillis()} must be at least this value for us
- * to show the notification again.
- */
- private long mNotificationRepeatTime;
- /**
- * The Notification object given to the NotificationManager.
- */
- private Notification.Builder mNotificationBuilder;
- /**
- * Whether the notification is being shown, as set by us. That is, if the
- * user cancels the notification, we will not receive the callback so this
- * will still be true. We only guarantee if this is false, then the
- * notification is not showing.
- */
- private boolean mNotificationShown;
- /** Whether the screen is on or not. */
- private boolean mScreenOn;
-
- private final Context mContext;
- private FrameworkFacade mFrameworkFacade;
-
- WifiNotificationController(Context context,
- Looper looper,
- FrameworkFacade framework,
- Notification.Builder builder) {
- mContext = context;
- mFrameworkFacade = framework;
- mNotificationBuilder = builder;
-
- mScreenOn = false;
-
- // Setting is in seconds
- NOTIFICATION_REPEAT_DELAY_MS = mFrameworkFacade.getIntegerSetting(context,
- Settings.Global.WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY, 900) * 1000L;
- mNotificationEnabledSettingObserver = new NotificationEnabledSettingObserver(
- new Handler(looper));
- mNotificationEnabledSettingObserver.register();
- }
-
- /**
- * Clears the pending notification. This is called by {@link WifiConnectivityManager} on stop.
- *
- * @param resetRepeatDelay resets the time delay for repeated notification if true.
- */
- public void clearPendingNotification(boolean resetRepeatDelay) {
- if (resetRepeatDelay) {
- mNotificationRepeatTime = 0;
- }
- setNotificationVisible(false, 0, false, 0);
- }
-
- private boolean isControllerEnabled() {
- return mSettingEnabled && !UserManager.get(mContext)
- .hasUserRestriction(UserManager.DISALLOW_CONFIG_WIFI, UserHandle.CURRENT);
- }
-
- /**
- * If there are open networks, attempt to post an open network notification.
- *
- * @param availableNetworks Available networks from
- * {@link WifiNetworkSelector.NetworkEvaluator#getFilteredScanDetailsForOpenUnsavedNetworks()}.
- */
- public void handleScanResults(@NonNull List<ScanDetail> availableNetworks) {
- if (!isControllerEnabled()) {
- clearPendingNotification(true /* resetRepeatDelay */);
- return;
- }
- if (availableNetworks.isEmpty()) {
- clearPendingNotification(false /* resetRepeatDelay */);
- return;
- }
-
- // Do not show or update the notification if screen is off. We want to avoid a race that
- // could occur between a user picking a network in settings and a network candidate picked
- // through network selection, which will happen because screen on triggers a new
- // connectivity scan.
- if (mNotificationShown || !mScreenOn) {
- return;
- }
-
- setNotificationVisible(true, availableNetworks.size(), false, 0);
- }
-
- /** Handles screen state changes. */
- public void handleScreenStateChanged(boolean screenOn) {
- mScreenOn = screenOn;
- }
-
- /**
- * Display or don't display a notification that there are open Wi-Fi networks.
- * @param visible {@code true} if notification should be visible, {@code false} otherwise
- * @param numNetworks the number networks seen
- * @param force {@code true} to force notification to be shown/not-shown,
- * even if it is already shown/not-shown.
- * @param delay time in milliseconds after which the notification should be made
- * visible or invisible.
- */
- private void setNotificationVisible(boolean visible, int numNetworks, boolean force,
- int delay) {
-
- // Since we use auto cancel on the notification, when the
- // mNetworksAvailableNotificationShown is true, the notification may
- // have actually been canceled. However, when it is false we know
- // for sure that it is not being shown (it will not be shown any other
- // place than here)
-
- // If it should be hidden and it is already hidden, then noop
- if (!visible && !mNotificationShown && !force) {
- return;
- }
-
- NotificationManager notificationManager = (NotificationManager) mContext
- .getSystemService(Context.NOTIFICATION_SERVICE);
-
- Message message;
- if (visible) {
-
- // Not enough time has passed to show the notification again
- if (System.currentTimeMillis() < mNotificationRepeatTime) {
- return;
- }
-
- if (mNotificationBuilder == null) {
- // Cache the Notification builder object.
- mNotificationBuilder = new Notification.Builder(mContext,
- SystemNotificationChannels.NETWORK_AVAILABLE)
- .setWhen(0)
- .setSmallIcon(ICON_NETWORKS_AVAILABLE)
- .setAutoCancel(true)
- .setContentIntent(TaskStackBuilder.create(mContext)
- .addNextIntentWithParentStack(
- new Intent(WifiManager.ACTION_PICK_WIFI_NETWORK))
- .getPendingIntent(0, 0, null, UserHandle.CURRENT))
- .setColor(mContext.getResources().getColor(
- com.android.internal.R.color.system_notification_accent_color));
- }
-
- CharSequence title = mContext.getResources().getQuantityText(
- com.android.internal.R.plurals.wifi_available, numNetworks);
- CharSequence details = mContext.getResources().getQuantityText(
- com.android.internal.R.plurals.wifi_available_detailed, numNetworks);
- mNotificationBuilder.setTicker(title);
- mNotificationBuilder.setContentTitle(title);
- mNotificationBuilder.setContentText(details);
-
- mNotificationRepeatTime = System.currentTimeMillis() + NOTIFICATION_REPEAT_DELAY_MS;
-
- notificationManager.notifyAsUser(null, ICON_NETWORKS_AVAILABLE,
- mNotificationBuilder.build(), UserHandle.ALL);
- } else {
- notificationManager.cancelAsUser(null, ICON_NETWORKS_AVAILABLE, UserHandle.ALL);
- }
-
- mNotificationShown = visible;
- }
-
- /** Dump ONA controller state. */
- public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- pw.println("WifiNotificationController: ");
- pw.println("mSettingEnabled " + mSettingEnabled);
- pw.println("mNotificationRepeatTime " + mNotificationRepeatTime);
- pw.println("mNotificationShown " + mNotificationShown);
- }
-
- private class NotificationEnabledSettingObserver extends ContentObserver {
- NotificationEnabledSettingObserver(Handler handler) {
- super(handler);
- }
-
- public void register() {
- mFrameworkFacade.registerContentObserver(mContext, Settings.Global.getUriFor(
- Settings.Global.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON), true, this);
- mSettingEnabled = getValue();
- }
-
- @Override
- public void onChange(boolean selfChange) {
- super.onChange(selfChange);
- mSettingEnabled = getValue();
- clearPendingNotification(true /* resetRepeatDelay */);
- }
-
- private boolean getValue() {
- return mFrameworkFacade.getIntegerSetting(mContext,
- Settings.Global.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON, 1) == 1;
- }
- }
-}
diff --git a/tests/wifitests/src/com/android/server/wifi/OpenNetworkNotifierTest.java b/tests/wifitests/src/com/android/server/wifi/OpenNetworkNotifierTest.java
new file mode 100644
index 000000000..29c068ddc
--- /dev/null
+++ b/tests/wifitests/src/com/android/server/wifi/OpenNetworkNotifierTest.java
@@ -0,0 +1,322 @@
+/*
+ * 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.server.wifi;
+
+import static com.android.server.wifi.OpenNetworkNotifier.DEFAULT_REPEAT_DELAY_SEC;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.anyInt;
+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.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.res.Resources;
+import android.net.wifi.ScanResult;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.os.test.TestLooper;
+import android.provider.Settings;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Answers;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Unit tests for {@link OpenNetworkNotifier}.
+ */
+public class OpenNetworkNotifierTest {
+
+ private static final String TEST_SSID_1 = "Test SSID 1";
+ private static final int MIN_RSSI_LEVEL = -127;
+
+ @Mock private Context mContext;
+ @Mock private Resources mResources;
+ @Mock private FrameworkFacade mFrameworkFacade;
+ @Mock private Clock mClock;
+ @Mock(answer = Answers.RETURNS_DEEP_STUBS) private Notification.Builder mNotificationBuilder;
+ @Mock private NotificationManager mNotificationManager;
+ @Mock private OpenNetworkRecommender mOpenNetworkRecommender;
+ @Mock private UserManager mUserManager;
+ private OpenNetworkNotifier mNotificationController;
+ private BroadcastReceiver mBroadcastReceiver;
+ private ScanResult mDummyNetwork;
+
+
+ /** Initialize objects before each test run. */
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ when(mContext.getSystemService(Context.NOTIFICATION_SERVICE))
+ .thenReturn(mNotificationManager);
+ when(mFrameworkFacade.getIntegerSetting(mContext,
+ Settings.Global.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON, 1)).thenReturn(1);
+ when(mFrameworkFacade.getIntegerSetting(mContext,
+ Settings.Global.WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY, DEFAULT_REPEAT_DELAY_SEC))
+ .thenReturn(DEFAULT_REPEAT_DELAY_SEC);
+ when(mFrameworkFacade.makeNotificationBuilder(any(), anyString()))
+ .thenReturn(mNotificationBuilder);
+ when(mContext.getSystemService(Context.USER_SERVICE))
+ .thenReturn(mUserManager);
+ when(mContext.getResources()).thenReturn(mResources);
+ mDummyNetwork = new ScanResult();
+ mDummyNetwork.SSID = TEST_SSID_1;
+ mDummyNetwork.capabilities = "[ESS]";
+ mDummyNetwork.level = MIN_RSSI_LEVEL;
+ when(mOpenNetworkRecommender.recommendNetwork(any(), any())).thenReturn(mDummyNetwork);
+
+ TestLooper mock_looper = new TestLooper();
+ mNotificationController = new OpenNetworkNotifier(
+ mContext, mock_looper.getLooper(), mFrameworkFacade,
+ mClock, mOpenNetworkRecommender);
+ ArgumentCaptor<BroadcastReceiver> broadcastReceiverCaptor =
+ ArgumentCaptor.forClass(BroadcastReceiver.class);
+ verify(mContext).registerReceiver(broadcastReceiverCaptor.capture(), any(), any(), any());
+ mBroadcastReceiver = broadcastReceiverCaptor.getValue();
+ mNotificationController.handleScreenStateChanged(true);
+ }
+
+ private List<ScanDetail> createOpenScanResults() {
+ List<ScanDetail> scanResults = new ArrayList<>();
+ scanResults.add(new ScanDetail(mDummyNetwork, null /* networkDetail */));
+ return scanResults;
+ }
+
+ /**
+ * When scan results with open networks are handled, a notification is posted.
+ */
+ @Test
+ public void handleScanResults_hasOpenNetworks_notificationDisplayed() {
+ mNotificationController.handleScanResults(createOpenScanResults());
+
+ verify(mOpenNetworkRecommender).recommendNetwork(any(), any());
+ verify(mNotificationManager).notify(anyInt(), any());
+ }
+
+ /**
+ * When scan results with no open networks are handled, a notification is not posted.
+ */
+ @Test
+ public void handleScanResults_emptyList_notificationNotDisplayed() {
+ mNotificationController.handleScanResults(new ArrayList<>());
+
+ verify(mOpenNetworkRecommender, never()).recommendNetwork(any(), any());
+ verify(mNotificationManager, never()).notify(anyInt(), any());
+ }
+
+ /**
+ * When a notification is showing and scan results with no open networks are handled, the
+ * notification is cleared.
+ */
+ @Test
+ public void handleScanResults_notificationShown_emptyList_notificationCleared() {
+ mNotificationController.handleScanResults(createOpenScanResults());
+
+ verify(mOpenNetworkRecommender).recommendNetwork(any(), any());
+ verify(mNotificationManager).notify(anyInt(), any());
+
+ mNotificationController.handleScanResults(new ArrayList<>());
+
+ verify(mNotificationManager).cancel(anyInt());
+ }
+ /**
+ * When a notification is showing, screen is off, and scan results with no open networks are
+ * handled, the notification is cleared.
+ */
+ @Test
+ public void handleScanResults_notificationShown_screenOff_emptyList_notificationCleared() {
+ mNotificationController.handleScanResults(createOpenScanResults());
+
+ verify(mOpenNetworkRecommender).recommendNetwork(any(), any());
+ verify(mNotificationManager).notify(anyInt(), any());
+
+ mNotificationController.handleScreenStateChanged(false);
+ mNotificationController.handleScanResults(new ArrayList<>());
+
+ verify(mNotificationManager).cancel(anyInt());
+ }
+
+ /**
+ * If notification is showing, do not post another notification.
+ */
+ @Test
+ public void handleScanResults_notificationShowing_doesNotRepostNotification() {
+ mNotificationController.handleScanResults(createOpenScanResults());
+ mNotificationController.handleScanResults(createOpenScanResults());
+
+ verify(mOpenNetworkRecommender).recommendNetwork(any(), any());
+ verify(mNotificationManager).notify(anyInt(), any());
+ }
+
+ /**
+ * When {@link OpenNetworkNotifier#clearPendingNotification(boolean)} is called and a
+ * notification is shown, clear the notification.
+ */
+ @Test
+ public void clearPendingNotification_clearsNotificationIfOneIsShowing() {
+ mNotificationController.handleScanResults(createOpenScanResults());
+
+ verify(mOpenNetworkRecommender).recommendNetwork(any(), any());
+ verify(mNotificationManager).notify(anyInt(), any());
+
+ mNotificationController.clearPendingNotification(true);
+
+ verify(mNotificationManager).cancel(anyInt());
+ }
+
+ /**
+ * When {@link OpenNetworkNotifier#clearPendingNotification(boolean)} is called and a
+ * notification was not previously shown, do not clear the notification.
+ */
+ @Test
+ public void clearPendingNotification_doesNotClearNotificationIfNoneShowing() {
+ mNotificationController.clearPendingNotification(true);
+
+ verify(mNotificationManager, never()).cancel(anyInt());
+ }
+
+ /**
+ * When screen is off and notification is not displayed, notification is not posted on handling
+ * new scan results with open networks.
+ */
+ @Test
+ public void screenOff_handleScanResults_notificationNotDisplayed() {
+ mNotificationController.handleScreenStateChanged(false);
+ mNotificationController.handleScanResults(createOpenScanResults());
+
+ verify(mOpenNetworkRecommender, never()).recommendNetwork(any(), any());
+ verify(mNotificationManager, never()).notify(anyInt(), any());
+ }
+
+ /**
+ * When a notification is posted and cleared without reseting delay, the next scan with open
+ * networks should not post another notification.
+ */
+ @Test
+ public void postNotification_clearNotificationWithoutDelayReset_shouldNotPostNotification() {
+ mNotificationController.handleScanResults(createOpenScanResults());
+
+ verify(mOpenNetworkRecommender).recommendNetwork(any(), any());
+ verify(mNotificationManager).notify(anyInt(), any());
+
+ mNotificationController.clearPendingNotification(false);
+
+ mNotificationController.handleScanResults(createOpenScanResults());
+
+ // Recommendation made twice but no new notification posted.
+ verify(mOpenNetworkRecommender, times(2)).recommendNetwork(any(), any());
+ verify(mNotificationManager).notify(anyInt(), any());
+ verify(mNotificationManager).cancel(anyInt());
+ }
+
+ /**
+ * When a notification is posted and cleared without reseting delay, the next scan with open
+ * networks should post a notification.
+ */
+ @Test
+ public void postNotification_clearNotificationWithDelayReset_shouldPostNotification() {
+ mNotificationController.handleScanResults(createOpenScanResults());
+
+ verify(mOpenNetworkRecommender).recommendNetwork(any(), any());
+ verify(mNotificationManager).notify(anyInt(), any());
+
+ mNotificationController.clearPendingNotification(true);
+
+ mNotificationController.handleScanResults(createOpenScanResults());
+
+ verify(mOpenNetworkRecommender, times(2)).recommendNetwork(any(), any());
+ verify(mNotificationManager, times(2)).notify(anyInt(), any());
+ }
+
+ /**
+ * When a notification is tapped, open Wi-Fi settings.
+ */
+ @Test
+ public void notificationTap_opensWifiSettings() {
+ mNotificationController.handleScanResults(createOpenScanResults());
+
+ verify(mOpenNetworkRecommender).recommendNetwork(any(), any());
+ verify(mNotificationManager).notify(anyInt(), any());
+
+ mBroadcastReceiver.onReceive(
+ mContext, new Intent(OpenNetworkNotifier.ACTION_USER_TAPPED_CONTENT));
+
+ verify(mContext).startActivity(any());
+ }
+
+ /**
+ * When a notification is posted and cleared without reseting delay, after the delay has passed
+ * the next scan with open networks should post a notification.
+ */
+ @Test
+ public void delaySet_delayPassed_shouldPostNotification() {
+ mNotificationController.handleScanResults(createOpenScanResults());
+
+ verify(mOpenNetworkRecommender).recommendNetwork(any(), any());
+ verify(mNotificationManager).notify(anyInt(), any());
+
+ mNotificationController.clearPendingNotification(false);
+
+ // twice the delay time passed
+ when(mClock.getWallClockMillis()).thenReturn(DEFAULT_REPEAT_DELAY_SEC * 1000L * 2);
+
+ mNotificationController.handleScanResults(createOpenScanResults());
+
+ verify(mOpenNetworkRecommender, times(2)).recommendNetwork(any(), any());
+ verify(mNotificationManager, times(2)).notify(anyInt(), any());
+ }
+
+ /** Verifies that {@link UserManager#DISALLOW_CONFIG_WIFI} disables the feature. */
+ @Test
+ public void userHasDisallowConfigWifiRestriction_notificationNotDisplayed() {
+ when(mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_WIFI, UserHandle.CURRENT))
+ .thenReturn(true);
+
+ mNotificationController.handleScanResults(createOpenScanResults());
+
+ verify(mOpenNetworkRecommender, never()).recommendNetwork(any(), any());
+ verify(mNotificationManager, never()).notify(anyInt(), any());
+ }
+
+ /** Verifies that {@link UserManager#DISALLOW_CONFIG_WIFI} clears the showing notification. */
+ @Test
+ public void userHasDisallowConfigWifiRestriction_showingNotificationIsCleared() {
+ mNotificationController.handleScanResults(createOpenScanResults());
+
+ verify(mOpenNetworkRecommender).recommendNetwork(any(), any());
+ verify(mNotificationManager).notify(anyInt(), any());
+
+ when(mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_WIFI, UserHandle.CURRENT))
+ .thenReturn(true);
+
+ mNotificationController.handleScanResults(createOpenScanResults());
+
+ verify(mNotificationManager).cancel(anyInt());
+ }
+}
diff --git a/tests/wifitests/src/com/android/server/wifi/OpenNetworkRecommenderTest.java b/tests/wifitests/src/com/android/server/wifi/OpenNetworkRecommenderTest.java
new file mode 100644
index 000000000..becc1d2e8
--- /dev/null
+++ b/tests/wifitests/src/com/android/server/wifi/OpenNetworkRecommenderTest.java
@@ -0,0 +1,98 @@
+/*
+ * 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.server.wifi;
+
+import static org.junit.Assert.assertEquals;
+
+import android.net.wifi.ScanResult;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Tests for {@link OpenNetworkRecommender}.
+ */
+public class OpenNetworkRecommenderTest {
+
+ private static final String TEST_SSID_1 = "Test SSID 1";
+ private static final String TEST_SSID_2 = "Test SSID 2";
+ private static final int MIN_RSSI_LEVEL = -127;
+
+ private OpenNetworkRecommender mOpenNetworkRecommender;
+
+ @Before
+ public void setUp() throws Exception {
+ mOpenNetworkRecommender = new OpenNetworkRecommender();
+ }
+
+ private List<ScanDetail> createOpenScanResults(String... ssids) {
+ List<ScanDetail> scanResults = new ArrayList<>();
+ for (String ssid : ssids) {
+ ScanResult scanResult = new ScanResult();
+ scanResult.SSID = ssid;
+ scanResult.capabilities = "[ESS]";
+ scanResults.add(new ScanDetail(scanResult, null /* networkDetail */));
+ }
+ return scanResults;
+ }
+
+ /** If list of open networks contain only one network, that network should be returned. */
+ @Test
+ public void onlyNetworkIsRecommended() {
+ List<ScanDetail> scanResults = createOpenScanResults(TEST_SSID_1);
+ scanResults.get(0).getScanResult().level = MIN_RSSI_LEVEL;
+
+ ScanResult actual = mOpenNetworkRecommender.recommendNetwork(scanResults, null);
+ ScanResult expected = scanResults.get(0).getScanResult();
+ assertEquals(expected, actual);
+ }
+
+ /** Verifies that the network with the highest rssi is recommended. */
+ @Test
+ public void networkWithHighestRssiIsRecommended() {
+ List<ScanDetail> scanResults = createOpenScanResults(TEST_SSID_1, TEST_SSID_2);
+ scanResults.get(0).getScanResult().level = MIN_RSSI_LEVEL;
+ scanResults.get(1).getScanResult().level = MIN_RSSI_LEVEL + 1;
+
+ ScanResult actual = mOpenNetworkRecommender.recommendNetwork(scanResults, null);
+ ScanResult expected = scanResults.get(1).getScanResult();
+ assertEquals(expected, actual);
+ }
+
+ /**
+ * If the current recommended network is present in the list for the next recommendation and has
+ * an equal RSSI, the recommendation should not change.
+ */
+ @Test
+ public void currentRecommendationHasEquallyHighRssi_shouldNotChangeRecommendation() {
+ List<ScanDetail> scanResults = createOpenScanResults(TEST_SSID_1, TEST_SSID_2);
+ scanResults.get(0).getScanResult().level = MIN_RSSI_LEVEL + 1;
+ scanResults.get(1).getScanResult().level = MIN_RSSI_LEVEL + 1;
+
+ ScanResult currentRecommendation = new ScanResult(scanResults.get(1).getScanResult());
+ // next recommendation does not depend on the rssi of the input recommendation.
+ currentRecommendation.level = MIN_RSSI_LEVEL;
+
+ ScanResult expected = scanResults.get(1).getScanResult();
+ ScanResult actual = mOpenNetworkRecommender.recommendNetwork(
+ scanResults, currentRecommendation);
+ assertEquals(expected, actual);
+ }
+}
diff --git a/tests/wifitests/src/com/android/server/wifi/WifiConnectivityManagerTest.java b/tests/wifitests/src/com/android/server/wifi/WifiConnectivityManagerTest.java
index bdb6b14ed..a8278d365 100644
--- a/tests/wifitests/src/com/android/server/wifi/WifiConnectivityManagerTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/WifiConnectivityManagerTest.java
@@ -123,7 +123,7 @@ public class WifiConnectivityManagerTest {
@Mock private NetworkScoreManager mNetworkScoreManager;
@Mock private Clock mClock;
@Mock private WifiLastResortWatchdog mWifiLastResortWatchdog;
- @Mock private WifiNotificationController mWifiNotificationController;
+ @Mock private OpenNetworkNotifier mOpenNetworkNotifier;
@Mock private WifiMetrics mWifiMetrics;
@Mock private WifiNetworkScoreCache mScoreCache;
@Captor ArgumentCaptor<ScanResult> mCandidateScanResultCaptor;
@@ -294,7 +294,7 @@ public class WifiConnectivityManagerTest {
WifiConnectivityManager createConnectivityManager() {
return new WifiConnectivityManager(mContext, mWifiStateMachine, mWifiScanner,
mWifiConfigManager, mWifiInfo, mWifiNS, mWifiConnectivityHelper,
- mWifiLastResortWatchdog, mWifiNotificationController, mWifiMetrics,
+ mWifiLastResortWatchdog, mOpenNetworkNotifier, mWifiMetrics,
mLooper.getLooper(), mClock, mLocalLog, true, mFrameworkFacade, null, null, null);
}
@@ -609,7 +609,7 @@ public class WifiConnectivityManagerTest {
}
/**
- * {@link WifiNotificationController} handles scan results on network selection.
+ * {@link OpenNetworkNotifier} handles scan results on network selection.
*
* Expected behavior: ONA handles scan results
*/
@@ -633,11 +633,11 @@ public class WifiConnectivityManagerTest {
mWifiConnectivityManager.handleConnectionStateChanged(
WifiConnectivityManager.WIFI_STATE_DISCONNECTED);
- verify(mWifiNotificationController).handleScanResults(expectedOpenNetworks);
+ verify(mOpenNetworkNotifier).handleScanResults(expectedOpenNetworks);
}
/**
- * When wifi is connected, {@link WifiNotificationController} tries to clear the pending
+ * When wifi is connected, {@link OpenNetworkNotifier} tries to clear the pending
* notification and does not reset notification repeat delay.
*
* Expected behavior: ONA clears pending notification and does not reset repeat delay.
@@ -648,11 +648,11 @@ public class WifiConnectivityManagerTest {
mWifiConnectivityManager.handleConnectionStateChanged(
WifiConnectivityManager.WIFI_STATE_CONNECTED);
- verify(mWifiNotificationController).clearPendingNotification(false /* isRepeatDelayReset*/);
+ verify(mOpenNetworkNotifier).clearPendingNotification(false /* isRepeatDelayReset*/);
}
/**
- * When wifi is connected, {@link WifiNotificationController} handles connection state
+ * When wifi is connected, {@link OpenNetworkNotifier} handles connection state
* change.
*
* Expected behavior: ONA does not clear pending notification.
@@ -663,7 +663,7 @@ public class WifiConnectivityManagerTest {
mWifiConnectivityManager.handleConnectionStateChanged(
WifiConnectivityManager.WIFI_STATE_DISCONNECTED);
- verify(mWifiNotificationController, never()).clearPendingNotification(anyBoolean());
+ verify(mOpenNetworkNotifier, never()).clearPendingNotification(anyBoolean());
}
/**
@@ -675,7 +675,7 @@ public class WifiConnectivityManagerTest {
public void openNetworkNotificationControllerToggledOnWifiStateChanges() {
mWifiConnectivityManager.setWifiEnabled(false);
- verify(mWifiNotificationController).clearPendingNotification(true /* isRepeatDelayReset */);
+ verify(mOpenNetworkNotifier).clearPendingNotification(true /* isRepeatDelayReset */);
}
/**
@@ -685,11 +685,11 @@ public class WifiConnectivityManagerTest {
public void openNetworkNotificationControllerTracksScreenStateChanges() {
mWifiConnectivityManager.handleScreenStateChanged(false);
- verify(mWifiNotificationController).handleScreenStateChanged(false);
+ verify(mOpenNetworkNotifier).handleScreenStateChanged(false);
mWifiConnectivityManager.handleScreenStateChanged(true);
- verify(mWifiNotificationController).handleScreenStateChanged(true);
+ verify(mOpenNetworkNotifier).handleScreenStateChanged(true);
}
/**
@@ -1652,7 +1652,7 @@ public class WifiConnectivityManagerTest {
/**
* Dump ONA controller.
*
- * Expected behavior: {@link WifiNotificationController#dump(FileDescriptor, PrintWriter,
+ * Expected behavior: {@link OpenNetworkNotifier#dump(FileDescriptor, PrintWriter,
* String[])} is invoked.
*/
@Test
@@ -1661,6 +1661,6 @@ public class WifiConnectivityManagerTest {
PrintWriter pw = new PrintWriter(sw);
mWifiConnectivityManager.dump(new FileDescriptor(), pw, new String[]{});
- verify(mWifiNotificationController).dump(any(), any(), any());
+ verify(mOpenNetworkNotifier).dump(any(), any(), any());
}
}
diff --git a/tests/wifitests/src/com/android/server/wifi/WifiNotificationControllerTest.java b/tests/wifitests/src/com/android/server/wifi/WifiNotificationControllerTest.java
deleted file mode 100644
index 27055a885..000000000
--- a/tests/wifitests/src/com/android/server/wifi/WifiNotificationControllerTest.java
+++ /dev/null
@@ -1,208 +0,0 @@
-/*
- * 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.server.wifi;
-
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.anyInt;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-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.res.Resources;
-import android.net.wifi.ScanResult;
-import android.os.UserHandle;
-import android.os.UserManager;
-import android.os.test.TestLooper;
-import android.provider.Settings;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Unit tests for {@link WifiNotificationController}.
- */
-public class WifiNotificationControllerTest {
-
- @Mock private Context mContext;
- @Mock private Resources mResources;
- @Mock private FrameworkFacade mFrameworkFacade;
- @Mock private NotificationManager mNotificationManager;
- @Mock private UserManager mUserManager;
- private WifiNotificationController mNotificationController;
-
-
- /** Initialize objects before each test run. */
- @Before
- public void setUp() throws Exception {
- MockitoAnnotations.initMocks(this);
- when(mContext.getSystemService(Context.NOTIFICATION_SERVICE))
- .thenReturn(mNotificationManager);
- when(mFrameworkFacade.getIntegerSetting(mContext,
- Settings.Global.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON, 1)).thenReturn(1);
- when(mContext.getSystemService(Context.USER_SERVICE))
- .thenReturn(mUserManager);
- when(mContext.getResources()).thenReturn(mResources);
-
- TestLooper mock_looper = new TestLooper();
- mNotificationController = new WifiNotificationController(
- mContext, mock_looper.getLooper(), mFrameworkFacade,
- mock(Notification.Builder.class));
- mNotificationController.handleScreenStateChanged(true);
- }
-
- private List<ScanDetail> createOpenScanResults() {
- List<ScanDetail> scanResults = new ArrayList<>();
- ScanResult scanResult = new ScanResult();
- scanResult.capabilities = "[ESS]";
- scanResults.add(new ScanDetail(scanResult, null /* networkDetail */));
- return scanResults;
- }
-
- /**
- * When scan results with open networks are handled, a notification is posted.
- */
- @Test
- public void handleScanResults_hasOpenNetworks_notificationDisplayed() {
- mNotificationController.handleScanResults(createOpenScanResults());
-
- verify(mNotificationManager).notifyAsUser(any(), anyInt(), any(), any());
- }
-
- /**
- * When scan results with no open networks are handled, a notification is not posted.
- */
- @Test
- public void handleScanResults_emptyList_notificationNotDisplayed() {
- mNotificationController.handleScanResults(new ArrayList<>());
-
- verify(mNotificationManager, never()).notifyAsUser(any(), anyInt(), any(), any());
- }
-
- /**
- * When a notification is showing and scan results with no open networks are handled, the
- * notification is cleared.
- */
- @Test
- public void handleScanResults_notificationShown_emptyList_notificationCleared() {
- mNotificationController.handleScanResults(createOpenScanResults());
-
- verify(mNotificationManager).notifyAsUser(any(), anyInt(), any(), any());
-
- mNotificationController.handleScanResults(new ArrayList<>());
-
- verify(mNotificationManager).cancelAsUser(any(), anyInt(), any());
- }
- /**
- * When a notification is showing, screen is off, and scan results with no open networks are
- * handled, the notification is cleared.
- */
- @Test
- public void handleScanResults_notificationShown_screenOff_emptyList_notificationCleared() {
- mNotificationController.handleScanResults(createOpenScanResults());
-
- verify(mNotificationManager).notifyAsUser(any(), anyInt(), any(), any());
-
- mNotificationController.handleScreenStateChanged(false);
- mNotificationController.handleScanResults(new ArrayList<>());
-
- verify(mNotificationManager).cancelAsUser(any(), anyInt(), any());
- }
-
- /**
- * If notification is showing, do not post another notification.
- */
- @Test
- public void handleScanResults_notificationShowing_doesNotRepostNotification() {
- mNotificationController.handleScanResults(createOpenScanResults());
- mNotificationController.handleScanResults(createOpenScanResults());
-
- verify(mNotificationManager).notifyAsUser(any(), anyInt(), any(), any());
- }
-
- /**
- * When {@link WifiNotificationController#clearPendingNotification(boolean)} is called and a
- * notification is shown, clear the notification.
- */
- @Test
- public void clearPendingNotification_clearsNotificationIfOneIsShowing() {
- mNotificationController.handleScanResults(createOpenScanResults());
-
- verify(mNotificationManager).notifyAsUser(any(), anyInt(), any(), any());
-
- mNotificationController.clearPendingNotification(true);
-
- verify(mNotificationManager).cancelAsUser(any(), anyInt(), any());
- }
-
- /**
- * When {@link WifiNotificationController#clearPendingNotification(boolean)} is called and a
- * notification was not previously shown, do not clear the notification.
- */
- @Test
- public void clearPendingNotification_doesNotClearNotificationIfNoneShowing() {
- mNotificationController.clearPendingNotification(true);
-
- verify(mNotificationManager, never()).cancelAsUser(any(), anyInt(), any());
- }
-
- /**
- * When screen is off and notification is not displayed, notification is not posted on handling
- * new scan results with open networks.
- */
- @Test
- public void screenOff_handleScanResults_notificationNotDisplayed() {
- mNotificationController.handleScreenStateChanged(false);
- mNotificationController.handleScanResults(createOpenScanResults());
-
- verify(mNotificationManager, never()).notifyAsUser(any(), anyInt(), any(), any());
- }
-
- /** Verifies that {@link UserManager#DISALLOW_CONFIG_WIFI} disables the feature. */
- @Test
- public void userHasDisallowConfigWifiRestriction_notificationNotDisplayed() {
- when(mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_WIFI, UserHandle.CURRENT))
- .thenReturn(true);
-
- mNotificationController.handleScanResults(createOpenScanResults());
-
- verify(mNotificationManager, never()).notifyAsUser(any(), anyInt(), any(), any());
- }
-
- /** Verifies that {@link UserManager#DISALLOW_CONFIG_WIFI} clears the showing notification. */
- @Test
- public void userHasDisallowConfigWifiRestriction_showingNotificationIsCleared() {
- mNotificationController.handleScanResults(createOpenScanResults());
-
- verify(mNotificationManager).notifyAsUser(any(), anyInt(), any(), any());
-
- when(mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_WIFI, UserHandle.CURRENT))
- .thenReturn(true);
-
- mNotificationController.handleScanResults(createOpenScanResults());
-
- verify(mNotificationManager).cancelAsUser(any(), anyInt(), any());
- }
-}