diff options
author | Stephen Chen <stewchen@google.com> | 2017-09-05 11:54:05 -0700 |
---|---|---|
committer | Stephen Chen <stewchen@google.com> | 2017-09-07 15:24:45 -0700 |
commit | 20361dcf2d45262685c8dec334c11f0b2c987702 (patch) | |
tree | fa856ac60353f8ea5a83e176755fb2c5e43ca08a | |
parent | 08ffa580f6756129929667785408da377b363787 (diff) |
ONA: Add connection related notifications.
This change introduces the new notifications but does not utilize them
to change the existing functionality yet. It also refactors the state
handling of the notifier to represent the new connection and
notification states.
When attempting to connect to a network, the notification will update
based on connection success and failures.
Bug: 37357441
Bug: 65257065
Test: frameworks/opt/net/wifi/tests/wifitests/runtests.sh
Change-Id: I3cf188f7f0fac1ea7d1ec882c9473bdbaccccabd
5 files changed, 479 insertions, 154 deletions
diff --git a/service/java/com/android/server/wifi/ConnectToNetworkNotificationBuilder.java b/service/java/com/android/server/wifi/ConnectToNetworkNotificationBuilder.java new file mode 100644 index 000000000..c0960d405 --- /dev/null +++ b/service/java/com/android/server/wifi/ConnectToNetworkNotificationBuilder.java @@ -0,0 +1,143 @@ +/* + * 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.app.Notification; +import android.app.PendingIntent; +import android.content.Context; +import android.content.Intent; +import android.content.res.Resources; +import android.net.wifi.ScanResult; + +import com.android.internal.R; +import com.android.internal.notification.SystemNotificationChannels; + +/** + * Helper to create notifications for {@link OpenNetworkNotifier}. + */ +public class ConnectToNetworkNotificationBuilder { + + /** Intent when user dismissed the "Connect to Network" notification. */ + public static final String ACTION_USER_DISMISSED_NOTIFICATION = + "com.android.server.wifi.ConnectToNetworkNotification.USER_DISMISSED_NOTIFICATION"; + + /** Intent when user tapped the "Connect to Network" notification. */ + public static final String ACTION_USER_TAPPED_CONTENT = + "com.android.server.wifi.ConnectToNetworkNotification.USER_TAPPED_CONTENT"; + + /** Intent when user tapped action button to connect to recommended network. */ + public static final String ACTION_CONNECT_TO_NETWORK = + "com.android.server.wifi.ConnectToNetworkNotification.CONNECT_TO_NETWORK"; + + /** Intent when user tapped action button to open Wi-Fi Settings. */ + public static final String ACTION_PICK_WIFI_NETWORK = + "com.android.server.wifi.ConnectToNetworkNotification.PICK_WIFI_NETWORK"; + + /** Intent when user tapped "Failed to connect" notification to open Wi-Fi Settings. */ + public static final String ACTION_PICK_WIFI_NETWORK_AFTER_CONNECT_FAILURE = + "com.android.server.wifi.ConnectToNetworkNotification.PICK_NETWORK_AFTER_FAILURE"; + + private Context mContext; + private Resources mResources; + private FrameworkFacade mFrameworkFacade; + + public ConnectToNetworkNotificationBuilder( + Context context, + FrameworkFacade framework) { + mContext = context; + mResources = context.getResources(); + mFrameworkFacade = framework; + } + + /** + * Creates the connect to network notification that alerts users of a recommended connectable + * network. + * + * @param numNetworks Number of available open networks nearby + */ + public Notification createConnectToNetworkNotification(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); + + return createNotificationBuilder(title, content) + .setContentIntent(getPrivateBroadcast(ACTION_USER_TAPPED_CONTENT)) + .build(); + } + + /** + * Creates the notification that indicates the controller is attempting to connect to the + * recommended network. + * + * @param network The network to be recommended + */ + public Notification createNetworkConnectingNotification(ScanResult network) { + return createNotificationBuilder( + mContext.getText(R.string.wifi_available_title_connecting), network.SSID) + .setProgress(0 /* max */, 0 /* progress */, true /* indeterminate */) + .build(); + } + + /** + * Creates the notification that indicates the controller successfully connected to the + * recommended network. + * + * @param network The network to be recommended + */ + public Notification createNetworkConnectedNotification(ScanResult network) { + return createNotificationBuilder( + mContext.getText(R.string.wifi_available_title_connected), network.SSID) + .build(); + } + + /** + * Creates the notification that indicates the controller failed to connect to the recommended + * network. Tapping this notification opens the wifi picker. + */ + public Notification createNetworkFailedNotification() { + return createNotificationBuilder( + mContext.getText(R.string.wifi_available_title_failed_to_connect), + mContext.getText(R.string.wifi_available_content_failed_to_connect)) + .setContentIntent( + getPrivateBroadcast(ACTION_PICK_WIFI_NETWORK_AFTER_CONNECT_FAILURE)) + .build(); + } + + private Notification.Builder createNotificationBuilder( + CharSequence title, CharSequence content) { + return mFrameworkFacade.makeNotificationBuilder(mContext, + SystemNotificationChannels.NETWORK_AVAILABLE) + .setSmallIcon(R.drawable.stat_notify_wifi_in_range) + .setAutoCancel(true) + .setTicker(title) + .setContentTitle(title) + .setContentText(content) + .setDeleteIntent(getPrivateBroadcast(ACTION_USER_DISMISSED_NOTIFICATION)) + .setShowWhen(false) + .setLocalOnly(true) + .setColor(mResources.getColor(R.color.system_notification_accent_color, + mContext.getTheme())); + } + + private PendingIntent getPrivateBroadcast(String action) { + Intent intent = new Intent(action).setPackage("android"); + return mFrameworkFacade.getBroadcast( + mContext, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT); + } +} diff --git a/service/java/com/android/server/wifi/OpenNetworkNotificationBuilder.java b/service/java/com/android/server/wifi/OpenNetworkNotificationBuilder.java deleted file mode 100644 index 5963b57a3..000000000 --- a/service/java/com/android/server/wifi/OpenNetworkNotificationBuilder.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * 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 index 279223759..d2d45c37c 100644 --- a/service/java/com/android/server/wifi/OpenNetworkNotifier.java +++ b/service/java/com/android/server/wifi/OpenNetworkNotifier.java @@ -16,7 +16,15 @@ package com.android.server.wifi; +import static com.android.server.wifi.ConnectToNetworkNotificationBuilder.ACTION_CONNECT_TO_NETWORK; +import static com.android.server.wifi.ConnectToNetworkNotificationBuilder.ACTION_PICK_WIFI_NETWORK; +import static com.android.server.wifi.ConnectToNetworkNotificationBuilder.ACTION_PICK_WIFI_NETWORK_AFTER_CONNECT_FAILURE; +import static com.android.server.wifi.ConnectToNetworkNotificationBuilder.ACTION_USER_DISMISSED_NOTIFICATION; +import static com.android.server.wifi.ConnectToNetworkNotificationBuilder.ACTION_USER_TAPPED_CONTENT; + +import android.annotation.IntDef; import android.annotation.NonNull; +import android.app.Notification; import android.app.NotificationManager; import android.content.BroadcastReceiver; import android.content.Context; @@ -42,6 +50,8 @@ import com.android.server.wifi.util.ScanResultUtil; import java.io.FileDescriptor; import java.io.PrintWriter; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.util.List; import java.util.Set; @@ -55,12 +65,39 @@ public class OpenNetworkNotifier { private static final String TAG = "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"; - static final String ACTION_CONNECT_TO_NETWORK = - "com.android.server.wifi.OpenNetworkNotifier.CONNECT_TO_NETWORK"; + /** Time in milliseconds to display the Connecting notification. */ + private static final int TIME_TO_SHOW_CONNECTING_MILLIS = 10000; + + /** Time in milliseconds to display the Connected notification. */ + private static final int TIME_TO_SHOW_CONNECTED_MILLIS = 5000; + + /** Time in milliseconds to display the Failed To Connect notification. */ + private static final int TIME_TO_SHOW_FAILED_MILLIS = 5000; + + /** The state of the notification */ + @IntDef({ + STATE_NO_NOTIFICATION, + STATE_SHOWING_RECOMMENDATION_NOTIFICATION, + STATE_CONNECTING_IN_NOTIFICATION, + STATE_CONNECTED_NOTIFICATION, + STATE_CONNECT_FAILED_NOTIFICATION + }) + @Retention(RetentionPolicy.SOURCE) + private @interface State {} + + /** No recommendation is made and no notifications are shown. */ + private static final int STATE_NO_NOTIFICATION = 0; + /** The initial notification recommending an open network to connect to is shown. */ + private static final int STATE_SHOWING_RECOMMENDATION_NOTIFICATION = 1; + /** The notification of status of connecting to the recommended network is shown. */ + private static final int STATE_CONNECTING_IN_NOTIFICATION = 2; + /** The notification that the connection to the recommended network was successful is shown. */ + private static final int STATE_CONNECTED_NOTIFICATION = 3; + /** The notification to show that connection to the recommended network failed is shown. */ + private static final int STATE_CONNECT_FAILED_NOTIFICATION = 4; + + /** Current state of the notification. */ + @State private int mState = STATE_NO_NOTIFICATION; /** Identifier of the {@link SsidSetStoreData}. */ private static final String STORE_DATA_IDENTIFIER = "OpenNetworkNotifierBlacklist"; @@ -79,8 +116,6 @@ public class OpenNetworkNotifier { /** 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; @@ -95,7 +130,7 @@ public class OpenNetworkNotifier { private final WifiStateMachine mWifiStateMachine; private final Messenger mSrcMessenger; private final OpenNetworkRecommender mOpenNetworkRecommender; - private final OpenNetworkNotificationBuilder mOpenNetworkNotificationBuilder; + private final ConnectToNetworkNotificationBuilder mNotificationBuilder; private ScanResult mRecommendedNetwork; @@ -107,7 +142,8 @@ public class OpenNetworkNotifier { WifiConfigManager wifiConfigManager, WifiConfigStore wifiConfigStore, WifiStateMachine wifiStateMachine, - OpenNetworkRecommender openNetworkRecommender) { + OpenNetworkRecommender openNetworkRecommender, + ConnectToNetworkNotificationBuilder connectToNetworkNotificationBuilder) { mContext = context; mHandler = new Handler(looper); mFrameworkFacade = framework; @@ -115,7 +151,7 @@ public class OpenNetworkNotifier { mConfigManager = wifiConfigManager; mWifiStateMachine = wifiStateMachine; mOpenNetworkRecommender = openNetworkRecommender; - mOpenNetworkNotificationBuilder = new OpenNetworkNotificationBuilder(context, framework); + mNotificationBuilder = connectToNetworkNotificationBuilder; mScreenOn = false; mSrcMessenger = new Messenger(new Handler(looper, mConnectionStateCallback)); @@ -135,6 +171,8 @@ public class OpenNetworkNotifier { filter.addAction(ACTION_USER_DISMISSED_NOTIFICATION); filter.addAction(ACTION_USER_TAPPED_CONTENT); filter.addAction(ACTION_CONNECT_TO_NETWORK); + filter.addAction(ACTION_PICK_WIFI_NETWORK); + filter.addAction(ACTION_PICK_WIFI_NETWORK_AFTER_CONNECT_FAILURE); mContext.registerReceiver( mBroadcastReceiver, filter, null /* broadcastPermission */, mHandler); } @@ -153,6 +191,12 @@ public class OpenNetworkNotifier { case ACTION_CONNECT_TO_NETWORK: handleConnectToNetworkAction(); break; + case ACTION_PICK_WIFI_NETWORK: + handleSeeAllNetworksAction(); + break; + case ACTION_PICK_WIFI_NETWORK_AFTER_CONNECT_FAILURE: + handlePickWifiNetworkAfterConnectFailure(); + break; default: Log.e(TAG, "Unknown action " + intent.getAction()); } @@ -178,17 +222,17 @@ public class OpenNetworkNotifier { /** * Clears the pending notification. This is called by {@link WifiConnectivityManager} on stop. * - * @param resetRepeatDelay resets the time delay for repeated notification if true. + * @param resetRepeatTime resets the time delay for repeated notification if true. */ - public void clearPendingNotification(boolean resetRepeatDelay) { - if (resetRepeatDelay) { + public void clearPendingNotification(boolean resetRepeatTime) { + if (resetRepeatTime) { mNotificationRepeatTime = 0; } - if (mNotificationShown) { + if (mState != STATE_NO_NOTIFICATION) { getNotificationManager().cancel(SystemMessage.NOTE_NETWORK_AVAILABLE); + mState = STATE_NO_NOTIFICATION; mRecommendedNetwork = null; - mNotificationShown = false; } } @@ -205,11 +249,11 @@ public class OpenNetworkNotifier { */ public void handleScanResults(@NonNull List<ScanDetail> availableNetworks) { if (!isControllerEnabled()) { - clearPendingNotification(true /* resetRepeatDelay */); + clearPendingNotification(true /* resetRepeatTime */); return; } if (availableNetworks.isEmpty()) { - clearPendingNotification(false /* resetRepeatDelay */); + clearPendingNotification(false /* resetRepeatTime */); return; } @@ -217,14 +261,14 @@ public class OpenNetworkNotifier { // 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) { + if (mState != STATE_NO_NOTIFICATION || !mScreenOn) { return; } mRecommendedNetwork = mOpenNetworkRecommender.recommendNetwork( availableNetworks, new ArraySet<>(mBlacklistedSsids)); - postNotification(availableNetworks.size()); + postInitialNotification(availableNetworks.size()); } /** Handles screen state changes. */ @@ -232,28 +276,78 @@ public class OpenNetworkNotifier { mScreenOn = screenOn; } + /** + * Called by {@link WifiConnectivityManager} when Wi-Fi is connected. If the notification + * was in the connecting state, update the notification to show that it has connected to the + * recommended network. + */ + public void handleWifiConnected() { + if (mState != STATE_CONNECTING_IN_NOTIFICATION) { + clearPendingNotification(true /* resetRepeatTime */); + return; + } + + postNotification(mNotificationBuilder.createNetworkConnectedNotification( + mRecommendedNetwork)); + mState = STATE_CONNECTED_NOTIFICATION; + mHandler.postDelayed( + () -> { + if (mState == STATE_CONNECTED_NOTIFICATION) { + clearPendingNotification(true /* resetRepeatTime */); + } + }, + TIME_TO_SHOW_CONNECTED_MILLIS); + } + + /** + * Handles when a Wi-Fi connection attempt failed. + */ + public void handleConnectionFailure() { + if (mState != STATE_CONNECTING_IN_NOTIFICATION) { + return; + } + postNotification(mNotificationBuilder.createNetworkFailedNotification()); + mState = STATE_CONNECT_FAILED_NOTIFICATION; + mHandler.postDelayed( + () -> { + if (mState == STATE_CONNECT_FAILED_NOTIFICATION) { + clearPendingNotification(false /* resetRepeatTime */); + } + }, + TIME_TO_SHOW_FAILED_MILLIS); + } + private NotificationManager getNotificationManager() { return (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE); } - private void postNotification(int numNetworks) { + private void postInitialNotification(int numNetworks) { + if (mState != STATE_NO_NOTIFICATION + && mState != STATE_SHOWING_RECOMMENDATION_NOTIFICATION) { + return; + } // 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; + postNotification(mNotificationBuilder.createConnectToNetworkNotification( + numNetworks)); + mState = STATE_SHOWING_RECOMMENDATION_NOTIFICATION; mNotificationRepeatTime = mClock.getWallClockMillis() + mNotificationRepeatDelay; } + private void postNotification(Notification notification) { + getNotificationManager().notify(SystemMessage.NOTE_NETWORK_AVAILABLE, notification); + } + private void handleConnectToNetworkAction() { - if (mRecommendedNetwork == null) { + if (mState != STATE_SHOWING_RECOMMENDATION_NOTIFICATION) { return; } + postNotification(mNotificationBuilder.createNetworkConnectingNotification( + mRecommendedNetwork)); + Log.d(TAG, "User initiated connection to recommended network: " + mRecommendedNetwork.SSID); WifiConfiguration network = ScanResultUtil.createNetworkFromScanResult(mRecommendedNetwork); Message msg = Message.obtain(); @@ -262,32 +356,52 @@ public class OpenNetworkNotifier { msg.obj = network; msg.replyTo = mSrcMessenger; mWifiStateMachine.sendMessage(msg); + + mState = STATE_CONNECTING_IN_NOTIFICATION; + mHandler.postDelayed( + () -> { + if (mState == STATE_CONNECTING_IN_NOTIFICATION) { + handleConnectionFailure(); + } + }, + TIME_TO_SHOW_CONNECTING_MILLIS); } - /** - * Handles when a Wi-Fi connection attempt failed. - */ - public void handleConnectionFailure() { - // Stub. Should post connection failure notification once implemented. + private void handleSeeAllNetworksAction() { + startWifiSettings(); } - /** Opens Wi-Fi picker. */ - private void handleUserClickedContentAction() { - mNotificationShown = false; + private void startWifiSettings() { mContext.startActivity( new Intent(Settings.ACTION_WIFI_SETTINGS) .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)); + clearPendingNotification(false /* resetRepeatTime */); + } + + private void handlePickWifiNetworkAfterConnectFailure() { + startWifiSettings(); + } + + private void handleUserClickedContentAction() { + startWifiSettings(); + resetStateAndDelayNotification(); } private void handleUserDismissedAction() { - if (mRecommendedNetwork != null) { + if (mState == STATE_SHOWING_RECOMMENDATION_NOTIFICATION) { // blacklist dismissed network mBlacklistedSsids.add(mRecommendedNetwork.SSID); mConfigManager.saveToStore(false /* forceWrite */); Log.d(TAG, "Network is added to the open network notification blacklist: " + mRecommendedNetwork.SSID); } - mNotificationShown = false; + resetStateAndDelayNotification(); + } + + private void resetStateAndDelayNotification() { + mState = STATE_NO_NOTIFICATION; + mNotificationRepeatTime = System.currentTimeMillis() + mNotificationRepeatDelay; + mRecommendedNetwork = null; } /** Dump ONA controller state. */ @@ -296,7 +410,7 @@ public class OpenNetworkNotifier { pw.println("mSettingEnabled " + mSettingEnabled); pw.println("currentTime: " + mClock.getWallClockMillis()); pw.println("mNotificationRepeatTime: " + mNotificationRepeatTime); - pw.println("mNotificationShown: " + mNotificationShown); + pw.println("mState: " + mState); pw.println("mBlacklistedSsids: " + mBlacklistedSsids.toString()); } @@ -327,7 +441,7 @@ public class OpenNetworkNotifier { public void onChange(boolean selfChange) { super.onChange(selfChange); mSettingEnabled = getValue(); - clearPendingNotification(true /* resetRepeatDelay */); + clearPendingNotification(true /* resetRepeatTime */); } private boolean getValue() { diff --git a/service/java/com/android/server/wifi/WifiInjector.java b/service/java/com/android/server/wifi/WifiInjector.java index a0d0e82d5..95a68f1b4 100644 --- a/service/java/com/android/server/wifi/WifiInjector.java +++ b/service/java/com/android/server/wifi/WifiInjector.java @@ -234,7 +234,8 @@ public class WifiInjector { mOpenNetworkNotifier = new OpenNetworkNotifier(mContext, mWifiStateMachineHandlerThread.getLooper(), mFrameworkFacade, mClock, mWifiConfigManager, mWifiConfigStore, mWifiStateMachine, - new OpenNetworkRecommender()); + new OpenNetworkRecommender(), + new ConnectToNetworkNotificationBuilder(mContext, mFrameworkFacade)); mLockManager = new WifiLockManager(mContext, BatteryStatsService.getService()); mWifiController = new WifiController(mContext, mWifiStateMachine, mSettingsStore, mLockManager, mWifiServiceHandlerThread.getLooper(), mFrameworkFacade); diff --git a/tests/wifitests/src/com/android/server/wifi/OpenNetworkNotifierTest.java b/tests/wifitests/src/com/android/server/wifi/OpenNetworkNotifierTest.java index 7c1223a79..3af19e163 100644 --- a/tests/wifitests/src/com/android/server/wifi/OpenNetworkNotifierTest.java +++ b/tests/wifitests/src/com/android/server/wifi/OpenNetworkNotifierTest.java @@ -18,22 +18,23 @@ package com.android.server.wifi; import static com.android.server.wifi.OpenNetworkNotifier.DEFAULT_REPEAT_DELAY_SEC; +import static org.junit.Assert.assertEquals; 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.net.wifi.WifiManager; import android.os.Message; +import android.os.RemoteException; import android.os.UserHandle; import android.os.UserManager; import android.os.test.TestLooper; @@ -42,7 +43,6 @@ import android.util.ArraySet; import org.junit.Before; import org.junit.Test; -import org.mockito.Answers; import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; @@ -65,12 +65,13 @@ public class OpenNetworkNotifierTest { @Mock private Clock mClock; @Mock private WifiConfigStore mWifiConfigStore; @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 ConnectToNetworkNotificationBuilder mNotificationBuilder; @Mock private UserManager mUserManager; private OpenNetworkNotifier mNotificationController; + private TestLooper mLooper; private BroadcastReceiver mBroadcastReceiver; private ScanResult mDummyNetwork; private List<ScanDetail> mOpenNetworks; @@ -88,8 +89,6 @@ public class OpenNetworkNotifierTest { 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); @@ -102,10 +101,10 @@ public class OpenNetworkNotifierTest { mOpenNetworks.add(new ScanDetail(mDummyNetwork, null /* networkDetail */)); mBlacklistedSsids = new ArraySet<>(); - TestLooper mock_looper = new TestLooper(); + mLooper = new TestLooper(); mNotificationController = new OpenNetworkNotifier( - mContext, mock_looper.getLooper(), mFrameworkFacade, mClock, mWifiConfigManager, - mWifiConfigStore, mWifiStateMachine, mOpenNetworkRecommender); + mContext, mLooper.getLooper(), mFrameworkFacade, mClock, mWifiConfigManager, + mWifiConfigStore, mWifiStateMachine, mOpenNetworkRecommender, mNotificationBuilder); ArgumentCaptor<BroadcastReceiver> broadcastReceiverCaptor = ArgumentCaptor.forClass(BroadcastReceiver.class); verify(mContext).registerReceiver(broadcastReceiverCaptor.capture(), any(), any(), any()); @@ -121,6 +120,7 @@ public class OpenNetworkNotifierTest { mNotificationController.handleScanResults(mOpenNetworks); verify(mOpenNetworkRecommender).recommendNetwork(mOpenNetworks, mBlacklistedSsids); + verify(mNotificationBuilder).createConnectToNetworkNotification(1); verify(mNotificationManager).notify(anyInt(), any()); } @@ -144,6 +144,7 @@ public class OpenNetworkNotifierTest { mNotificationController.handleScanResults(mOpenNetworks); verify(mOpenNetworkRecommender).recommendNetwork(mOpenNetworks, mBlacklistedSsids); + verify(mNotificationBuilder).createConnectToNetworkNotification(1); verify(mNotificationManager).notify(anyInt(), any()); mNotificationController.handleScanResults(new ArrayList<>()); @@ -159,6 +160,7 @@ public class OpenNetworkNotifierTest { mNotificationController.handleScanResults(mOpenNetworks); verify(mOpenNetworkRecommender).recommendNetwork(mOpenNetworks, mBlacklistedSsids); + verify(mNotificationBuilder).createConnectToNetworkNotification(1); verify(mNotificationManager).notify(anyInt(), any()); mNotificationController.handleScreenStateChanged(false); @@ -176,6 +178,7 @@ public class OpenNetworkNotifierTest { mNotificationController.handleScanResults(mOpenNetworks); verify(mOpenNetworkRecommender).recommendNetwork(mOpenNetworks, mBlacklistedSsids); + verify(mNotificationBuilder).createConnectToNetworkNotification(1); verify(mNotificationManager).notify(anyInt(), any()); } @@ -188,6 +191,7 @@ public class OpenNetworkNotifierTest { mNotificationController.handleScanResults(mOpenNetworks); verify(mOpenNetworkRecommender).recommendNetwork(mOpenNetworks, mBlacklistedSsids); + verify(mNotificationBuilder).createConnectToNetworkNotification(1); verify(mNotificationManager).notify(anyInt(), any()); mNotificationController.clearPendingNotification(true); @@ -220,7 +224,7 @@ public class OpenNetworkNotifierTest { } /** - * When a notification is posted and cleared without reseting delay, the next scan with open + * When a notification is posted and cleared without resetting delay, the next scan with open * networks should not post another notification. */ @Test @@ -228,6 +232,7 @@ public class OpenNetworkNotifierTest { mNotificationController.handleScanResults(mOpenNetworks); verify(mOpenNetworkRecommender).recommendNetwork(mOpenNetworks, mBlacklistedSsids); + verify(mNotificationBuilder).createConnectToNetworkNotification(1); verify(mNotificationManager).notify(anyInt(), any()); mNotificationController.clearPendingNotification(false); @@ -238,11 +243,12 @@ public class OpenNetworkNotifierTest { verify(mOpenNetworkRecommender, times(2)).recommendNetwork( mOpenNetworks, mBlacklistedSsids); verify(mNotificationManager).notify(anyInt(), any()); + verify(mNotificationBuilder).createConnectToNetworkNotification(1); verify(mNotificationManager).cancel(anyInt()); } /** - * When a notification is posted and cleared without reseting delay, the next scan with open + * When a notification is posted and cleared without resetting delay, the next scan with open * networks should post a notification. */ @Test @@ -250,6 +256,7 @@ public class OpenNetworkNotifierTest { mNotificationController.handleScanResults(mOpenNetworks); verify(mOpenNetworkRecommender).recommendNetwork(mOpenNetworks, mBlacklistedSsids); + verify(mNotificationBuilder).createConnectToNetworkNotification(1); verify(mNotificationManager).notify(anyInt(), any()); mNotificationController.clearPendingNotification(true); @@ -258,6 +265,7 @@ public class OpenNetworkNotifierTest { verify(mOpenNetworkRecommender, times(2)).recommendNetwork( mOpenNetworks, mBlacklistedSsids); + verify(mNotificationBuilder, times(2)).createConnectToNetworkNotification(1); verify(mNotificationManager, times(2)).notify(anyInt(), any()); } @@ -269,12 +277,16 @@ public class OpenNetworkNotifierTest { mNotificationController.handleScanResults(mOpenNetworks); verify(mOpenNetworkRecommender).recommendNetwork(mOpenNetworks, mBlacklistedSsids); + verify(mNotificationBuilder).createConnectToNetworkNotification(1); verify(mNotificationManager).notify(anyInt(), any()); mBroadcastReceiver.onReceive( - mContext, new Intent(OpenNetworkNotifier.ACTION_USER_TAPPED_CONTENT)); + mContext, + new Intent(ConnectToNetworkNotificationBuilder.ACTION_USER_TAPPED_CONTENT)); - verify(mContext).startActivity(any()); + ArgumentCaptor<Intent> pickerIntentCaptor = ArgumentCaptor.forClass(Intent.class); + verify(mContext).startActivity(pickerIntentCaptor.capture()); + assertEquals(pickerIntentCaptor.getValue().getAction(), Settings.ACTION_WIFI_SETTINGS); } /** @@ -286,10 +298,12 @@ public class OpenNetworkNotifierTest { mNotificationController.handleScanResults(mOpenNetworks); verify(mOpenNetworkRecommender).recommendNetwork(mOpenNetworks, mBlacklistedSsids); + verify(mNotificationBuilder).createConnectToNetworkNotification(1); verify(mNotificationManager).notify(anyInt(), any()); mBroadcastReceiver.onReceive( - mContext, new Intent(OpenNetworkNotifier.ACTION_USER_DISMISSED_NOTIFICATION)); + mContext, + new Intent(ConnectToNetworkNotificationBuilder.ACTION_USER_DISMISSED_NOTIFICATION)); verify(mWifiConfigManager).saveToStore(false /* forceWrite */); @@ -301,7 +315,7 @@ public class OpenNetworkNotifierTest { } /** - * When a notification is posted and cleared without reseting delay, after the delay has passed + * When a notification is posted and cleared without resetting delay, after the delay has passed * the next scan with open networks should post a notification. */ @Test @@ -309,6 +323,7 @@ public class OpenNetworkNotifierTest { mNotificationController.handleScanResults(mOpenNetworks); verify(mOpenNetworkRecommender).recommendNetwork(mOpenNetworks, mBlacklistedSsids); + verify(mNotificationBuilder).createConnectToNetworkNotification(1); verify(mNotificationManager).notify(anyInt(), any()); mNotificationController.clearPendingNotification(false); @@ -341,6 +356,7 @@ public class OpenNetworkNotifierTest { mNotificationController.handleScanResults(mOpenNetworks); verify(mOpenNetworkRecommender).recommendNetwork(mOpenNetworks, mBlacklistedSsids); + verify(mNotificationBuilder).createConnectToNetworkNotification(1); verify(mNotificationManager).notify(anyInt(), any()); when(mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_WIFI, UserHandle.CURRENT)) @@ -352,30 +368,172 @@ public class OpenNetworkNotifierTest { } /** - * {@link OpenNetworkNotifier#ACTION_CONNECT_TO_NETWORK} does not connect to any network if - * there is no current recommendation. + * {@link ConnectToNetworkNotificationBuilder#ACTION_CONNECT_TO_NETWORK} does not connect to + * any network if the initial notification is not showing. */ @Test - public void actionConnectToNetwork_currentRecommendationIsNull_doesNothing() { + public void actionConnectToNetwork_notificationNotShowing_doesNothing() { mBroadcastReceiver.onReceive(mContext, - new Intent(OpenNetworkNotifier.ACTION_CONNECT_TO_NETWORK)); + new Intent(ConnectToNetworkNotificationBuilder.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. + * {@link ConnectToNetworkNotificationBuilder#ACTION_CONNECT_TO_NETWORK} connects to the + * currently recommended network if it exists. */ @Test - public void actionConnectToNetwork_currentRecommendationExists_connectsToNetwork() { + public void actionConnectToNetwork_currentRecommendationExists_connectsAndPostsNotification() { mNotificationController.handleScanResults(mOpenNetworks); verify(mOpenNetworkRecommender).recommendNetwork(mOpenNetworks, mBlacklistedSsids); + // Initial Notification + verify(mNotificationBuilder).createConnectToNetworkNotification(1); + verify(mNotificationManager).notify(anyInt(), any()); mBroadcastReceiver.onReceive(mContext, - new Intent(OpenNetworkNotifier.ACTION_CONNECT_TO_NETWORK)); + new Intent(ConnectToNetworkNotificationBuilder.ACTION_CONNECT_TO_NETWORK)); verify(mWifiStateMachine).sendMessage(any(Message.class)); + // Connecting Notification + verify(mNotificationBuilder).createNetworkConnectingNotification(mDummyNetwork); + verify(mNotificationManager, times(2)).notify(anyInt(), any()); + } + + /** + * {@link OpenNetworkNotifier#handleWifiConnected()} does not post connected notification if + * the connecting notification is not showing + */ + @Test + public void networkConnectionSuccess_wasNotInConnectingFlow_doesNothing() { + mNotificationController.handleWifiConnected(); + + verify(mNotificationManager, never()).notify(anyInt(), any()); + } + + /** + * {@link OpenNetworkNotifier#handleWifiConnected()} clears notification that is not connecting. + */ + @Test + public void networkConnectionSuccess_wasShowingNotification_clearsNotification() { + mNotificationController.handleScanResults(mOpenNetworks); + + verify(mOpenNetworkRecommender).recommendNetwork(mOpenNetworks, mBlacklistedSsids); + // Initial Notification + verify(mNotificationBuilder).createConnectToNetworkNotification(1); + verify(mNotificationManager).notify(anyInt(), any()); + + mNotificationController.handleWifiConnected(); + + verify(mNotificationManager).cancel(anyInt()); + } + + /** + * {@link OpenNetworkNotifier#handleWifiConnected()} posts the connected notification if + * the connecting notification is showing. + */ + @Test + public void networkConnectionSuccess_wasInConnectingFlow_postsConnectedNotification() { + mNotificationController.handleScanResults(mOpenNetworks); + + verify(mOpenNetworkRecommender).recommendNetwork(mOpenNetworks, mBlacklistedSsids); + // Initial Notification + verify(mNotificationBuilder).createConnectToNetworkNotification(1); + verify(mNotificationManager).notify(anyInt(), any()); + + mBroadcastReceiver.onReceive(mContext, + new Intent(ConnectToNetworkNotificationBuilder.ACTION_CONNECT_TO_NETWORK)); + + // Connecting Notification + verify(mNotificationBuilder).createNetworkConnectingNotification(mDummyNetwork); + verify(mNotificationManager, times(2)).notify(anyInt(), any()); + + mNotificationController.handleWifiConnected(); + + // Connected Notification + verify(mNotificationBuilder).createNetworkConnectedNotification(mDummyNetwork); + verify(mNotificationManager, times(3)).notify(anyInt(), any()); + } + + /** + * {@link OpenNetworkNotifier#handleConnectionFailure()} posts the Failed to Connect + * notification if the connecting notification is showing. + */ + @Test + public void networkConnectionFailure_wasNotInConnectingFlow_doesNothing() { + mNotificationController.handleConnectionFailure(); + + verify(mNotificationManager, never()).notify(anyInt(), any()); + } + + /** + * {@link OpenNetworkNotifier#handleConnectionFailure()} posts the Failed to Connect + * notification if the connecting notification is showing. + */ + @Test + public void networkConnectionFailure_wasInConnectingFlow_postsFailedToConnectNotification() { + mNotificationController.handleScanResults(mOpenNetworks); + + verify(mOpenNetworkRecommender).recommendNetwork(mOpenNetworks, mBlacklistedSsids); + // Initial Notification + verify(mNotificationBuilder).createConnectToNetworkNotification(1); + verify(mNotificationManager).notify(anyInt(), any()); + + mBroadcastReceiver.onReceive(mContext, + new Intent(ConnectToNetworkNotificationBuilder.ACTION_CONNECT_TO_NETWORK)); + + // Connecting Notification + verify(mNotificationBuilder).createNetworkConnectingNotification(mDummyNetwork); + verify(mNotificationManager, times(2)).notify(anyInt(), any()); + + mNotificationController.handleConnectionFailure(); + + // Failed to Connect Notification + verify(mNotificationBuilder).createNetworkFailedNotification(); + verify(mNotificationManager, times(3)).notify(anyInt(), any()); + } + + /** + * When a {@link WifiManager#CONNECT_NETWORK_FAILED} is received from the connection callback + * of {@link WifiStateMachine#sendMessage(Message)}, a Failed to Connect notification should + * be posted. On tapping this notification, Wi-Fi Settings should be launched. + */ + @Test + public void connectionFailedCallback_postsFailedToConnectNotification() throws RemoteException { + mNotificationController.handleScanResults(mOpenNetworks); + + verify(mOpenNetworkRecommender).recommendNetwork(mOpenNetworks, mBlacklistedSsids); + // Initial Notification + verify(mNotificationBuilder).createConnectToNetworkNotification(1); + verify(mNotificationManager).notify(anyInt(), any()); + + mBroadcastReceiver.onReceive(mContext, + new Intent(ConnectToNetworkNotificationBuilder.ACTION_CONNECT_TO_NETWORK)); + + ArgumentCaptor<Message> connectMessageCaptor = ArgumentCaptor.forClass(Message.class); + verify(mWifiStateMachine).sendMessage(connectMessageCaptor.capture()); + Message connectMessage = connectMessageCaptor.getValue(); + + // Connecting Notification + verify(mNotificationBuilder).createNetworkConnectingNotification(mDummyNetwork); + verify(mNotificationManager, times(2)).notify(anyInt(), any()); + + Message connectFailedMsg = Message.obtain(); + connectFailedMsg.what = WifiManager.CONNECT_NETWORK_FAILED; + connectMessage.replyTo.send(connectFailedMsg); + mLooper.dispatchAll(); + + // Failed to Connect Notification + verify(mNotificationBuilder).createNetworkFailedNotification(); + verify(mNotificationManager, times(3)).notify(anyInt(), any()); + + mBroadcastReceiver.onReceive(mContext, + new Intent(ConnectToNetworkNotificationBuilder + .ACTION_PICK_WIFI_NETWORK_AFTER_CONNECT_FAILURE)); + + ArgumentCaptor<Intent> pickerIntentCaptor = ArgumentCaptor.forClass(Intent.class); + verify(mContext).startActivity(pickerIntentCaptor.capture()); + assertEquals(pickerIntentCaptor.getValue().getAction(), Settings.ACTION_WIFI_SETTINGS); } } |