1 /*
2  * Copyright (C) 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.server.wifi;
18 
19 import static com.android.server.wifi.WakeupNotificationFactory.ACTION_DISMISS_NOTIFICATION;
20 import static com.android.server.wifi.WakeupNotificationFactory.ACTION_OPEN_WIFI_PREFERENCES;
21 import static com.android.server.wifi.WakeupNotificationFactory.ACTION_TURN_OFF_WIFI_WAKE;
22 
23 import static org.junit.Assert.assertFalse;
24 import static org.junit.Assert.assertTrue;
25 import static org.mockito.ArgumentMatchers.any;
26 import static org.mockito.ArgumentMatchers.eq;
27 import static org.mockito.Mockito.never;
28 import static org.mockito.Mockito.times;
29 import static org.mockito.Mockito.verify;
30 
31 import android.content.BroadcastReceiver;
32 import android.content.Intent;
33 import android.content.IntentFilter;
34 import android.net.wifi.WifiContext;
35 import android.os.Handler;
36 import android.os.test.TestLooper;
37 import android.provider.Settings;
38 
39 import androidx.test.filters.SmallTest;
40 
41 import org.junit.Before;
42 import org.junit.Test;
43 import org.mockito.ArgumentCaptor;
44 import org.mockito.InOrder;
45 import org.mockito.Mock;
46 import org.mockito.Mockito;
47 import org.mockito.MockitoAnnotations;
48 
49 /** Unit tests for {@link com.android.server.wifi.WakeupOnboarding} */
50 @SmallTest
51 public class WakeupOnboardingTest extends WifiBaseTest {
52     @Mock private WifiContext mContext;
53     @Mock private WifiConfigManager mWifiConfigManager;
54     @Mock private FrameworkFacade mFrameworkFacade;
55     @Mock private WakeupNotificationFactory mWakeupNotificationFactory;
56     @Mock private WifiNotificationManager mWifiNotificationManager;
57 
58     private TestLooper mLooper;
59     private WakeupOnboarding mWakeupOnboarding;
60 
61     // convenience method for resetting onboarded status
setOnboardedStatus(boolean isOnboarded)62     private void setOnboardedStatus(boolean isOnboarded) {
63         mWakeupOnboarding.getIsOnboadedDataSource().setData(isOnboarded);
64     }
65 
setNotificationsShown(int numNotifications)66     private void setNotificationsShown(int numNotifications) {
67         mWakeupOnboarding.getNotificationsDataSource().setData(numNotifications);
68     }
69 
70     @Before
setUp()71     public void setUp() {
72         MockitoAnnotations.initMocks(this);
73 
74         mLooper = new TestLooper();
75         mWakeupOnboarding = new WakeupOnboarding(mContext, mWifiConfigManager,
76                 new Handler(mLooper.getLooper()), mFrameworkFacade, mWakeupNotificationFactory,
77                 mWifiNotificationManager);
78     }
79 
80     /**
81      * Verify that the notification shows if the user isn't onboarded.
82      */
83     @Test
showsNotificationIfNotOnboarded()84     public void showsNotificationIfNotOnboarded() {
85         setOnboardedStatus(false);
86         mWakeupOnboarding.maybeShowNotification();
87 
88         verify(mWifiNotificationManager).notify(eq(WakeupNotificationFactory.ONBOARD_ID), any());
89     }
90 
91     /**
92      * Verify that the notification does not show if the user is onboarded.
93      */
94     @Test
doesNotShowNotificationIfAlreadyOnboarded()95     public void doesNotShowNotificationIfAlreadyOnboarded() {
96         setOnboardedStatus(true);
97         mWakeupOnboarding.maybeShowNotification();
98 
99         verify(mWifiNotificationManager, never())
100                 .notify(eq(WakeupNotificationFactory.ONBOARD_ID), any());
101     }
102 
103     /**
104      * Verify that the notification does not relaunch if it's already showing.
105      */
106     @Test
doesNotShowNotificationIfAlreadyShowing()107     public void doesNotShowNotificationIfAlreadyShowing() {
108         setOnboardedStatus(false);
109         mWakeupOnboarding.maybeShowNotification();
110         mWakeupOnboarding.maybeShowNotification();
111 
112         InOrder inOrder = Mockito.inOrder(mWifiNotificationManager);
113         inOrder.verify(mWifiNotificationManager).notify(eq(WakeupNotificationFactory.ONBOARD_ID),
114                 any());
115         inOrder.verifyNoMoreInteractions();
116     }
117 
118     /**
119      * Verify that the user is onboarded when the notification is dismissed.
120      */
121     @Test
dismissNotificationAction_setsOnboarded()122     public void dismissNotificationAction_setsOnboarded() {
123         setOnboardedStatus(false);
124         assertFalse(mWakeupOnboarding.isOnboarded());
125 
126         mWakeupOnboarding.maybeShowNotification();
127         ArgumentCaptor<BroadcastReceiver> captor = ArgumentCaptor.forClass(BroadcastReceiver.class);
128         verify(mContext).registerReceiver(captor.capture(), any(IntentFilter.class), any(),
129                 any(Handler.class));
130         BroadcastReceiver broadcastReceiver = captor.getValue();
131 
132         broadcastReceiver.onReceive(mContext, new Intent(ACTION_DISMISS_NOTIFICATION));
133 
134         verify(mWifiNotificationManager).cancel(WakeupNotificationFactory.ONBOARD_ID);
135         assertTrue(mWakeupOnboarding.isOnboarded());
136     }
137 
138     /**
139      * Verify that the user is onboarded and Wifi Wake is turned off when the user selects the
140      * ACTION_TURN_OFF_WIFI_WAKE action.
141      */
142     @Test
turnOffWifiWakeAction_setsOnboardedAndTurnsOffWifiWake()143     public void turnOffWifiWakeAction_setsOnboardedAndTurnsOffWifiWake() {
144         setOnboardedStatus(false);
145         assertFalse(mWakeupOnboarding.isOnboarded());
146 
147         mWakeupOnboarding.maybeShowNotification();
148         ArgumentCaptor<BroadcastReceiver> captor = ArgumentCaptor.forClass(BroadcastReceiver.class);
149         verify(mContext).registerReceiver(captor.capture(), any(IntentFilter.class), any(),
150                 any(Handler.class));
151         BroadcastReceiver broadcastReceiver = captor.getValue();
152 
153         broadcastReceiver.onReceive(mContext, new Intent(ACTION_TURN_OFF_WIFI_WAKE));
154 
155         verify(mFrameworkFacade).setIntegerSetting(mContext,
156                 Settings.Global.WIFI_WAKEUP_ENABLED, 0);
157 
158         verify(mWifiNotificationManager).cancel(WakeupNotificationFactory.ONBOARD_ID);
159         assertTrue(mWakeupOnboarding.isOnboarded());
160     }
161 
162     /**
163      * Verify that the user is onboarded and sent to WifiSettings when the user selects the
164      * ACTION_OPEN_WIFI_SETTINGS action.
165      */
166     @Test
openWifiSettingsAction_setsOnboardedAndOpensWifiSettings()167     public void openWifiSettingsAction_setsOnboardedAndOpensWifiSettings() {
168         setOnboardedStatus(false);
169         assertFalse(mWakeupOnboarding.isOnboarded());
170 
171         mWakeupOnboarding.maybeShowNotification();
172         ArgumentCaptor<BroadcastReceiver> captor = ArgumentCaptor.forClass(BroadcastReceiver.class);
173         verify(mContext).registerReceiver(captor.capture(), any(IntentFilter.class), any(),
174                 any(Handler.class));
175         BroadcastReceiver broadcastReceiver = captor.getValue();
176 
177         broadcastReceiver.onReceive(mContext, new Intent(ACTION_OPEN_WIFI_PREFERENCES));
178 
179         verify(mContext).startActivityAsUser(any(), any());
180 
181         verify(mWifiNotificationManager).cancel(WakeupNotificationFactory.ONBOARD_ID);
182         assertTrue(mWakeupOnboarding.isOnboarded());
183     }
184 
185     /**
186      * Verify that onStop() doesn't onboard the user.
187      */
188     @Test
onStopDismissesNotificationWithoutOnboarding()189     public void onStopDismissesNotificationWithoutOnboarding() {
190         setOnboardedStatus(false);
191         assertFalse(mWakeupOnboarding.isOnboarded());
192 
193         mWakeupOnboarding.maybeShowNotification();
194         mWakeupOnboarding.onStop();
195 
196         verify(mWifiNotificationManager).cancel(WakeupNotificationFactory.ONBOARD_ID);
197         assertFalse(mWakeupOnboarding.isOnboarded());
198     }
199 
200     /**
201      * Verify that incrementing the notification count saves to store.
202      */
203     @Test
setOnboardedSavesToStore()204     public void setOnboardedSavesToStore() {
205         setOnboardedStatus(false);
206         mWakeupOnboarding.setOnboarded();
207         verify(mWifiConfigManager).saveToStore();
208         assertTrue(mWakeupOnboarding.isOnboarded());
209     }
210 
211     /**
212      * Verify that incrementing the notification count saves to store.
213      */
214     @Test
incrementingNotificationCountSavesToStore()215     public void incrementingNotificationCountSavesToStore() {
216         setOnboardedStatus(false);
217         setNotificationsShown(0);
218         mWakeupOnboarding.maybeShowNotification();
219         verify(mWifiConfigManager).saveToStore();
220     }
221 
222     /**
223      * Verify that the notification does not show multiple times within 24 hours.
224      */
225     @Test
doesNotShowMultipleNotificationsWithin24Hours()226     public void doesNotShowMultipleNotificationsWithin24Hours() {
227         setOnboardedStatus(false);
228         setNotificationsShown(0);
229 
230         mWakeupOnboarding.maybeShowNotification(0 /* timestamp */);
231         mWakeupOnboarding.onStop();
232         mWakeupOnboarding.maybeShowNotification(0 /* timestamp */);
233 
234         InOrder inOrder = Mockito.inOrder(mWifiNotificationManager);
235         inOrder.verify(mWifiNotificationManager).notify(eq(WakeupNotificationFactory.ONBOARD_ID),
236                 any());
237         inOrder.verify(mWifiNotificationManager).cancel(WakeupNotificationFactory.ONBOARD_ID);
238         inOrder.verifyNoMoreInteractions();
239     }
240 
241     /**
242      * Verify that notification reappears after 24 hours if not onboarded.
243      */
244     @Test
showsNotificationsOutsideOf24Hours()245     public void showsNotificationsOutsideOf24Hours() {
246         setOnboardedStatus(false);
247         setNotificationsShown(0);
248 
249         mWakeupOnboarding.maybeShowNotification(0 /* timestamp */);
250         assertFalse(mWakeupOnboarding.isOnboarded());
251 
252         mWakeupOnboarding.onStop();
253         mWakeupOnboarding.maybeShowNotification(WakeupOnboarding.REQUIRED_NOTIFICATION_DELAY + 1);
254 
255         verify(mWifiNotificationManager, times(2))
256                 .notify(eq(WakeupNotificationFactory.ONBOARD_ID), any());
257     }
258 
259     /**
260      * Verify that the user is onboarded after
261      * {@link WakeupOnboarding#NOTIFICATIONS_UNTIL_ONBOARDED} notifications are shown.
262      */
263     @Test
onboardsUserAfterThreeNotifications()264     public void onboardsUserAfterThreeNotifications() {
265         setOnboardedStatus(false);
266         setNotificationsShown(WakeupOnboarding.NOTIFICATIONS_UNTIL_ONBOARDED - 1);
267 
268         mWakeupOnboarding.maybeShowNotification(0 /* timestamp */);
269         assertTrue(mWakeupOnboarding.isOnboarded());
270     }
271 }
272