From e81b8275a8ec480740b446264b6529eca84a3f18 Mon Sep 17 00:00:00 2001 From: Julia Reynolds Date: Tue, 25 May 2021 11:50:21 -0400 Subject: [PATCH] Consolidate app notification setting prefs Test: manual Fixes: 189201867 Change-Id: If5cc03e0bd2d4273cd842e097b99b15d1178f3dc --- res/values/strings.xml | 6 + res/xml/configure_notification_settings.xml | 83 ++-- .../ConfigureNotificationSettings.java | 4 - ...centNotifyingAppsPreferenceController.java | 301 -------------- ...NotifyingAppsPreferenceControllerTest.java | 389 ------------------ 5 files changed, 39 insertions(+), 744 deletions(-) delete mode 100644 src/com/android/settings/notification/RecentNotifyingAppsPreferenceController.java delete mode 100644 tests/robotests/src/com/android/settings/notification/RecentNotifyingAppsPreferenceControllerTest.java diff --git a/res/values/strings.xml b/res/values/strings.xml index 4dc306093ce..424f7a20a9c 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -8747,6 +8747,12 @@ See all from last 7 days + + General + + + App settings + General diff --git a/res/xml/configure_notification_settings.xml b/res/xml/configure_notification_settings.xml index ab22f73dd8f..dad5e0e5453 100644 --- a/res/xml/configure_notification_settings.xml +++ b/res/xml/configure_notification_settings.xml @@ -18,6 +18,39 @@ xmlns:settings="http://schemas.android.com/apk/res-auto" android:title="@string/configure_notification_settings"> + + + + + + + + + + + @@ -39,59 +72,9 @@ /> - - - - - - - - - - - - - - - - buildPreferenceControllers(Context context, Application app, Fragment host) { final List controllers = new ArrayList<>(); - controllers.add(new RecentNotifyingAppsPreferenceController( - context, new NotificationBackend(), IUsageStatsManager.Stub.asInterface( - ServiceManager.getService(Context.USAGE_STATS_SERVICE)), - context.getSystemService(UserManager.class), app, host)); controllers.add(new ShowOnLockScreenNotificationPreferenceController( context, KEY_LOCKSCREEN)); controllers.add(new NotificationRingtonePreferenceController(context) { diff --git a/src/com/android/settings/notification/RecentNotifyingAppsPreferenceController.java b/src/com/android/settings/notification/RecentNotifyingAppsPreferenceController.java deleted file mode 100644 index 8e0807db89e..00000000000 --- a/src/com/android/settings/notification/RecentNotifyingAppsPreferenceController.java +++ /dev/null @@ -1,301 +0,0 @@ -/* - * Copyright (C) 2018 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.settings.notification; - -import android.app.Application; -import android.app.settings.SettingsEnums; -import android.app.usage.IUsageStatsManager; -import android.app.usage.UsageEvents; -import android.content.Context; -import android.content.pm.PackageManager; -import android.os.Bundle; -import android.os.RemoteException; -import android.os.UserHandle; -import android.os.UserManager; -import android.service.notification.NotifyingApp; -import android.text.TextUtils; -import android.util.ArrayMap; -import android.util.IconDrawableFactory; -import android.util.Slog; - -import androidx.annotation.VisibleForTesting; -import androidx.fragment.app.Fragment; -import androidx.preference.Preference; -import androidx.preference.PreferenceCategory; -import androidx.preference.PreferenceScreen; - -import com.android.settings.R; -import com.android.settings.Utils; -import com.android.settings.applications.AppInfoBase; -import com.android.settings.core.PreferenceControllerMixin; -import com.android.settings.core.SubSettingLauncher; -import com.android.settings.notification.app.AppNotificationSettings; -import com.android.settings.widget.PrimarySwitchPreference; -import com.android.settingslib.applications.ApplicationsState; -import com.android.settingslib.core.AbstractPreferenceController; -import com.android.settingslib.utils.StringUtil; -import com.android.settingslib.utils.ThreadUtils; -import com.android.settingslib.widget.TwoTargetPreference; - -import java.util.ArrayList; -import java.util.Calendar; -import java.util.Collections; -import java.util.List; - -/** - * This controller displays a list of recently used apps and a "See all" button. If there is - * no recently used app, "See all" will be displayed as "Notifications". - */ -public class RecentNotifyingAppsPreferenceController extends AbstractPreferenceController - implements PreferenceControllerMixin { - - private static final String TAG = "RecentNotisCtrl"; - private static final String KEY_PREF_CATEGORY = "recent_notifications_category"; - - @VisibleForTesting - static final String KEY_SEE_ALL = "all_notifications"; - static final String KEY_PLACEHOLDER = "app"; - private static final int SHOW_RECENT_APP_COUNT = 3; - private static final int DAYS = 3; - - private final Fragment mHost; - private final PackageManager mPm; - private final NotificationBackend mNotificationBackend; - private IUsageStatsManager mUsageStatsManager; - private final IconDrawableFactory mIconDrawableFactory; - - private Calendar mCal; - List mApps; - private final ApplicationsState mApplicationsState; - - private PreferenceCategory mCategory; - private Preference mSeeAllPref; - protected List mUserIds; - - public RecentNotifyingAppsPreferenceController(Context context, NotificationBackend backend, - IUsageStatsManager usageStatsManager, UserManager userManager, - Application app, Fragment host) { - this(context, backend, usageStatsManager, userManager, - app == null ? null : ApplicationsState.getInstance(app), host); - } - - @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE) - RecentNotifyingAppsPreferenceController(Context context, NotificationBackend backend, - IUsageStatsManager usageStatsManager, UserManager userManager, - ApplicationsState appState, Fragment host) { - super(context); - mIconDrawableFactory = IconDrawableFactory.newInstance(context); - mPm = context.getPackageManager(); - mHost = host; - mApplicationsState = appState; - mNotificationBackend = backend; - mUsageStatsManager = usageStatsManager; - mUserIds = new ArrayList<>(); - mUserIds.add(mContext.getUserId()); - int workUserId = Utils.getManagedProfileId(userManager, mContext.getUserId()); - if (workUserId != UserHandle.USER_NULL) { - mUserIds.add(workUserId); - } - } - - @Override - public boolean isAvailable() { - return mApplicationsState != null; - } - - @Override - public String getPreferenceKey() { - return KEY_PREF_CATEGORY; - } - - @Override - public void updateNonIndexableKeys(List keys) { - PreferenceControllerMixin.super.updateNonIndexableKeys(keys); - // Don't index category name into search. It's not actionable. - keys.add(KEY_PREF_CATEGORY); - } - - @Override - public void displayPreference(PreferenceScreen screen) { - mCategory = screen.findPreference(getPreferenceKey()); - mSeeAllPref = screen.findPreference(KEY_SEE_ALL); - super.displayPreference(screen); - refreshUi(mCategory.getContext()); - } - - @Override - public void updateState(Preference preference) { - super.updateState(preference); - refreshUi(mCategory.getContext()); - mSeeAllPref.setTitle(mContext.getString(R.string.recent_notifications_see_all_title)); - } - - @VisibleForTesting - void refreshUi(Context prefContext) { - for (int i = 1; i <= SHOW_RECENT_APP_COUNT; i++) { - PrimarySwitchPreference app = mCategory.findPreference(KEY_PLACEHOLDER + i); - if (app != null) { - app.setChecked(true); - } - } - ThreadUtils.postOnBackgroundThread(() -> { - reloadData(); - final List recentApps = getDisplayableRecentAppList(); - ThreadUtils.postOnMainThread(() -> { - if (recentApps != null && !recentApps.isEmpty()) { - displayRecentApps(prefContext, recentApps); - } else { - displayOnlyAllAppsLink(); - } - }); - }); - } - - @VisibleForTesting - void reloadData() { - mApps = new ArrayList<>(); - mCal = Calendar.getInstance(); - mCal.add(Calendar.DAY_OF_YEAR, -DAYS); - for (int userId : mUserIds) { - UsageEvents events = null; - try { - events = mUsageStatsManager.queryEventsForUser(mCal.getTimeInMillis(), - System.currentTimeMillis(), userId, mContext.getPackageName()); - } catch (RemoteException e) { - e.printStackTrace(); - } - if (events != null) { - ArrayMap aggregatedStats = new ArrayMap<>(); - - UsageEvents.Event event = new UsageEvents.Event(); - while (events.hasNextEvent()) { - events.getNextEvent(event); - - if (event.getEventType() == UsageEvents.Event.NOTIFICATION_INTERRUPTION) { - NotifyingApp app = - aggregatedStats.get(getKey(userId, event.getPackageName())); - if (app == null) { - app = new NotifyingApp(); - aggregatedStats.put(getKey(userId, event.getPackageName()), app); - app.setPackage(event.getPackageName()); - app.setUserId(userId); - } - if (event.getTimeStamp() > app.getLastNotified()) { - app.setLastNotified(event.getTimeStamp()); - } - } - - } - - mApps.addAll(aggregatedStats.values()); - } - } - } - - private static String getKey(int userId, String pkg) { - return userId + "|" + pkg; - } - - private void displayOnlyAllAppsLink() { - mCategory.setTitle(null); - mSeeAllPref.setTitle(R.string.notifications_title); - mSeeAllPref.setIcon(null); - int prefCount = mCategory.getPreferenceCount(); - for (int i = prefCount - 1; i >= 0; i--) { - final Preference pref = mCategory.getPreference(i); - if (!TextUtils.equals(pref.getKey(), KEY_SEE_ALL)) { - mCategory.removePreference(pref); - } - } - } - - private void displayRecentApps(Context prefContext, List recentApps) { - mCategory.setTitle(R.string.recent_notifications); - mSeeAllPref.setSummary(null); - mSeeAllPref.setIcon(R.drawable.ic_chevron_right_24dp); - - int keyIndex = 1; - final int recentAppsCount = recentApps.size(); - for (int i = 0; i < recentAppsCount; i++, keyIndex++) { - final NotifyingApp app = recentApps.get(i); - // Bind recent apps to existing prefs if possible, or create a new pref. - final String pkgName = app.getPackage(); - final ApplicationsState.AppEntry appEntry = - mApplicationsState.getEntry(app.getPackage(), app.getUserId()); - if (appEntry == null || appEntry.label == null) { - continue; - } - - PrimarySwitchPreference pref = mCategory.findPreference(KEY_PLACEHOLDER + keyIndex); - pref.setTitle(appEntry.label); - pref.setIcon(mIconDrawableFactory.getBadgedIcon(appEntry.info)); - pref.setIconSize(TwoTargetPreference.ICON_SIZE_SMALL); - pref.setSummary(StringUtil.formatRelativeTime(mContext, - System.currentTimeMillis() - app.getLastNotified(), true)); - Bundle args = new Bundle(); - args.putString(AppInfoBase.ARG_PACKAGE_NAME, pkgName); - args.putInt(AppInfoBase.ARG_PACKAGE_UID, appEntry.info.uid); - pref.setOnPreferenceClickListener(preference -> { - new SubSettingLauncher(mHost.getActivity()) - .setDestination(AppNotificationSettings.class.getName()) - .setTitleRes(R.string.notifications_title) - .setArguments(args) - .setUserHandle(new UserHandle(UserHandle.getUserId(appEntry.info.uid))) - .setSourceMetricsCategory( - SettingsEnums.MANAGE_APPLICATIONS_NOTIFICATIONS) - .launch(); - return true; - }); - pref.setSwitchEnabled(mNotificationBackend.isBlockable(mContext, appEntry.info)); - pref.setOnPreferenceChangeListener((preference, newValue) -> { - mNotificationBackend.setNotificationsEnabledForPackage( - pkgName, appEntry.info.uid, (Boolean) newValue); - return true; - }); - pref.setChecked( - !mNotificationBackend.getNotificationsBanned(pkgName, appEntry.info.uid)); - - } - // If there are less than SHOW_RECENT_APP_COUNT recent apps, remove placeholders - for (int i = keyIndex; i <= SHOW_RECENT_APP_COUNT; i++) { - mCategory.removePreferenceRecursively(KEY_PLACEHOLDER + i); - } - } - - private List getDisplayableRecentAppList() { - Collections.sort(mApps); - List displayableApps = new ArrayList<>(SHOW_RECENT_APP_COUNT); - int count = 0; - for (NotifyingApp app : mApps) { - try { - final ApplicationsState.AppEntry appEntry = mApplicationsState.getEntry( - app.getPackage(), app.getUserId()); - if (appEntry == null) { - continue; - } - displayableApps.add(app); - count++; - if (count >= SHOW_RECENT_APP_COUNT) { - break; - } - } catch (Exception e) { - Slog.e(TAG, "Failed to find app " + app.getPackage() + "/" + app.getUserId(), e); - } - } - return displayableApps; - } -} diff --git a/tests/robotests/src/com/android/settings/notification/RecentNotifyingAppsPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/RecentNotifyingAppsPreferenceControllerTest.java deleted file mode 100644 index f6eb93b7f29..00000000000 --- a/tests/robotests/src/com/android/settings/notification/RecentNotifyingAppsPreferenceControllerTest.java +++ /dev/null @@ -1,389 +0,0 @@ -/* - * Copyright (C) 2018 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.settings.notification; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.ArgumentMatchers.anyLong; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.ArgumentMatchers.argThat; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.doNothing; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import android.app.usage.IUsageStatsManager; -import android.app.usage.UsageEvents; -import android.app.usage.UsageEvents.Event; -import android.content.Context; -import android.content.Intent; -import android.content.pm.ApplicationInfo; -import android.content.pm.PackageManager; -import android.content.pm.ResolveInfo; -import android.os.Parcel; -import android.os.UserHandle; -import android.os.UserManager; -import android.service.notification.NotifyingApp; -import android.text.TextUtils; - -import com.android.settings.R; -import com.android.settings.widget.PrimarySwitchPreference; -import com.android.settingslib.applications.AppUtils; -import com.android.settingslib.applications.ApplicationsState; -import com.android.settingslib.applications.instantapps.InstantAppDataProvider; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.ArgumentCaptor; -import org.mockito.ArgumentMatcher; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; -import org.robolectric.annotation.Config; -import org.robolectric.util.ReflectionHelpers; - -import java.util.ArrayList; -import java.util.List; - -import androidx.fragment.app.Fragment; -import androidx.fragment.app.FragmentActivity; -import androidx.preference.Preference; -import androidx.preference.PreferenceCategory; -import androidx.preference.PreferenceScreen; - -@RunWith(RobolectricTestRunner.class) -public class RecentNotifyingAppsPreferenceControllerTest { - - @Mock - private PreferenceScreen mScreen; - @Mock - private PreferenceCategory mCategory; - private PrimarySwitchPreference mApp1; - private PrimarySwitchPreference mApp2; - private PrimarySwitchPreference mApp3; - @Mock - private Preference mSeeAllPref; - @Mock - private UserManager mUserManager; - @Mock - private ApplicationsState mAppState; - @Mock - private PackageManager mPackageManager; - @Mock - private ApplicationsState.AppEntry mAppEntry; - @Mock - private ApplicationInfo mApplicationInfo; - @Mock - private NotificationBackend mBackend; - @Mock - private Fragment mHost; - @Mock - private FragmentActivity mActivity; - @Mock - private IUsageStatsManager mIUsageStatsManager; - - private Context mContext; - private RecentNotifyingAppsPreferenceController mController; - - @Before - public void setUp() { - MockitoAnnotations.initMocks(this); - mContext = spy(RuntimeEnvironment.application); - doReturn(mUserManager).when(mContext).getSystemService(Context.USER_SERVICE); - doReturn(mPackageManager).when(mContext).getPackageManager(); - when(mUserManager.getProfileIdsWithDisabled(0)).thenReturn(new int[] {0}); - - mController = new RecentNotifyingAppsPreferenceController( - mContext, mBackend, mIUsageStatsManager, mUserManager, mAppState, mHost); - when(mScreen.findPreference(anyString())).thenReturn(mCategory); - mApp1 = new PrimarySwitchPreference(mContext); - mApp1.setKey("app1"); - mApp2 = new PrimarySwitchPreference(mContext); - mApp2.setKey("app2"); - mApp3 = new PrimarySwitchPreference(mContext); - mApp3.setKey("app3"); - when(mCategory.findPreference("app1")).thenReturn(mApp1); - when(mCategory.findPreference("app2")).thenReturn(mApp2); - when(mCategory.findPreference("app3")).thenReturn(mApp3); - - when(mScreen.findPreference(RecentNotifyingAppsPreferenceController.KEY_SEE_ALL)) - .thenReturn(mSeeAllPref); - when(mCategory.getContext()).thenReturn(mContext); - when(mHost.getActivity()).thenReturn(mActivity); - } - - @Test - public void isAlwaysAvailable() { - assertThat(mController.isAvailable()).isTrue(); - } - - @Test - public void onDisplayAndUpdateState_shouldRefreshUi() { - mController = spy(new RecentNotifyingAppsPreferenceController( - mContext, null, mIUsageStatsManager, mUserManager, (ApplicationsState) null, null)); - - doNothing().when(mController).refreshUi(mContext); - - mController.displayPreference(mScreen); - mController.updateState(mCategory); - - verify(mController, times(2)).refreshUi(mContext); - } - - @Test - @Config(qualifiers = "mcc999") - public void display_shouldNotShowRecents_showAppInfoPreference() { - mController.displayPreference(mScreen); - - verify(mCategory, never()).addPreference(any(Preference.class)); - verify(mCategory).setTitle(null); - verify(mSeeAllPref).setTitle(R.string.notifications_title); - verify(mSeeAllPref).setIcon(null); - } - - @Test - public void display_showRecents() throws Exception { - List events = new ArrayList<>(); - Event app = new Event(); - app.mEventType = Event.NOTIFICATION_INTERRUPTION; - app.mPackage = "a"; - app.mTimeStamp = System.currentTimeMillis(); - events.add(app); - Event app1 = new Event(); - app1.mEventType = Event.NOTIFICATION_INTERRUPTION; - app1.mPackage = "com.android.settings"; - app1.mTimeStamp = System.currentTimeMillis(); - events.add(app1); - Event app2 = new Event(); - app2.mEventType = Event.NOTIFICATION_INTERRUPTION; - app2.mPackage = "pkg.class2"; - app2.mTimeStamp = System.currentTimeMillis() - 1000; - events.add(app2); - ApplicationsState.AppEntry app1Entry = mock(ApplicationsState.AppEntry.class); - ApplicationsState.AppEntry app2Entry = mock(ApplicationsState.AppEntry.class); - app1Entry.info = mApplicationInfo; - app1Entry.label = "app 1"; - app2Entry.info = mApplicationInfo; - app2Entry.label = "app 2"; - - // app1, app2 are valid apps. app3 is invalid. - when(mAppState.getEntry(app.getPackageName(), UserHandle.myUserId())) - .thenReturn(app1Entry); - when(mAppState.getEntry(app1.getPackageName(), UserHandle.myUserId())) - .thenReturn(app2Entry); - when(mAppState.getEntry(app2.getPackageName(), UserHandle.myUserId())) - .thenReturn(null); - when(mPackageManager.resolveActivity(any(Intent.class), anyInt())).thenReturn( - new ResolveInfo()); - - UsageEvents usageEvents = getUsageEvents( - new String[] {app.getPackageName(), app1.getPackageName(), app2.getPackageName()}, - events); - when(mIUsageStatsManager.queryEventsForUser(anyLong(), anyLong(), anyInt(), anyString())) - .thenReturn(usageEvents); - - mAppEntry.info = mApplicationInfo; - - mController.displayPreference(mScreen); - - verify(mCategory).setTitle(R.string.recent_notifications); - // Only add app1 & app2. app3 skipped because it's invalid app. - assertThat(mApp1.getTitle()).isEqualTo(app1Entry.label); - assertThat(mApp2.getTitle()).isEqualTo(app2Entry.label); - - verify(mCategory).removePreferenceRecursively(mApp3.getKey()); - - verify(mSeeAllPref).setSummary(null); - verify(mSeeAllPref).setIcon(R.drawable.ic_chevron_right_24dp); - } - - @Test - public void display_noCrashIfLessThan3() throws Exception { - List events = new ArrayList<>(); - Event app = new Event(); - app.mEventType = Event.NOTIFICATION_INTERRUPTION; - app.mPackage = "a"; - app.mTimeStamp = System.currentTimeMillis(); - events.add(app); - ApplicationsState.AppEntry app1Entry = mock(ApplicationsState.AppEntry.class); - app1Entry.info = mApplicationInfo; - app1Entry.label = "app 1"; - - when(mAppState.getEntry(app.getPackageName(), UserHandle.myUserId())) - .thenReturn(app1Entry); - when(mPackageManager.resolveActivity(any(Intent.class), anyInt())).thenReturn( - new ResolveInfo()); - - UsageEvents usageEvents = getUsageEvents( - new String[] {app.getPackageName()}, - events); - when(mIUsageStatsManager.queryEventsForUser(anyLong(), anyLong(), anyInt(), anyString())) - .thenReturn(usageEvents); - - mAppEntry.info = mApplicationInfo; - - mController.displayPreference(mScreen); - - verify(mCategory).setTitle(R.string.recent_notifications); - // Only add app1 & app2. app3 skipped because it's invalid app. - assertThat(mApp1.getTitle()).isEqualTo(app1Entry.label); - - verify(mCategory).removePreferenceRecursively("app2"); - - mController.refreshUi(mContext); - } - - @Test - public void display_showRecentsWithInstantApp() throws Exception { - List events = new ArrayList<>(); - Event app = new Event(); - app.mEventType = Event.NOTIFICATION_INTERRUPTION; - app.mPackage = "com.foo.bar"; - app.mTimeStamp = System.currentTimeMillis(); - events.add(app); - Event app1 = new Event(); - app1.mEventType = Event.NOTIFICATION_INTERRUPTION; - app1.mPackage = "com.foo.barinstant"; - app1.mTimeStamp = System.currentTimeMillis() - 200; - events.add(app1); - UsageEvents usageEvents = getUsageEvents( - new String[] {"com.foo.bar", "com.foo.barinstant"}, events); - when(mIUsageStatsManager.queryEventsForUser(anyLong(), anyLong(), anyInt(), anyString())) - .thenReturn(usageEvents); - - ApplicationsState.AppEntry appEntry = mock(ApplicationsState.AppEntry.class); - ApplicationsState.AppEntry app1Entry = mock(ApplicationsState.AppEntry.class); - appEntry.info = mApplicationInfo; - appEntry.label = "app 1"; - app1Entry.info = mApplicationInfo; - app1Entry.label = "app 2"; - - when(mAppState.getEntry( - app.getPackageName(), UserHandle.myUserId())).thenReturn(appEntry); - when(mAppState.getEntry( - app1.getPackageName(), UserHandle.myUserId())).thenReturn(app1Entry); - - // Only the regular app app1 should have its intent resolve. - when(mPackageManager.resolveActivity(argThat(intentMatcher(app.getPackageName())), - anyInt())).thenReturn(new ResolveInfo()); - - // Make sure app2 is considered an instant app. - ReflectionHelpers.setStaticField(AppUtils.class, "sInstantAppDataProvider", - (InstantAppDataProvider) (ApplicationInfo info) -> { - if (info == app1Entry.info) { - return true; - } else { - return false; - } - }); - - mController.displayPreference(mScreen); - - assertThat(mApp1.getTitle()).isEqualTo(appEntry.label); - assertThat(mApp1.getSummary()).isEqualTo("Just now"); - assertThat(mApp2.getTitle()).isEqualTo(app1Entry.label); - - verify(mCategory).removePreferenceRecursively(mApp3.getKey()); - } - - @Test - public void reloadData() throws Exception { - when(mUserManager.getProfileIdsWithDisabled(0)).thenReturn(new int[] {0, 10}); - - mController = new RecentNotifyingAppsPreferenceController( - mContext, mBackend, mIUsageStatsManager, mUserManager, mAppState, mHost); - - List events = new ArrayList<>(); - Event app = new Event(); - app.mEventType = Event.NOTIFICATION_INTERRUPTION; - app.mPackage = "b"; - app.mTimeStamp = 1; - events.add(app); - Event app1 = new Event(); - app1.mEventType = Event.MAX_EVENT_TYPE; - app1.mPackage = "com.foo.bar"; - app1.mTimeStamp = 10; - events.add(app1); - UsageEvents usageEvents = getUsageEvents( - new String[] {"b", "com.foo.bar"}, events); - when(mIUsageStatsManager.queryEventsForUser(anyLong(), anyLong(), eq(0), anyString())) - .thenReturn(usageEvents); - - List events10 = new ArrayList<>(); - Event app10 = new Event(); - app10.mEventType = Event.NOTIFICATION_INTERRUPTION; - app10.mPackage = "a"; - app10.mTimeStamp = 2; - events10.add(app10); - Event app10a = new Event(); - app10a.mEventType = Event.NOTIFICATION_INTERRUPTION; - app10a.mPackage = "a"; - app10a.mTimeStamp = 20; - events10.add(app10a); - UsageEvents usageEvents10 = getUsageEvents( - new String[] {"a"}, events10); - when(mIUsageStatsManager.queryEventsForUser(anyLong(), anyLong(), eq(10), anyString())) - .thenReturn(usageEvents10); - - mController.reloadData(); - - assertThat(mController.mApps.size()).isEqualTo(2); - boolean foundPkg0 = false; - boolean foundPkg10 = false; - for (NotifyingApp notifyingApp : mController.mApps) { - if (notifyingApp.getLastNotified() == 20 - && notifyingApp.getPackage().equals("a") - && notifyingApp.getUserId() == 10) { - foundPkg10 = true; - } - if (notifyingApp.getLastNotified() == 1 - && notifyingApp.getPackage().equals("b") - && notifyingApp.getUserId() == 0) { - foundPkg0 = true; - } - } - assertThat(foundPkg0).isTrue(); - assertThat(foundPkg10).isTrue(); - } - - private static ArgumentMatcher summaryMatches(String expected) { - return preference -> TextUtils.equals(expected, preference.getSummary()); - } - - // Used for matching an intent with a specific package name. - private static ArgumentMatcher intentMatcher(String packageName) { - return intent -> packageName.equals(intent.getPackage()); - } - - private UsageEvents getUsageEvents(String[] pkgs, List events) { - UsageEvents usageEvents = new UsageEvents(events, pkgs); - Parcel parcel = Parcel.obtain(); - parcel.setDataPosition(0); - usageEvents.writeToParcel(parcel, 0); - parcel.setDataPosition(0); - return UsageEvents.CREATOR.createFromParcel(parcel); - } -}