• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.settings.notification;
18 
19 import static com.google.common.truth.Truth.assertThat;
20 import static org.mockito.Matchers.any;
21 import static org.mockito.Matchers.anyInt;
22 import static org.mockito.Matchers.anyString;
23 import static org.mockito.Matchers.argThat;
24 import static org.mockito.Mockito.doNothing;
25 import static org.mockito.Mockito.doReturn;
26 import static org.mockito.Mockito.mock;
27 import static org.mockito.Mockito.never;
28 import static org.mockito.Mockito.spy;
29 import static org.mockito.Mockito.times;
30 import static org.mockito.Mockito.verify;
31 import static org.mockito.Mockito.when;
32 
33 import android.app.Activity;
34 import android.app.Fragment;
35 import android.content.Context;
36 import android.content.Intent;
37 import android.content.pm.ApplicationInfo;
38 import android.content.pm.PackageManager;
39 import android.content.pm.ResolveInfo;
40 import android.os.UserHandle;
41 import android.os.UserManager;
42 import android.service.notification.NotifyingApp;
43 import android.support.v7.preference.Preference;
44 import android.support.v7.preference.PreferenceCategory;
45 import android.support.v7.preference.PreferenceScreen;
46 import android.text.TextUtils;
47 
48 import com.android.settings.R;
49 import com.android.settings.testutils.SettingsRobolectricTestRunner;
50 import com.android.settingslib.applications.AppUtils;
51 import com.android.settingslib.applications.ApplicationsState;
52 import com.android.settingslib.applications.instantapps.InstantAppDataProvider;
53 
54 import org.junit.Before;
55 import org.junit.Test;
56 import org.junit.runner.RunWith;
57 import org.mockito.ArgumentCaptor;
58 import org.mockito.ArgumentMatcher;
59 import org.mockito.Mock;
60 import org.mockito.MockitoAnnotations;
61 import org.robolectric.RuntimeEnvironment;
62 import org.robolectric.annotation.Config;
63 import org.robolectric.util.ReflectionHelpers;
64 
65 import java.util.ArrayList;
66 import java.util.List;
67 
68 @RunWith(SettingsRobolectricTestRunner.class)
69 public class RecentNotifyingAppsPreferenceControllerTest {
70 
71     @Mock
72     private PreferenceScreen mScreen;
73     @Mock
74     private PreferenceCategory mCategory;
75     @Mock
76     private Preference mSeeAllPref;
77     @Mock
78     private PreferenceCategory mDivider;
79     @Mock
80     private UserManager mUserManager;
81     @Mock
82     private ApplicationsState mAppState;
83     @Mock
84     private PackageManager mPackageManager;
85     @Mock
86     private ApplicationsState.AppEntry mAppEntry;
87     @Mock
88     private ApplicationInfo mApplicationInfo;
89     @Mock
90     private NotificationBackend mBackend;
91     @Mock
92     private Fragment mHost;
93     @Mock
94     private Activity mActivity;
95 
96     private Context mContext;
97     private RecentNotifyingAppsPreferenceController mController;
98 
99     @Before
setUp()100     public void setUp() {
101         MockitoAnnotations.initMocks(this);
102         mContext = spy(RuntimeEnvironment.application);
103         doReturn(mUserManager).when(mContext).getSystemService(Context.USER_SERVICE);
104         doReturn(mPackageManager).when(mContext).getPackageManager();
105 
106         mController = new RecentNotifyingAppsPreferenceController(
107                 mContext, mBackend, mAppState, mHost);
108         when(mScreen.findPreference(anyString())).thenReturn(mCategory);
109 
110         when(mScreen.findPreference(RecentNotifyingAppsPreferenceController.KEY_SEE_ALL))
111                 .thenReturn(mSeeAllPref);
112         when(mScreen.findPreference(RecentNotifyingAppsPreferenceController.KEY_DIVIDER))
113                 .thenReturn(mDivider);
114         when(mCategory.getContext()).thenReturn(mContext);
115         when(mHost.getActivity()).thenReturn(mActivity);
116     }
117 
118     @Test
isAlwaysAvailable()119     public void isAlwaysAvailable() {
120         assertThat(mController.isAvailable()).isTrue();
121     }
122 
123     @Test
doNotIndexCategory()124     public void doNotIndexCategory() {
125         final List<String> nonIndexable = new ArrayList<>();
126 
127         mController.updateNonIndexableKeys(nonIndexable);
128 
129         assertThat(nonIndexable).containsAllOf(mController.getPreferenceKey(),
130                 RecentNotifyingAppsPreferenceController.KEY_DIVIDER);
131     }
132 
133     @Test
onDisplayAndUpdateState_shouldRefreshUi()134     public void onDisplayAndUpdateState_shouldRefreshUi() {
135         mController = spy(new RecentNotifyingAppsPreferenceController(
136                 mContext, null, (ApplicationsState) null, null));
137 
138         doNothing().when(mController).refreshUi(mContext);
139 
140         mController.displayPreference(mScreen);
141         mController.updateState(mCategory);
142 
143         verify(mController, times(2)).refreshUi(mContext);
144     }
145 
146     @Test
147     @Config(qualifiers = "mcc999")
display_shouldNotShowRecents_showAppInfoPreference()148     public void display_shouldNotShowRecents_showAppInfoPreference() {
149         mController.displayPreference(mScreen);
150 
151         verify(mCategory, never()).addPreference(any(Preference.class));
152         verify(mCategory).setTitle(null);
153         verify(mSeeAllPref).setTitle(R.string.notifications_title);
154         verify(mSeeAllPref).setIcon(null);
155         verify(mDivider).setVisible(false);
156     }
157 
158     @Test
display_showRecents()159     public void display_showRecents() {
160         final List<NotifyingApp> apps = new ArrayList<>();
161         final NotifyingApp app1 = new NotifyingApp()
162                 .setPackage("pkg.class")
163                 .setLastNotified(System.currentTimeMillis());
164         final NotifyingApp app2 = new NotifyingApp()
165                 .setLastNotified(System.currentTimeMillis())
166                 .setPackage("com.android.settings");
167         final NotifyingApp app3 = new NotifyingApp()
168                 .setLastNotified(System.currentTimeMillis() - 1000)
169                 .setPackage("pkg.class2");
170 
171         apps.add(app1);
172         apps.add(app2);
173         apps.add(app3);
174 
175         // app1, app2 are valid apps. app3 is invalid.
176         when(mAppState.getEntry(app1.getPackage(), UserHandle.myUserId()))
177                 .thenReturn(mAppEntry);
178         when(mAppState.getEntry(app2.getPackage(), UserHandle.myUserId()))
179                 .thenReturn(mAppEntry);
180         when(mAppState.getEntry(app3.getPackage(), UserHandle.myUserId()))
181                 .thenReturn(null);
182         when(mPackageManager.resolveActivity(any(Intent.class), anyInt())).thenReturn(
183                 new ResolveInfo());
184         when(mBackend.getRecentApps()).thenReturn(apps);
185         mAppEntry.info = mApplicationInfo;
186 
187         mController.displayPreference(mScreen);
188 
189         verify(mCategory).setTitle(R.string.recent_notifications);
190         // Only add app1. app2 is skipped because of the package name, app3 skipped because
191         // it's invalid app.
192         verify(mCategory, times(1)).addPreference(any(Preference.class));
193 
194         verify(mSeeAllPref).setSummary(null);
195         verify(mSeeAllPref).setIcon(R.drawable.ic_chevron_right_24dp);
196         verify(mDivider).setVisible(true);
197     }
198 
199     @Test
display_showRecentsWithInstantApp()200     public void display_showRecentsWithInstantApp() {
201         // Regular app.
202         final List<NotifyingApp> apps = new ArrayList<>();
203         final NotifyingApp app1 = new NotifyingApp().
204                 setLastNotified(System.currentTimeMillis())
205                 .setPackage("com.foo.bar");
206         apps.add(app1);
207 
208         // Instant app.
209         final NotifyingApp app2 = new NotifyingApp()
210                 .setLastNotified(System.currentTimeMillis() + 200)
211                 .setPackage("com.foo.barinstant");
212         apps.add(app2);
213 
214         ApplicationsState.AppEntry app1Entry = mock(ApplicationsState.AppEntry.class);
215         ApplicationsState.AppEntry app2Entry = mock(ApplicationsState.AppEntry.class);
216         app1Entry.info = mApplicationInfo;
217         app2Entry.info = mApplicationInfo;
218 
219         when(mAppState.getEntry(app1.getPackage(), UserHandle.myUserId())).thenReturn(app1Entry);
220         when(mAppState.getEntry(app2.getPackage(), UserHandle.myUserId())).thenReturn(app2Entry);
221 
222         // Only the regular app app1 should have its intent resolve.
223         when(mPackageManager.resolveActivity(argThat(intentMatcher(app1.getPackage())),
224                 anyInt())).thenReturn(new ResolveInfo());
225 
226         when(mBackend.getRecentApps()).thenReturn(apps);
227 
228         // Make sure app2 is considered an instant app.
229         ReflectionHelpers.setStaticField(AppUtils.class, "sInstantAppDataProvider",
230                 (InstantAppDataProvider) (ApplicationInfo info) -> {
231                     if (info == app2Entry.info) {
232                         return true;
233                     } else {
234                         return false;
235                     }
236                 });
237 
238         mController.displayPreference(mScreen);
239 
240         ArgumentCaptor<Preference> prefCaptor = ArgumentCaptor.forClass(Preference.class);
241         verify(mCategory, times(2)).addPreference(prefCaptor.capture());
242         List<Preference> prefs = prefCaptor.getAllValues();
243         assertThat(prefs.get(1).getKey()).isEqualTo(app1.getPackage());
244         assertThat(prefs.get(0).getKey()).isEqualTo(app2.getPackage());
245     }
246 
247     @Test
display_hasRecentButNoneDisplayable_showAppInfo()248     public void display_hasRecentButNoneDisplayable_showAppInfo() {
249         final List<NotifyingApp> apps = new ArrayList<>();
250         final NotifyingApp app1 = new NotifyingApp()
251                 .setPackage("com.android.phone")
252                 .setLastNotified(System.currentTimeMillis());
253         final NotifyingApp app2 = new NotifyingApp()
254                 .setPackage("com.android.settings")
255                 .setLastNotified(System.currentTimeMillis());
256         apps.add(app1);
257         apps.add(app2);
258 
259         // app1, app2 are not displayable
260         when(mAppState.getEntry(app1.getPackage(), UserHandle.myUserId()))
261                 .thenReturn(mock(ApplicationsState.AppEntry.class));
262         when(mAppState.getEntry(app2.getPackage(), UserHandle.myUserId()))
263                 .thenReturn(mock(ApplicationsState.AppEntry.class));
264         when(mPackageManager.resolveActivity(any(Intent.class), anyInt())).thenReturn(
265                 new ResolveInfo());
266         when(mBackend.getRecentApps()).thenReturn(apps);
267 
268         mController.displayPreference(mScreen);
269 
270         verify(mCategory, never()).addPreference(any(Preference.class));
271         verify(mCategory).setTitle(null);
272         verify(mSeeAllPref).setTitle(R.string.notifications_title);
273         verify(mSeeAllPref).setIcon(null);
274     }
275 
276     @Test
display_showRecents_formatSummary()277     public void display_showRecents_formatSummary() {
278         final List<NotifyingApp> apps = new ArrayList<>();
279         final NotifyingApp app1 = new NotifyingApp()
280                 .setLastNotified(System.currentTimeMillis())
281                 .setPackage("pkg.class");
282         apps.add(app1);
283 
284         when(mAppState.getEntry(app1.getPackage(), UserHandle.myUserId()))
285                 .thenReturn(mAppEntry);
286         when(mPackageManager.resolveActivity(any(Intent.class), anyInt())).thenReturn(
287                 new ResolveInfo());
288         when(mBackend.getRecentApps()).thenReturn(apps);
289         mAppEntry.info = mApplicationInfo;
290 
291         mController.displayPreference(mScreen);
292 
293         verify(mCategory).addPreference(argThat(summaryMatches("Just now")));
294     }
295 
summaryMatches(String expected)296     private static ArgumentMatcher<Preference> summaryMatches(String expected) {
297         return preference -> TextUtils.equals(expected, preference.getSummary());
298     }
299 
300     // Used for matching an intent with a specific package name.
intentMatcher(String packageName)301     private static ArgumentMatcher<Intent> intentMatcher(String packageName) {
302         return intent -> packageName.equals(intent.getPackage());
303     }
304 }
305