1/*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5 * use this file except in compliance with the License. You may obtain a copy of
6 * 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, WITHOUT
12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 * License for the specific language governing permissions and limitations under
14 * the License.
15 */
16
17package com.android.storagemanager.automatic;
18
19import android.app.Notification;
20import android.app.NotificationManager;
21import android.content.Context;
22import android.content.Intent;
23import android.provider.Settings;
24import com.android.storagemanager.testing.TestingConstants;
25import org.junit.Before;
26import org.junit.Test;
27import org.junit.runner.RunWith;
28import org.mockito.ArgumentCaptor;
29import org.mockito.Mock;
30import org.mockito.MockitoAnnotations;
31import org.robolectric.RobolectricTestRunner;
32import org.robolectric.annotation.Config;
33import org.robolectric.shadows.ShadowApplication;
34
35import java.util.concurrent.TimeUnit;
36
37import static com.google.common.truth.Truth.assertThat;
38import static org.mockito.Matchers.any;
39import static org.mockito.Matchers.anyInt;
40import static org.mockito.Mockito.*;
41
42@RunWith(RobolectricTestRunner.class)
43@Config(manifest=TestingConstants.MANIFEST, sdk=TestingConstants.SDK_VERSION)
44public class NotificationControllerTest {
45    @Mock
46    private NotificationManager mNotificationManager;
47    private Context mContext;
48    private NotificationController mController;
49    private FakeClock mClock;
50
51    @Before
52    public void setUp() {
53        MockitoAnnotations.initMocks(this);
54        ShadowApplication application = ShadowApplication.getInstance();
55        application.setSystemService(Context.NOTIFICATION_SERVICE, mNotificationManager);
56        mController = new NotificationController();
57        mClock = new FakeClock();
58        mController.setClock(mClock);
59        mContext = application.getApplicationContext();
60    }
61
62    @Test
63    public void testShouldShowNotificationFirstTime() {
64        mController.onReceive(mContext,
65                new Intent(NotificationController.INTENT_ACTION_SHOW_NOTIFICATION));
66
67        verify(mNotificationManager).notify(anyInt(), any(Notification.class));
68        mController.onReceive(mContext,
69                getNotificationIntent(NotificationController.INTENT_ACTION_DISMISS, 1));
70        verify(mNotificationManager).cancel(1);
71    }
72
73    @Test
74    public void testNotificationNotShownIfShownTooManyTimes() {
75        // Show the notification 4 times.
76        for (int i = 1; i < 5; i++) {
77            mController.onReceive(mContext,
78                    new Intent(NotificationController.INTENT_ACTION_SHOW_NOTIFICATION));
79            verify(mNotificationManager, times(i)).notify(anyInt(), any(Notification.class));
80            mController.onReceive(mContext,
81                    getNotificationIntent(NotificationController.INTENT_ACTION_NO_THANKS, 1));
82            verify(mNotificationManager, times(i)).cancel(1);
83            mClock.time += TimeUnit.DAYS.toMillis(91);
84        }
85
86        // The next time should show nothing.
87        mController.onReceive(mContext,
88                new Intent(NotificationController.INTENT_ACTION_SHOW_NOTIFICATION));
89        verifyZeroInteractions(mNotificationManager);
90    }
91
92    @Test
93    public void testNotificationNotShownIfDismissedTooManyTimes() {
94        // Show the notification 9 times.
95        for (int i = 0; i < 9; i++) {
96            mController.onReceive(mContext,
97                    new Intent(NotificationController.INTENT_ACTION_SHOW_NOTIFICATION));
98            verify(mNotificationManager, times(i + 1)).notify(anyInt(), any(Notification.class));
99            mController.onReceive(mContext,
100                    getNotificationIntent(NotificationController.INTENT_ACTION_DISMISS, 1));
101            verify(mNotificationManager, times(i + 1)).cancel(1);
102            mClock.time += TimeUnit.DAYS.toMillis(14);
103        }
104
105        // The next time should show nothing.
106        mController.onReceive(mContext,
107                new Intent(NotificationController.INTENT_ACTION_SHOW_NOTIFICATION));
108        verifyZeroInteractions(mNotificationManager);
109    }
110
111    @Test
112    public void testDismissNotificationDelay() {
113        mController.onReceive(mContext,
114                new Intent(NotificationController.INTENT_ACTION_SHOW_NOTIFICATION));
115        verify(mNotificationManager).notify(anyInt(), any(Notification.class));
116        mController.onReceive(mContext,
117                getNotificationIntent(NotificationController.INTENT_ACTION_DISMISS, 1));
118        verify(mNotificationManager).cancel(1);
119
120        // Another attempt should not show a notification.
121        mController.onReceive(mContext,
122                new Intent(NotificationController.INTENT_ACTION_SHOW_NOTIFICATION));
123        verifyZeroInteractions(mNotificationManager);
124
125        // The notification should show against after 14 days.
126        mClock.time = TimeUnit.DAYS.toMillis(14);
127        mController.onReceive(mContext,
128                new Intent(NotificationController.INTENT_ACTION_SHOW_NOTIFICATION));
129        verify(mNotificationManager, times(2)).notify(anyInt(), any(Notification.class));
130    }
131
132    @Test
133    public void testNoThanksNotificationDelay() {
134        mController.onReceive(mContext,
135                new Intent(NotificationController.INTENT_ACTION_SHOW_NOTIFICATION));
136        verify(mNotificationManager).notify(anyInt(), any(Notification.class));
137        mController.onReceive(mContext,
138                getNotificationIntent(NotificationController.INTENT_ACTION_NO_THANKS, 1));
139        verify(mNotificationManager).cancel(1);
140
141        // Another attempt should not show a notification.
142        mController.onReceive(mContext,
143                new Intent(NotificationController.INTENT_ACTION_SHOW_NOTIFICATION));
144        verifyZeroInteractions(mNotificationManager);
145
146        // The notification should show against after 90 days.
147        mClock.time = TimeUnit.DAYS.toMillis(90);
148        mController.onReceive(mContext,
149                new Intent(NotificationController.INTENT_ACTION_SHOW_NOTIFICATION));
150        verify(mNotificationManager, times(2)).notify(anyInt(), any(Notification.class));
151    }
152
153    @Test
154    public void testActivateStorageManagerIntent() throws Exception {
155        mController.onReceive(mContext,
156                new Intent(NotificationController.INTENT_ACTION_ACTIVATE_ASM));
157        assertThat(Settings.Secure.getInt(mContext.getContentResolver(),
158                Settings.Secure.AUTOMATIC_STORAGE_MANAGER_ENABLED)).isEqualTo(1);
159    }
160
161    @Test
162    public void testNotificationIsLocalOnly(){
163        ArgumentCaptor<Notification> captor = ArgumentCaptor.forClass(Notification.class);
164        mController.onReceive(mContext,
165                new Intent(NotificationController.INTENT_ACTION_SHOW_NOTIFICATION));
166        verify(mNotificationManager).notify(anyInt(), captor.capture());
167        assertThat(captor.getValue().flags & Notification.FLAG_LOCAL_ONLY)
168                .isEqualTo(Notification.FLAG_LOCAL_ONLY);
169    }
170
171    @Test
172    public void testIntentFromNotificationAreExplicit() {
173        Intent baseIntent =
174                mController.getBaseIntent(mContext, NotificationController.INTENT_ACTION_DISMISS);
175
176        assertThat(baseIntent.getComponent().getPackageName())
177                .isEqualTo("com.android.storagemanager");
178        assertThat(baseIntent.getComponent().getClassName())
179                .isEqualTo("com.android.storagemanager.automatic.NotificationController");
180    }
181
182    @Test
183    public void testTappingGoesToStorageSettings() {
184        mController.onReceive(mContext, new Intent(NotificationController.INTENT_ACTION_TAP));
185
186        assertThat(ShadowApplication.getInstance().getNextStartedActivity().getAction())
187                .isEqualTo(Settings.ACTION_INTERNAL_STORAGE_SETTINGS);
188    }
189
190    private Intent getNotificationIntent(String action, int id) {
191        Intent intent = new Intent(action);
192        intent.putExtra(NotificationController.INTENT_EXTRA_ID, id);
193        return intent;
194    }
195
196    private class FakeClock extends NotificationController.Clock {
197        public long time = 0L;
198
199        @Override
200        public long currentTimeMillis() {
201            return time;
202        }
203    }
204}
205