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 import static org.mockito.Mockito.when;
31 
32 import android.app.NotificationManager;
33 import android.content.BroadcastReceiver;
34 import android.content.Context;
35 import android.content.Intent;
36 import android.content.IntentFilter;
37 import android.os.Handler;
38 import android.os.test.TestLooper;
39 import android.provider.Settings;
40 
41 import androidx.test.filters.SmallTest;
42 
43 import org.junit.Before;
44 import org.junit.Test;
45 import org.mockito.ArgumentCaptor;
46 import org.mockito.InOrder;
47 import org.mockito.Mock;
48 import org.mockito.Mockito;
49 import org.mockito.MockitoAnnotations;
50 
51 /** Unit tests for {@link com.android.server.wifi.WakeupOnboarding} */
52 @SmallTest
53 public class WakeupOnboardingTest {
54 
55     @Mock private Context mContext;
56     @Mock private WifiConfigManager mWifiConfigManager;
57     @Mock private FrameworkFacade mFrameworkFacade;
58     @Mock private WakeupNotificationFactory mWakeupNotificationFactory;
59     @Mock private NotificationManager mNotificationManager;
60 
61     private TestLooper mLooper;
62     private WakeupOnboarding mWakeupOnboarding;
63 
64     // convenience method for resetting onboarded status
setOnboardedStatus(boolean isOnboarded)65     private void setOnboardedStatus(boolean isOnboarded) {
66         mWakeupOnboarding.getIsOnboadedDataSource().setData(isOnboarded);
67     }
68 
setNotificationsShown(int numNotifications)69     private void setNotificationsShown(int numNotifications) {
70         mWakeupOnboarding.getNotificationsDataSource().setData(numNotifications);
71     }
72 
73     @Before
setUp()74     public void setUp() {
75         MockitoAnnotations.initMocks(this);
76 
77         when(mContext.getSystemService(Context.NOTIFICATION_SERVICE))
78                 .thenReturn(mNotificationManager);
79 
80         mLooper = new TestLooper();
81         mWakeupOnboarding = new WakeupOnboarding(mContext, mWifiConfigManager, mLooper.getLooper(),
82                 mFrameworkFacade, mWakeupNotificationFactory);
83     }
84 
85     /**
86      * Verify that the notification shows if the user isn't onboarded.
87      */
88     @Test
showsNotificationIfNotOnboarded()89     public void showsNotificationIfNotOnboarded() {
90         setOnboardedStatus(false);
91         mWakeupOnboarding.maybeShowNotification();
92 
93         verify(mNotificationManager).notify(eq(WakeupNotificationFactory.ONBOARD_ID), any());
94     }
95 
96     /**
97      * Verify that the notification does not show if the user is onboarded.
98      */
99     @Test
doesNotShowNotificationIfAlreadyOnboarded()100     public void doesNotShowNotificationIfAlreadyOnboarded() {
101         setOnboardedStatus(true);
102         mWakeupOnboarding.maybeShowNotification();
103 
104         verify(mNotificationManager, never())
105                 .notify(eq(WakeupNotificationFactory.ONBOARD_ID), any());
106     }
107 
108     /**
109      * Verify that the notification does not relaunch if it's already showing.
110      */
111     @Test
doesNotShowNotificationIfAlreadyShowing()112     public void doesNotShowNotificationIfAlreadyShowing() {
113         setOnboardedStatus(false);
114         mWakeupOnboarding.maybeShowNotification();
115         mWakeupOnboarding.maybeShowNotification();
116 
117         InOrder inOrder = Mockito.inOrder(mNotificationManager);
118         inOrder.verify(mNotificationManager)
119                 .notify(eq(WakeupNotificationFactory.ONBOARD_ID), any());
120         inOrder.verifyNoMoreInteractions();
121     }
122 
123     /**
124      * Verify that the user is onboarded when the notification is dismissed.
125      */
126     @Test
dismissNotificationAction_setsOnboarded()127     public void dismissNotificationAction_setsOnboarded() {
128         setOnboardedStatus(false);
129         assertFalse(mWakeupOnboarding.isOnboarded());
130 
131         mWakeupOnboarding.maybeShowNotification();
132         ArgumentCaptor<BroadcastReceiver> captor = ArgumentCaptor.forClass(BroadcastReceiver.class);
133         verify(mContext).registerReceiver(captor.capture(), any(IntentFilter.class), any(),
134                 any(Handler.class));
135         BroadcastReceiver broadcastReceiver = captor.getValue();
136 
137         broadcastReceiver.onReceive(mContext, new Intent(ACTION_DISMISS_NOTIFICATION));
138 
139         verify(mNotificationManager).cancel(WakeupNotificationFactory.ONBOARD_ID);
140         assertTrue(mWakeupOnboarding.isOnboarded());
141     }
142 
143     /**
144      * Verify that the user is onboarded and Wifi Wake is turned off when the user selects the
145      * ACTION_TURN_OFF_WIFI_WAKE action.
146      */
147     @Test
turnOffWifiWakeAction_setsOnboardedAndTurnsOffWifiWake()148     public void turnOffWifiWakeAction_setsOnboardedAndTurnsOffWifiWake() {
149         setOnboardedStatus(false);
150         assertFalse(mWakeupOnboarding.isOnboarded());
151 
152         mWakeupOnboarding.maybeShowNotification();
153         ArgumentCaptor<BroadcastReceiver> captor = ArgumentCaptor.forClass(BroadcastReceiver.class);
154         verify(mContext).registerReceiver(captor.capture(), any(IntentFilter.class), any(),
155                 any(Handler.class));
156         BroadcastReceiver broadcastReceiver = captor.getValue();
157 
158         broadcastReceiver.onReceive(mContext, new Intent(ACTION_TURN_OFF_WIFI_WAKE));
159 
160         verify(mFrameworkFacade).setIntegerSetting(mContext,
161                 Settings.Global.WIFI_WAKEUP_ENABLED, 0);
162 
163         verify(mNotificationManager).cancel(WakeupNotificationFactory.ONBOARD_ID);
164         assertTrue(mWakeupOnboarding.isOnboarded());
165     }
166 
167     /**
168      * Verify that the user is onboarded and sent to WifiSettings when the user selects the
169      * ACTION_OPEN_WIFI_SETTINGS action.
170      */
171     @Test
openWifiSettingsAction_setsOnboardedAndOpensWifiSettings()172     public void openWifiSettingsAction_setsOnboardedAndOpensWifiSettings() {
173         setOnboardedStatus(false);
174         assertFalse(mWakeupOnboarding.isOnboarded());
175 
176         mWakeupOnboarding.maybeShowNotification();
177         ArgumentCaptor<BroadcastReceiver> captor = ArgumentCaptor.forClass(BroadcastReceiver.class);
178         verify(mContext).registerReceiver(captor.capture(), any(IntentFilter.class), any(),
179                 any(Handler.class));
180         BroadcastReceiver broadcastReceiver = captor.getValue();
181 
182         broadcastReceiver.onReceive(mContext, new Intent(ACTION_OPEN_WIFI_PREFERENCES));
183 
184         verify(mContext).startActivity(any());
185 
186         verify(mNotificationManager).cancel(WakeupNotificationFactory.ONBOARD_ID);
187         assertTrue(mWakeupOnboarding.isOnboarded());
188     }
189 
190     /**
191      * Verify that onStop() doesn't onboard the user.
192      */
193     @Test
onStopDismissesNotificationWithoutOnboarding()194     public void onStopDismissesNotificationWithoutOnboarding() {
195         setOnboardedStatus(false);
196         assertFalse(mWakeupOnboarding.isOnboarded());
197 
198         mWakeupOnboarding.maybeShowNotification();
199         mWakeupOnboarding.onStop();
200 
201         verify(mNotificationManager).cancel(WakeupNotificationFactory.ONBOARD_ID);
202         assertFalse(mWakeupOnboarding.isOnboarded());
203     }
204 
205     /**
206      * Verify that incrementing the notification count saves to store.
207      */
208     @Test
setOnboardedSavesToStore()209     public void setOnboardedSavesToStore() {
210         setOnboardedStatus(false);
211         mWakeupOnboarding.setOnboarded();
212         verify(mWifiConfigManager).saveToStore(false /* forceWrite */);
213         assertTrue(mWakeupOnboarding.isOnboarded());
214     }
215 
216     /**
217      * Verify that incrementing the notification count saves to store.
218      */
219     @Test
incrementingNotificationCountSavesToStore()220     public void incrementingNotificationCountSavesToStore() {
221         setOnboardedStatus(false);
222         setNotificationsShown(0);
223         mWakeupOnboarding.maybeShowNotification();
224         verify(mWifiConfigManager).saveToStore(false /* forceWrite */);
225     }
226 
227     /**
228      * Verify that the notification does not show multiple times within 24 hours.
229      */
230     @Test
doesNotShowMultipleNotificationsWithin24Hours()231     public void doesNotShowMultipleNotificationsWithin24Hours() {
232         setOnboardedStatus(false);
233         setNotificationsShown(0);
234 
235         mWakeupOnboarding.maybeShowNotification(0 /* timestamp */);
236         mWakeupOnboarding.onStop();
237         mWakeupOnboarding.maybeShowNotification(0 /* timestamp */);
238 
239         InOrder inOrder = Mockito.inOrder(mNotificationManager);
240         inOrder.verify(mNotificationManager)
241                 .notify(eq(WakeupNotificationFactory.ONBOARD_ID), any());
242         inOrder.verify(mNotificationManager).cancel(WakeupNotificationFactory.ONBOARD_ID);
243         inOrder.verifyNoMoreInteractions();
244     }
245 
246     /**
247      * Verify that notification reappears after 24 hours if not onboarded.
248      */
249     @Test
showsNotificationsOutsideOf24Hours()250     public void showsNotificationsOutsideOf24Hours() {
251         setOnboardedStatus(false);
252         setNotificationsShown(0);
253 
254         mWakeupOnboarding.maybeShowNotification(0 /* timestamp */);
255         assertFalse(mWakeupOnboarding.isOnboarded());
256 
257         mWakeupOnboarding.onStop();
258         mWakeupOnboarding.maybeShowNotification(WakeupOnboarding.REQUIRED_NOTIFICATION_DELAY + 1);
259 
260         verify(mNotificationManager, times(2))
261                 .notify(eq(WakeupNotificationFactory.ONBOARD_ID), any());
262     }
263 
264     /**
265      * Verify that the user is onboarded after
266      * {@link WakeupOnboarding#NOTIFICATIONS_UNTIL_ONBOARDED} notifications are shown.
267      */
268     @Test
onboardsUserAfterThreeNotifications()269     public void onboardsUserAfterThreeNotifications() {
270         setOnboardedStatus(false);
271         setNotificationsShown(WakeupOnboarding.NOTIFICATIONS_UNTIL_ONBOARDED - 1);
272 
273         mWakeupOnboarding.maybeShowNotification(0 /* timestamp */);
274         assertTrue(mWakeupOnboarding.isOnboarded());
275     }
276 }
277