diff options
6 files changed, 146 insertions, 15 deletions
diff --git a/service/java/com/android/server/wifi/OpenNetworkNotifier.java b/service/java/com/android/server/wifi/OpenNetworkNotifier.java index 692c8e22c..279223759 100644 --- a/service/java/com/android/server/wifi/OpenNetworkNotifier.java +++ b/service/java/com/android/server/wifi/OpenNetworkNotifier.java @@ -24,8 +24,12 @@ import android.content.Intent; import android.content.IntentFilter; import android.database.ContentObserver; import android.net.wifi.ScanResult; +import android.net.wifi.WifiConfiguration; +import android.net.wifi.WifiManager; import android.os.Handler; import android.os.Looper; +import android.os.Message; +import android.os.Messenger; import android.os.UserHandle; import android.os.UserManager; import android.provider.Settings; @@ -34,6 +38,7 @@ import android.util.Log; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.messages.nano.SystemMessageProto.SystemMessage; +import com.android.server.wifi.util.ScanResultUtil; import java.io.FileDescriptor; import java.io.PrintWriter; @@ -54,6 +59,8 @@ public class OpenNetworkNotifier { "com.android.server.wifi.OpenNetworkNotifier.USER_DISMISSED_NOTIFICATION"; static final String ACTION_USER_TAPPED_CONTENT = "com.android.server.wifi.OpenNetworkNotifier.USER_TAPPED_CONTENT"; + static final String ACTION_CONNECT_TO_NETWORK = + "com.android.server.wifi.OpenNetworkNotifier.CONNECT_TO_NETWORK"; /** Identifier of the {@link SsidSetStoreData}. */ private static final String STORE_DATA_IDENTIFIER = "OpenNetworkNotifierBlacklist"; @@ -85,6 +92,8 @@ public class OpenNetworkNotifier { private final FrameworkFacade mFrameworkFacade; private final Clock mClock; private final WifiConfigManager mConfigManager; + private final WifiStateMachine mWifiStateMachine; + private final Messenger mSrcMessenger; private final OpenNetworkRecommender mOpenNetworkRecommender; private final OpenNetworkNotificationBuilder mOpenNetworkNotificationBuilder; @@ -97,15 +106,18 @@ public class OpenNetworkNotifier { Clock clock, WifiConfigManager wifiConfigManager, WifiConfigStore wifiConfigStore, + WifiStateMachine wifiStateMachine, OpenNetworkRecommender openNetworkRecommender) { mContext = context; mHandler = new Handler(looper); mFrameworkFacade = framework; mClock = clock; mConfigManager = wifiConfigManager; + mWifiStateMachine = wifiStateMachine; mOpenNetworkRecommender = openNetworkRecommender; mOpenNetworkNotificationBuilder = new OpenNetworkNotificationBuilder(context, framework); mScreenOn = false; + mSrcMessenger = new Messenger(new Handler(looper, mConnectionStateCallback)); mBlacklistedSsids = new ArraySet<>(); wifiConfigStore.registerStoreData(new SsidSetStoreData( @@ -122,6 +134,7 @@ public class OpenNetworkNotifier { IntentFilter filter = new IntentFilter(); filter.addAction(ACTION_USER_DISMISSED_NOTIFICATION); filter.addAction(ACTION_USER_TAPPED_CONTENT); + filter.addAction(ACTION_CONNECT_TO_NETWORK); mContext.registerReceiver( mBroadcastReceiver, filter, null /* broadcastPermission */, mHandler); } @@ -130,14 +143,38 @@ public class OpenNetworkNotifier { 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(); + switch (intent.getAction()) { + case ACTION_USER_TAPPED_CONTENT: + handleUserClickedContentAction(); + break; + case ACTION_USER_DISMISSED_NOTIFICATION: + handleUserDismissedAction(); + break; + case ACTION_CONNECT_TO_NETWORK: + handleConnectToNetworkAction(); + break; + default: + Log.e(TAG, "Unknown action " + intent.getAction()); } } }; + private final Handler.Callback mConnectionStateCallback = (Message msg) -> { + switch (msg.what) { + // Success here means that an attempt to connect to the network has been initiated. + // Successful connection updates are received via the + // WifiConnectivityManager#handleConnectionStateChanged() callback. + case WifiManager.CONNECT_NETWORK_SUCCEEDED: + break; + case WifiManager.CONNECT_NETWORK_FAILED: + handleConnectionFailure(); + break; + default: + Log.e(TAG, "Unknown message " + msg.what); + } + return true; + }; + /** * Clears the pending notification. This is called by {@link WifiConnectivityManager} on stop. * @@ -213,6 +250,27 @@ public class OpenNetworkNotifier { mNotificationRepeatTime = mClock.getWallClockMillis() + mNotificationRepeatDelay; } + private void handleConnectToNetworkAction() { + if (mRecommendedNetwork == null) { + return; + } + Log.d(TAG, "User initiated connection to recommended network: " + mRecommendedNetwork.SSID); + WifiConfiguration network = ScanResultUtil.createNetworkFromScanResult(mRecommendedNetwork); + Message msg = Message.obtain(); + msg.what = WifiManager.CONNECT_NETWORK; + msg.arg1 = WifiConfiguration.INVALID_NETWORK_ID; + msg.obj = network; + msg.replyTo = mSrcMessenger; + mWifiStateMachine.sendMessage(msg); + } + + /** + * Handles when a Wi-Fi connection attempt failed. + */ + public void handleConnectionFailure() { + // Stub. Should post connection failure notification once implemented. + } + /** Opens Wi-Fi picker. */ private void handleUserClickedContentAction() { mNotificationShown = false; diff --git a/service/java/com/android/server/wifi/WifiConnectivityManager.java b/service/java/com/android/server/wifi/WifiConnectivityManager.java index e417fde2c..1c5ac2821 100644 --- a/service/java/com/android/server/wifi/WifiConnectivityManager.java +++ b/service/java/com/android/server/wifi/WifiConnectivityManager.java @@ -1088,6 +1088,17 @@ public class WifiConnectivityManager { } /** + * Handler when a WiFi connection attempt ended. + * + * @param failureCode {@link WifiMetrics.ConnectionEvent} failure code. + */ + public void handleConnectionAttemptEnded(int failureCode) { + if (failureCode != WifiMetrics.ConnectionEvent.FAILURE_NONE) { + mOpenNetworkNotifier.handleConnectionFailure(); + } + } + + /** * Handler when user toggles whether untrusted connection is allowed */ public void setUntrustedConnectionAllowed(boolean allowed) { diff --git a/service/java/com/android/server/wifi/WifiInjector.java b/service/java/com/android/server/wifi/WifiInjector.java index 734c28d19..7778c2ceb 100644 --- a/service/java/com/android/server/wifi/WifiInjector.java +++ b/service/java/com/android/server/wifi/WifiInjector.java @@ -226,7 +226,8 @@ public class WifiInjector { mCertManager = new WifiCertManager(mContext); mOpenNetworkNotifier = new OpenNetworkNotifier(mContext, mWifiStateMachineHandlerThread.getLooper(), mFrameworkFacade, mClock, - mWifiConfigManager, mWifiConfigStore, new OpenNetworkRecommender()); + mWifiConfigManager, mWifiConfigStore, mWifiStateMachine, + new OpenNetworkRecommender()); mLockManager = new WifiLockManager(mContext, BatteryStatsService.getService()); mWifiController = new WifiController(mContext, mWifiStateMachine, mSettingsStore, mLockManager, mWifiServiceHandlerThread.getLooper(), mFrameworkFacade); diff --git a/service/java/com/android/server/wifi/WifiStateMachine.java b/service/java/com/android/server/wifi/WifiStateMachine.java index 38c767f94..41a599451 100644 --- a/service/java/com/android/server/wifi/WifiStateMachine.java +++ b/service/java/com/android/server/wifi/WifiStateMachine.java @@ -3429,11 +3429,12 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss } /** - * Inform other components (WifiMetrics, WifiDiagnostics, etc.) that the current connection attempt - * has concluded. + * Inform other components (WifiMetrics, WifiDiagnostics, WifiConnectivityManager, etc.) that + * the current connection attempt has concluded. */ private void reportConnectionAttemptEnd(int level2FailureCode, int connectivityFailureCode) { mWifiMetrics.endConnectionEvent(level2FailureCode, connectivityFailureCode); + mWifiConnectivityManager.handleConnectionAttemptEnded(level2FailureCode); switch (level2FailureCode) { case WifiMetrics.ConnectionEvent.FAILURE_NONE: // Ideally, we'd wait until IP reachability has been confirmed. this code falls diff --git a/tests/wifitests/src/com/android/server/wifi/OpenNetworkNotifierTest.java b/tests/wifitests/src/com/android/server/wifi/OpenNetworkNotifierTest.java index 957fc2294..7c1223a79 100644 --- a/tests/wifitests/src/com/android/server/wifi/OpenNetworkNotifierTest.java +++ b/tests/wifitests/src/com/android/server/wifi/OpenNetworkNotifierTest.java @@ -33,6 +33,7 @@ import android.content.Context; import android.content.Intent; import android.content.res.Resources; import android.net.wifi.ScanResult; +import android.os.Message; import android.os.UserHandle; import android.os.UserManager; import android.os.test.TestLooper; @@ -66,6 +67,7 @@ public class OpenNetworkNotifierTest { @Mock private WifiConfigManager mWifiConfigManager; @Mock(answer = Answers.RETURNS_DEEP_STUBS) private Notification.Builder mNotificationBuilder; @Mock private NotificationManager mNotificationManager; + @Mock private WifiStateMachine mWifiStateMachine; @Mock private OpenNetworkRecommender mOpenNetworkRecommender; @Mock private UserManager mUserManager; private OpenNetworkNotifier mNotificationController; @@ -103,7 +105,7 @@ public class OpenNetworkNotifierTest { TestLooper mock_looper = new TestLooper(); mNotificationController = new OpenNetworkNotifier( mContext, mock_looper.getLooper(), mFrameworkFacade, mClock, mWifiConfigManager, - mWifiConfigStore, mOpenNetworkRecommender); + mWifiConfigStore, mWifiStateMachine, mOpenNetworkRecommender); ArgumentCaptor<BroadcastReceiver> broadcastReceiverCaptor = ArgumentCaptor.forClass(BroadcastReceiver.class); verify(mContext).registerReceiver(broadcastReceiverCaptor.capture(), any(), any(), any()); @@ -348,4 +350,32 @@ public class OpenNetworkNotifierTest { verify(mNotificationManager).cancel(anyInt()); } + + /** + * {@link OpenNetworkNotifier#ACTION_CONNECT_TO_NETWORK} does not connect to any network if + * there is no current recommendation. + */ + @Test + public void actionConnectToNetwork_currentRecommendationIsNull_doesNothing() { + mBroadcastReceiver.onReceive(mContext, + new Intent(OpenNetworkNotifier.ACTION_CONNECT_TO_NETWORK)); + + verify(mWifiStateMachine, never()).sendMessage(any(Message.class)); + } + + /** + * {@link OpenNetworkNotifier#ACTION_CONNECT_TO_NETWORK} connects to the currently recommended + * network if it exists. + */ + @Test + public void actionConnectToNetwork_currentRecommendationExists_connectsToNetwork() { + mNotificationController.handleScanResults(mOpenNetworks); + + verify(mOpenNetworkRecommender).recommendNetwork(mOpenNetworks, mBlacklistedSsids); + + mBroadcastReceiver.onReceive(mContext, + new Intent(OpenNetworkNotifier.ACTION_CONNECT_TO_NETWORK)); + + verify(mWifiStateMachine).sendMessage(any(Message.class)); + } } diff --git a/tests/wifitests/src/com/android/server/wifi/WifiConnectivityManagerTest.java b/tests/wifitests/src/com/android/server/wifi/WifiConnectivityManagerTest.java index a8278d365..cb1160cc1 100644 --- a/tests/wifitests/src/com/android/server/wifi/WifiConnectivityManagerTest.java +++ b/tests/wifitests/src/com/android/server/wifi/WifiConnectivityManagerTest.java @@ -614,7 +614,7 @@ public class WifiConnectivityManagerTest { * Expected behavior: ONA handles scan results */ @Test - public void wifiDisconnected_noConnectionCandidate_openNetworkNotificationScanResultsHandled() { + public void wifiDisconnected_noConnectionCandidate_openNetworkNotifierScanResultsHandled() { // no connection candidate selected when(mWifiNS.selectNetwork(anyObject(), anyObject(), anyObject(), anyBoolean(), anyBoolean(), anyBoolean())).thenReturn(null); @@ -643,12 +643,12 @@ public class WifiConnectivityManagerTest { * Expected behavior: ONA clears pending notification and does not reset repeat delay. */ @Test - public void wifiConnected_openNetworkNotificationClearsPendingNotification() { + public void wifiConnected_openNetworkNotifierClearsPendingNotification() { // Set WiFi to connected state mWifiConnectivityManager.handleConnectionStateChanged( WifiConnectivityManager.WIFI_STATE_CONNECTED); - verify(mOpenNetworkNotifier).clearPendingNotification(false /* isRepeatDelayReset*/); + verify(mOpenNetworkNotifier).clearPendingNotification(false /* resetRepeatDelay*/); } /** @@ -658,7 +658,7 @@ public class WifiConnectivityManagerTest { * Expected behavior: ONA does not clear pending notification. */ @Test - public void wifiDisconnected_openNetworkNotificationDoesNotClearPendingNotification() { + public void wifiDisconnected_openNetworkNotifierDoesNotClearPendingNotification() { // Set WiFi to disconnected state mWifiConnectivityManager.handleConnectionStateChanged( WifiConnectivityManager.WIFI_STATE_DISCONNECTED); @@ -667,22 +667,52 @@ public class WifiConnectivityManagerTest { } /** + * When a Wi-Fi connection attempt ends, {@link OpenNetworkNotifier} handles the connection + * failure. A failure code that is not {@link WifiMetrics.ConnectionEvent#FAILURE_NONE} + * represents a connection failure. + * + * Expected behavior: ONA handles connection failure. + */ + @Test + public void wifiConnectionEndsWithFailure_openNetworkNotifierHandlesConnectionFailure() { + mWifiConnectivityManager.handleConnectionAttemptEnded( + WifiMetrics.ConnectionEvent.FAILURE_CONNECT_NETWORK_FAILED); + + verify(mOpenNetworkNotifier).handleConnectionFailure(); + } + + /** + * When a Wi-Fi connection attempt ends, {@link OpenNetworkNotifier} does not handle connection + * failure after a successful connection. {@link WifiMetrics.ConnectionEvent#FAILURE_NONE} + * represents a successful connection. + * + * Expected behavior: ONA does nothing. + */ + @Test + public void wifiConnectionEndsWithSuccess_openNetworkNotifierDoesNotHandleConnectionFailure() { + mWifiConnectivityManager.handleConnectionAttemptEnded( + WifiMetrics.ConnectionEvent.FAILURE_NONE); + + verify(mOpenNetworkNotifier, never()).handleConnectionFailure(); + } + + /** * 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() { + public void openNetworkNotifierClearsPendingNotificationOnWifiDisabled() { mWifiConnectivityManager.setWifiEnabled(false); - verify(mOpenNetworkNotifier).clearPendingNotification(true /* isRepeatDelayReset */); + verify(mOpenNetworkNotifier).clearPendingNotification(true /* resetRepeatDelay */); } /** * Verify that the ONA controller tracks screen state changes. */ @Test - public void openNetworkNotificationControllerTracksScreenStateChanges() { + public void openNetworkNotifierTracksScreenStateChanges() { mWifiConnectivityManager.handleScreenStateChanged(false); verify(mOpenNetworkNotifier).handleScreenStateChanged(false); |