diff options
author | TreeHugger Robot <treehugger-gerrit@google.com> | 2017-07-25 18:03:30 +0000 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2017-07-25 18:03:30 +0000 |
commit | 6db34c0303b84c1c212a8f013ec90b257fb96052 (patch) | |
tree | 8513dee37cac5b4129c09e133cb6c89c90e08857 | |
parent | a305257d7c3b3421d47fb8f00799749aae9645a2 (diff) | |
parent | 3f8483262cf59572d0c0b3c42e72d8ce65a096ff (diff) |
Merge "ONA: Change ONA controller to directly handle scan results from WifiConnectivityManager." into oc-dr1-dev
7 files changed, 250 insertions, 247 deletions
diff --git a/service/java/com/android/server/wifi/WifiConnectivityManager.java b/service/java/com/android/server/wifi/WifiConnectivityManager.java index 99300bd50..13863c9bf 100644 --- a/service/java/com/android/server/wifi/WifiConnectivityManager.java +++ b/service/java/com/android/server/wifi/WifiConnectivityManager.java @@ -133,6 +133,7 @@ public class WifiConnectivityManager { private final WifiConnectivityHelper mConnectivityHelper; private final WifiNetworkSelector mNetworkSelector; private final WifiLastResortWatchdog mWifiLastResortWatchdog; + private final WifiNotificationController mWifiNotificationController; private final WifiMetrics mWifiMetrics; private final AlarmManager mAlarmManager; private final Handler mEventHandler; @@ -268,6 +269,10 @@ public class WifiConnectivityManager { connectToNetwork(candidate); return true; } else { + if (mWifiState == WIFI_STATE_DISCONNECTED) { + mWifiNotificationController.handleScanResults( + mNetworkSelector.getFilteredScanDetailsForOpenUnsavedNetworks()); + } return false; } } @@ -527,7 +532,8 @@ public class WifiConnectivityManager { WifiConnectivityManager(Context context, WifiStateMachine stateMachine, WifiScanner scanner, WifiConfigManager configManager, WifiInfo wifiInfo, WifiNetworkSelector networkSelector, WifiConnectivityHelper connectivityHelper, - WifiLastResortWatchdog wifiLastResortWatchdog, WifiMetrics wifiMetrics, + WifiLastResortWatchdog wifiLastResortWatchdog, + WifiNotificationController wifiNotificationController, WifiMetrics wifiMetrics, Looper looper, Clock clock, LocalLog localLog, boolean enable, FrameworkFacade frameworkFacade, SavedNetworkEvaluator savedNetworkEvaluator, @@ -541,6 +547,7 @@ public class WifiConnectivityManager { mConnectivityHelper = connectivityHelper; mLocalLog = localLog; mWifiLastResortWatchdog = wifiLastResortWatchdog; + mWifiNotificationController = wifiNotificationController; mWifiMetrics = wifiMetrics; mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); mEventHandler = new Handler(looper); @@ -1054,6 +1061,10 @@ public class WifiConnectivityManager { mWifiState = state; + if (mWifiState == WIFI_STATE_CONNECTED) { + mWifiNotificationController.clearPendingNotification(false /* resetRepeatDelay */); + } + // Reset BSSID of last connection attempt and kick off // the watchdog timer if entering disconnected state. if (mWifiState == WIFI_STATE_DISCONNECTED) { @@ -1287,6 +1298,7 @@ public class WifiConnectivityManager { stopConnectivityScan(); clearBssidBlacklist(); resetLastPeriodicSingleScanTimeStamp(); + mWifiNotificationController.clearPendingNotification(true /* resetRepeatDelay */); mLastConnectionAttemptBssid = null; mWaitForFullBandScanResults = false; } @@ -1346,5 +1358,6 @@ public class WifiConnectivityManager { pw.println("WifiConnectivityManager - Log Begin ----"); mLocalLog.dump(fd, pw, args); pw.println("WifiConnectivityManager - Log End ----"); + mWifiNotificationController.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 e1be8a3a9..f7d2e3096 100644 --- a/service/java/com/android/server/wifi/WifiInjector.java +++ b/service/java/com/android/server/wifi/WifiInjector.java @@ -228,7 +228,7 @@ public class WifiInjector { new WrongPasswordNotifier(mContext, mFrameworkFacade)); mCertManager = new WifiCertManager(mContext); mNotificationController = new WifiNotificationController(mContext, - mWifiServiceHandlerThread.getLooper(), mFrameworkFacade, null, this); + mWifiStateMachineHandlerThread.getLooper(), mFrameworkFacade, null); mLockManager = new WifiLockManager(mContext, BatteryStatsService.getService()); mWifiController = new WifiController(mContext, mWifiStateMachine, mSettingsStore, mLockManager, mWifiServiceHandlerThread.getLooper(), mFrameworkFacade); @@ -304,10 +304,6 @@ public class WifiInjector { return mCertManager; } - public WifiNotificationController getWifiNotificationController() { - return mNotificationController; - } - public WifiLockManager getWifiLockManager() { return mLockManager; } @@ -431,9 +427,10 @@ public class WifiInjector { boolean hasConnectionRequests) { return new WifiConnectivityManager(mContext, mWifiStateMachine, getWifiScanner(), mWifiConfigManager, wifiInfo, mWifiNetworkSelector, mWifiConnectivityHelper, - mWifiLastResortWatchdog, mWifiMetrics, mWifiStateMachineHandlerThread.getLooper(), - mClock, mConnectivityLocalLog, hasConnectionRequests, mFrameworkFacade, - mSavedNetworkEvaluator, mScoredNetworkEvaluator, mPasspointNetworkEvaluator); + mWifiLastResortWatchdog, mNotificationController, mWifiMetrics, + mWifiStateMachineHandlerThread.getLooper(), mClock, mConnectivityLocalLog, + hasConnectionRequests, mFrameworkFacade, mSavedNetworkEvaluator, + mScoredNetworkEvaluator, mPasspointNetworkEvaluator); } public WifiPermissionsUtil getWifiPermissionsUtil() { diff --git a/service/java/com/android/server/wifi/WifiNotificationController.java b/service/java/com/android/server/wifi/WifiNotificationController.java index c8e5e908a..3558a8546 100644 --- a/service/java/com/android/server/wifi/WifiNotificationController.java +++ b/service/java/com/android/server/wifi/WifiNotificationController.java @@ -16,18 +16,14 @@ package com.android.server.wifi; +import android.annotation.NonNull; import android.app.Notification; import android.app.NotificationManager; import android.app.TaskStackBuilder; -import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; -import android.content.IntentFilter; import android.database.ContentObserver; -import android.net.NetworkInfo; -import android.net.wifi.ScanResult; import android.net.wifi.WifiManager; -import android.net.wifi.WifiScanner; import android.os.Handler; import android.os.Looper; import android.os.Message; @@ -57,12 +53,11 @@ public class WifiNotificationController { */ private final long NOTIFICATION_REPEAT_DELAY_MS; + /** Whether the user has set the setting to show the 'available networks' notification. */ + private boolean mSettingEnabled; + /** - * Whether the user has set the setting to show the 'available networks' notification. - */ - private boolean mNotificationEnabled; - /** - * Observes the user setting to keep {@link #mNotificationEnabled} in sync. + * Observes the user setting to keep {@link #mSettingEnabled} in sync. */ private NotificationEnabledSettingObserver mNotificationEnabledSettingObserver; @@ -82,93 +77,18 @@ public class WifiNotificationController { * notification is not showing. */ private boolean mNotificationShown; - /** - * The number of continuous scans that must occur before consider the - * supplicant in a scanning state. This allows supplicant to associate with - * remembered networks that are in the scan results. - */ - private static final int NUM_SCANS_BEFORE_ACTUALLY_SCANNING = 3; - /** - * The number of scans since the last network state change. When this - * exceeds {@link #NUM_SCANS_BEFORE_ACTUALLY_SCANNING}, we consider the - * supplicant to actually be scanning. When the network state changes to - * something other than scanning, we reset this to 0. - */ - private int mNumScansSinceNetworkStateChange; + /** Wi-Fi connection state from {@link WifiConnectivityManager} */ private final Context mContext; - private NetworkInfo mNetworkInfo; - private NetworkInfo.DetailedState mDetailedState; - private volatile int mWifiState; private FrameworkFacade mFrameworkFacade; - private WifiInjector mWifiInjector; - private WifiScanner mWifiScanner; WifiNotificationController(Context context, Looper looper, FrameworkFacade framework, - Notification.Builder builder, - WifiInjector wifiInjector) { + Notification.Builder builder) { mContext = context; mFrameworkFacade = framework; mNotificationBuilder = builder; - mWifiInjector = wifiInjector; - mWifiState = WifiManager.WIFI_STATE_UNKNOWN; - mDetailedState = NetworkInfo.DetailedState.IDLE; - - IntentFilter filter = new IntentFilter(); - filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION); - filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION); - filter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION); - - mContext.registerReceiver( - new BroadcastReceiver() { - @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); - resetNotification(); - } else if (intent.getAction().equals( - WifiManager.NETWORK_STATE_CHANGED_ACTION)) { - mNetworkInfo = (NetworkInfo) intent.getParcelableExtra( - WifiManager.EXTRA_NETWORK_INFO); - NetworkInfo.DetailedState detailedState = - mNetworkInfo.getDetailedState(); - if (detailedState != NetworkInfo.DetailedState.SCANNING - && detailedState != mDetailedState) { - mDetailedState = detailedState; - // reset & clear notification on a network connect & disconnect - switch(mDetailedState) { - case CONNECTED: - case DISCONNECTED: - case CAPTIVE_PORTAL_CHECK: - resetNotification(); - break; - - case IDLE: - case SCANNING: - case CONNECTING: - case AUTHENTICATING: - case OBTAINING_IPADDR: - case SUSPENDED: - case FAILED: - case BLOCKED: - case VERIFYING_POOR_LINK: - break; - } - } - } else if (intent.getAction().equals( - WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) { - if (mWifiScanner == null) { - mWifiScanner = mWifiInjector.getWifiScanner(); - } - checkAndSetNotification(mNetworkInfo, - mWifiScanner.getSingleScanResults()); - } - } - }, filter); // Setting is in seconds NOTIFICATION_REPEAT_DELAY_MS = mFrameworkFacade.getIntegerSetting(context, @@ -178,66 +98,43 @@ public class WifiNotificationController { mNotificationEnabledSettingObserver.register(); } - private synchronized void checkAndSetNotification(NetworkInfo networkInfo, - List<ScanResult> scanResults) { - - // TODO: unregister broadcast so we do not have to check here - // If we shouldn't place a notification on available networks, then - // don't bother doing any of the following - if (!mNotificationEnabled) return; - if (mWifiState != WifiManager.WIFI_STATE_ENABLED) return; - if (UserManager.get(mContext) - .hasUserRestriction(UserManager.DISALLOW_CONFIG_WIFI, UserHandle.CURRENT)) { - return; - } - - NetworkInfo.State state = NetworkInfo.State.DISCONNECTED; - if (networkInfo != null) - state = networkInfo.getState(); - - if ((state == NetworkInfo.State.DISCONNECTED) - || (state == NetworkInfo.State.UNKNOWN)) { - if (scanResults != null) { - int numOpenNetworks = 0; - for (int i = scanResults.size() - 1; i >= 0; i--) { - ScanResult scanResult = scanResults.get(i); - - //A capability of [ESS] represents an open access point - //that is available for an STA to connect - if (scanResult.capabilities != null && - scanResult.capabilities.equals("[ESS]")) { - numOpenNetworks++; - } - } - - if (numOpenNetworks > 0) { - if (++mNumScansSinceNetworkStateChange >= NUM_SCANS_BEFORE_ACTUALLY_SCANNING) { - /* - * We've scanned continuously at least - * NUM_SCANS_BEFORE_NOTIFICATION times. The user - * probably does not have a remembered network in range, - * since otherwise supplicant would have tried to - * associate and thus resetting this counter. - */ - setNotificationVisible(true, numOpenNetworks, false, 0); - } - return; - } - } + /** + * 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; } - - // No open networks in range, remove the notification setNotificationVisible(false, 0, false, 0); } + private boolean isControllerEnabled() { + return mSettingEnabled && !UserManager.get(mContext) + .hasUserRestriction(UserManager.DISALLOW_CONFIG_WIFI, UserHandle.CURRENT); + } + /** - * Clears variables related to tracking whether a notification has been - * shown recently and clears the current notification. + * If there are open networks, attempt to post an open network notification. + * + * @param availableNetworks Available networks from + * {@link WifiNetworkSelector.NetworkEvaluator#getFilteredScanDetailsForOpenUnsavedNetworks()}. */ - private synchronized void resetNotification() { - mNotificationRepeatTime = 0; - mNumScansSinceNetworkStateChange = 0; - setNotificationVisible(false, 0, false, 0); + public void handleScanResults(@NonNull List<ScanDetail> availableNetworks) { + if (!isControllerEnabled()) { + clearPendingNotification(true /* resetRepeatDelay */); + return; + } + if (availableNetworks.isEmpty()) { + clearPendingNotification(false /* resetRepeatDelay */); + return; + } + if (mNotificationShown) { + return; + } + + setNotificationVisible(true, availableNetworks.size(), false, 0); } /** @@ -308,34 +205,30 @@ public class WifiNotificationController { mNotificationShown = visible; } - void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - pw.println("mNotificationEnabled " + mNotificationEnabled); + /** 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); - pw.println("mNumScansSinceNetworkStateChange " + mNumScansSinceNetworkStateChange); } private class NotificationEnabledSettingObserver extends ContentObserver { - public NotificationEnabledSettingObserver(Handler handler) { + NotificationEnabledSettingObserver(Handler handler) { super(handler); } public void register() { mFrameworkFacade.registerContentObserver(mContext, Settings.Global.getUriFor( Settings.Global.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON), true, this); - synchronized (WifiNotificationController.this) { - mNotificationEnabled = getValue(); - } + mSettingEnabled = getValue(); } @Override public void onChange(boolean selfChange) { super.onChange(selfChange); - - synchronized (WifiNotificationController.this) { - mNotificationEnabled = getValue(); - resetNotification(); - } + mSettingEnabled = getValue(); + clearPendingNotification(true /* resetRepeatDelay */); } private boolean getValue() { diff --git a/service/java/com/android/server/wifi/WifiServiceImpl.java b/service/java/com/android/server/wifi/WifiServiceImpl.java index 97e5ee72c..d222727b5 100644 --- a/service/java/com/android/server/wifi/WifiServiceImpl.java +++ b/service/java/com/android/server/wifi/WifiServiceImpl.java @@ -169,8 +169,6 @@ public class WifiServiceImpl extends IWifiManager.Stub { // Debug counter tracking scan requests sent by WifiManager private int scanRequestCounter = 0; - /* Tracks the open wi-fi network notification */ - private WifiNotificationController mNotificationController; /* Polls traffic stats and notifies clients */ private WifiTrafficPoller mTrafficPoller; /* Tracks the persisted states for wi-fi & airplane mode */ @@ -441,7 +439,6 @@ public class WifiServiceImpl extends IWifiManager.Stub { mAppOps = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE); mActivityManager = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE); mCertManager = mWifiInjector.getWifiCertManager(); - mNotificationController = mWifiInjector.getWifiNotificationController(); mWifiLockManager = mWifiInjector.getWifiLockManager(); mWifiMulticastLockManager = mWifiInjector.getWifiMulticastLockManager(); HandlerThread wifiServiceHandlerThread = mWifiInjector.getWifiServiceHandlerThread(); @@ -2291,7 +2288,6 @@ public class WifiServiceImpl extends IWifiManager.Stub { pw.println("mScanPending " + mScanPending); mWifiController.dump(fd, pw, args); mSettingsStore.dump(fd, pw, args); - mNotificationController.dump(fd, pw, args); mTrafficPoller.dump(fd, pw, args); pw.println(); pw.println("Locks held:"); diff --git a/tests/wifitests/src/com/android/server/wifi/WifiConnectivityManagerTest.java b/tests/wifitests/src/com/android/server/wifi/WifiConnectivityManagerTest.java index d4eef041e..11e220e7f 100644 --- a/tests/wifitests/src/com/android/server/wifi/WifiConnectivityManagerTest.java +++ b/tests/wifitests/src/com/android/server/wifi/WifiConnectivityManagerTest.java @@ -63,6 +63,7 @@ import java.io.StringWriter; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.HashSet; +import java.util.List; /** * Unit tests for {@link com.android.server.wifi.WifiConnectivityManager}. @@ -122,6 +123,7 @@ public class WifiConnectivityManagerTest { @Mock private NetworkScoreManager mNetworkScoreManager; @Mock private Clock mClock; @Mock private WifiLastResortWatchdog mWifiLastResortWatchdog; + @Mock private WifiNotificationController mWifiNotificationController; @Mock private WifiMetrics mWifiMetrics; @Mock private WifiNetworkScoreCache mScoreCache; @Captor ArgumentCaptor<ScanResult> mCandidateScanResultCaptor; @@ -292,8 +294,8 @@ public class WifiConnectivityManagerTest { WifiConnectivityManager createConnectivityManager() { return new WifiConnectivityManager(mContext, mWifiStateMachine, mWifiScanner, mWifiConfigManager, mWifiInfo, mWifiNS, mWifiConnectivityHelper, - mWifiLastResortWatchdog, mWifiMetrics, mLooper.getLooper(), mClock, - mLocalLog, true, mFrameworkFacade, null, null, null); + mWifiLastResortWatchdog, mWifiNotificationController, mWifiMetrics, + mLooper.getLooper(), mClock, mLocalLog, true, mFrameworkFacade, null, null, null); } /** @@ -607,6 +609,76 @@ public class WifiConnectivityManagerTest { } /** + * {@link WifiNotificationController} handles scan results on network selection. + * + * Expected behavior: ONA handles scan results + */ + @Test + public void wifiDisconnected_noConnectionCandidate_openNetworkNotificationScanResultsHandled() { + // no connection candidate selected + when(mWifiNS.selectNetwork(anyObject(), anyObject(), anyObject(), anyBoolean(), + anyBoolean(), anyBoolean())).thenReturn(null); + + List<ScanDetail> expectedOpenNetworks = new ArrayList<>(); + expectedOpenNetworks.add( + new ScanDetail( + new ScanResult(WifiSsid.createFromAsciiEncoded(CANDIDATE_SSID), + CANDIDATE_SSID, CANDIDATE_BSSID, 1245, 0, "some caps", -78, 2450, + 1025, 22, 33, 20, 0, 0, true), null)); + + when(mWifiNS.getFilteredScanDetailsForOpenUnsavedNetworks()) + .thenReturn(expectedOpenNetworks); + + // Set WiFi to disconnected state to trigger PNO scan + mWifiConnectivityManager.handleConnectionStateChanged( + WifiConnectivityManager.WIFI_STATE_DISCONNECTED); + + verify(mWifiNotificationController).handleScanResults(expectedOpenNetworks); + } + + /** + * When wifi is connected, {@link WifiNotificationController} 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. + */ + @Test + public void wifiConnected_openNetworkNotificationClearsPendingNotification() { + // Set WiFi to connected state + mWifiConnectivityManager.handleConnectionStateChanged( + WifiConnectivityManager.WIFI_STATE_CONNECTED); + + verify(mWifiNotificationController).clearPendingNotification(false /* isRepeatDelayReset*/); + } + + /** + * When wifi is connected, {@link WifiNotificationController} handles connection state + * change. + * + * Expected behavior: ONA does not clear pending notification. + */ + @Test + public void wifiDisconnected_openNetworkNotificationDoesNotClearPendingNotification() { + // Set WiFi to disconnected state + mWifiConnectivityManager.handleConnectionStateChanged( + WifiConnectivityManager.WIFI_STATE_DISCONNECTED); + + verify(mWifiNotificationController, never()).clearPendingNotification(anyBoolean()); + } + + /** + * When Wi-Fi is disabled, clear the pending notification and reset notification repeat delay. + * + * Expected behavior: clear pending notification and reset notification repeat delay + * */ + @Test + public void openNetworkNotificationControllerToggledOnWifiStateChanges() { + mWifiConnectivityManager.setWifiEnabled(false); + + verify(mWifiNotificationController).clearPendingNotification(true /* isRepeatDelayReset */); + } + + /** * Verify that scan interval for screen on and wifi disconnected scenario * is in the exponential backoff fashion. * @@ -1562,4 +1634,19 @@ public class WifiConnectivityManagerTest { mWifiConnectivityManager.dump(new FileDescriptor(), pw, new String[]{}); assertTrue(sw.toString().contains(localLogMessage)); } + + /** + * Dump ONA controller. + * + * Expected behavior: {@link WifiNotificationController#dump(FileDescriptor, PrintWriter, + * String[])} is invoked. + */ + @Test + public void dumpNotificationController() { + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw); + mWifiConnectivityManager.dump(new FileDescriptor(), pw, new String[]{}); + + verify(mWifiNotificationController).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 index f7b3bf6a1..9aa5ee938 100644 --- a/tests/wifitests/src/com/android/server/wifi/WifiNotificationControllerTest.java +++ b/tests/wifitests/src/com/android/server/wifi/WifiNotificationControllerTest.java @@ -16,7 +16,7 @@ package com.android.server.wifi; -import static org.mockito.Mockito.any; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.anyInt; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; @@ -25,23 +25,16 @@ 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.IntentFilter; import android.content.res.Resources; -import android.net.NetworkInfo; import android.net.wifi.ScanResult; -import android.net.wifi.WifiManager; -import android.net.wifi.WifiScanner; import android.os.UserHandle; import android.os.UserManager; import android.os.test.TestLooper; import android.provider.Settings; -import android.test.suitebuilder.annotation.SmallTest; import org.junit.Before; import org.junit.Test; -import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; @@ -49,26 +42,17 @@ import java.util.ArrayList; import java.util.List; /** - * Unit tests for {@link com.android.server.wifi.WifiScanningServiceImpl}. + * Unit tests for {@link WifiNotificationController}. */ -@SmallTest public class WifiNotificationControllerTest { - public static final String TAG = "WifiScanningServiceTest"; @Mock private Context mContext; @Mock private Resources mResources; @Mock private FrameworkFacade mFrameworkFacade; @Mock private NotificationManager mNotificationManager; @Mock private UserManager mUserManager; - @Mock private WifiInjector mWifiInjector; - @Mock private WifiScanner mWifiScanner; - WifiNotificationController mWifiNotificationController; + private WifiNotificationController mNotificationController; - /** - * Internal BroadcastReceiver that WifiNotificationController uses to listen for broadcasts - * this is initialized by calling startServiceAndLoadDriver - */ - BroadcastReceiver mBroadcastReceiver; /** Initialize objects before each test run. */ @Before @@ -76,86 +60,121 @@ public class WifiNotificationControllerTest { 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); - when(mWifiInjector.getWifiScanner()).thenReturn(mWifiScanner); - TestLooper mock_looper = new TestLooper(); - mWifiNotificationController = new WifiNotificationController( + mNotificationController = new WifiNotificationController( mContext, mock_looper.getLooper(), mFrameworkFacade, - mock(Notification.Builder.class), mWifiInjector); - ArgumentCaptor<BroadcastReceiver> broadcastReceiverCaptor = - ArgumentCaptor.forClass(BroadcastReceiver.class); - - verify(mContext) - .registerReceiver(broadcastReceiverCaptor.capture(), any(IntentFilter.class)); - mBroadcastReceiver = broadcastReceiverCaptor.getValue(); + mock(Notification.Builder.class)); } - private void setOpenAccessPoint() { - List<ScanResult> scanResults = new ArrayList<>(); + private List<ScanDetail> createOpenScanResults() { + List<ScanDetail> scanResults = new ArrayList<>(); ScanResult scanResult = new ScanResult(); scanResult.capabilities = "[ESS]"; - scanResults.add(scanResult); - when(mWifiScanner.getSingleScanResults()).thenReturn(scanResults); + 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()); } - /** Verifies that a notification is displayed (and retracted) given system events. */ + /** + * When a notification is showing and scan results with no open networks are handled, the + * notification is cleared. + */ @Test - public void verifyNotificationDisplayed() throws Exception { - TestUtil.sendWifiStateChanged(mBroadcastReceiver, mContext, WifiManager.WIFI_STATE_ENABLED); - TestUtil.sendNetworkStateChanged(mBroadcastReceiver, mContext, - NetworkInfo.DetailedState.DISCONNECTED); - setOpenAccessPoint(); - - // The notification should not be displayed after only two scan results. - TestUtil.sendScanResultsAvailable(mBroadcastReceiver, mContext); - TestUtil.sendScanResultsAvailable(mBroadcastReceiver, mContext); - verify(mNotificationManager, never()) - .notifyAsUser(any(), anyInt(), any(), any(UserHandle.class)); - - // Changing to and from "SCANNING" state should not affect the counter. - TestUtil.sendNetworkStateChanged(mBroadcastReceiver, mContext, - NetworkInfo.DetailedState.SCANNING); - TestUtil.sendNetworkStateChanged(mBroadcastReceiver, mContext, - NetworkInfo.DetailedState.DISCONNECTED); - - // The third scan result notification will trigger the notification. - TestUtil.sendScanResultsAvailable(mBroadcastReceiver, mContext); - verify(mNotificationManager) - .notifyAsUser(any(), anyInt(), any(), any(UserHandle.class)); - verify(mNotificationManager, never()) - .cancelAsUser(any(), anyInt(), any(UserHandle.class)); - - // Changing network state should cause the notification to go away. - TestUtil.sendNetworkStateChanged(mBroadcastReceiver, mContext, - NetworkInfo.DetailedState.CONNECTED); - verify(mNotificationManager) - .cancelAsUser(any(), anyInt(), any(UserHandle.class)); + 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()); } + /** + * If notification is showing, do not post another notification. + */ @Test - public void verifyNotificationNotDisplayed_userHasDisallowConfigWifiRestriction() { + 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()); + } + + /** 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); - TestUtil.sendWifiStateChanged(mBroadcastReceiver, mContext, WifiManager.WIFI_STATE_ENABLED); - TestUtil.sendNetworkStateChanged(mBroadcastReceiver, mContext, - NetworkInfo.DetailedState.DISCONNECTED); - setOpenAccessPoint(); + 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); - // The notification should be displayed after three scan results. - TestUtil.sendScanResultsAvailable(mBroadcastReceiver, mContext); - TestUtil.sendScanResultsAvailable(mBroadcastReceiver, mContext); - TestUtil.sendScanResultsAvailable(mBroadcastReceiver, mContext); + mNotificationController.handleScanResults(createOpenScanResults()); - verify(mNotificationManager, never()) - .notifyAsUser(any(), anyInt(), any(), any(UserHandle.class)); + verify(mNotificationManager).cancelAsUser(any(), anyInt(), any()); } } diff --git a/tests/wifitests/src/com/android/server/wifi/WifiServiceImplTest.java b/tests/wifitests/src/com/android/server/wifi/WifiServiceImplTest.java index ce4556d50..3b11d28c9 100644 --- a/tests/wifitests/src/com/android/server/wifi/WifiServiceImplTest.java +++ b/tests/wifitests/src/com/android/server/wifi/WifiServiceImplTest.java @@ -161,7 +161,6 @@ public class WifiServiceImplTest { @Mock ActivityManager mActivityManager; @Mock AppOpsManager mAppOpsManager; @Mock IBinder mAppBinder; - @Mock WifiNotificationController mWifiNotificationController; @Mock LocalOnlyHotspotRequestInfo mRequestInfo; @Mock LocalOnlyHotspotRequestInfo mRequestInfo2; @@ -278,7 +277,6 @@ public class WifiServiceImplTest { when(mWifiInjector.getWifiPermissionsUtil()).thenReturn(mWifiPermissionsUtil); when(mWifiInjector.getWifiSettingsStore()).thenReturn(mSettingsStore); when(mWifiInjector.getClock()).thenReturn(mClock); - when(mWifiInjector.getWifiNotificationController()).thenReturn(mWifiNotificationController); mWifiServiceImpl = new WifiServiceImpl(mContext, mWifiInjector, mAsyncChannel); mWifiServiceImpl.setWifiHandlerLogForTest(mLog); } |