diff --git a/AndroidManifest.xml b/AndroidManifest.xml index e2accdd2443..27788dcbaa1 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -2661,6 +2661,23 @@ android:resource="@string/sound_dashboard_summary"/> + + + + + + + + + + + + diff --git a/res/menu/manage_apps.xml b/res/menu/manage_apps.xml index 02ee2bbefdd..99dba37d3a4 100644 --- a/res/menu/manage_apps.xml +++ b/res/menu/manage_apps.xml @@ -37,6 +37,14 @@ android:id="@+id/sort_order_size" android:title="@string/sort_order_size" android:showAsAction="never" /> + + Sort by name Sort by size + + Most recent + + Most frequent Show running services @@ -7308,6 +7312,13 @@ Notification assistant + + ~%1$s sent daily + + ~%1$s sent weekly + + Never + Notification access diff --git a/res/xml/configure_notification_settings.xml b/res/xml/configure_notification_settings.xml index d7153efd2ec..73c1d6fc89b 100644 --- a/res/xml/configure_notification_settings.xml +++ b/res/xml/configure_notification_settings.xml @@ -69,14 +69,13 @@ - - + diff --git a/src/com/android/settings/Settings.java b/src/com/android/settings/Settings.java index 03853d1d4f7..836fa754069 100644 --- a/src/com/android/settings/Settings.java +++ b/src/com/android/settings/Settings.java @@ -106,6 +106,7 @@ public class Settings extends SettingsActivity { public static class ZenModeEventRuleSettingsActivity extends SettingsActivity { /* empty */ } public static class SoundSettingsActivity extends SettingsActivity { /* empty */ } public static class ConfigureNotificationSettingsActivity extends SettingsActivity { /* empty */ } + public static class NotificationAppListActivity extends SettingsActivity { /* empty */ } public static class AppNotificationSettingsActivity extends SettingsActivity { /* empty */ } public static class ChannelNotificationSettingsActivity extends SettingsActivity { /* empty */ } public static class ChannelGroupNotificationSettingsActivity extends SettingsActivity { /* empty */ } diff --git a/src/com/android/settings/applications/AppStateNotificationBridge.java b/src/com/android/settings/applications/AppStateNotificationBridge.java index b0c065ae0cb..238c135df75 100644 --- a/src/com/android/settings/applications/AppStateNotificationBridge.java +++ b/src/com/android/settings/applications/AppStateNotificationBridge.java @@ -15,70 +15,191 @@ */ package com.android.settings.applications; -import android.app.Notification; -import android.app.NotificationManager; +import android.app.usage.UsageEvents; +import android.app.usage.UsageStatsManager; import android.content.Context; -import android.content.pm.PackageManager; -import android.os.UserHandle; -import android.service.notification.NotificationListenerService; +import android.text.format.DateUtils; +import android.util.ArrayMap; -import com.android.internal.widget.LockPatternUtils; -import com.android.settings.notification.NotificationBackend; -import com.android.settings.notification.NotificationBackend.AppRow; +import com.android.settings.R; import com.android.settingslib.applications.ApplicationsState; import com.android.settingslib.applications.ApplicationsState.AppEntry; import com.android.settingslib.applications.ApplicationsState.AppFilter; +import com.android.settingslib.utils.StringUtil; import java.util.ArrayList; +import java.util.Comparator; +import java.util.Map; /** - * Connects the info provided by ApplicationsState and the NotificationBackend. + * Connects the info provided by ApplicationsState and UsageStatsManager. * Also provides app filters that can use the notification data. */ public class AppStateNotificationBridge extends AppStateBaseBridge { - private final NotificationBackend mNotifBackend; - private final PackageManager mPm; - private final Context mContext; + private UsageStatsManager mUsageStatsManager; + private static final int DAYS_TO_CHECK = 7; - public AppStateNotificationBridge(Context context, ApplicationsState appState, - Callback callback, NotificationBackend notifBackend) { + public AppStateNotificationBridge(ApplicationsState appState, + Callback callback, UsageStatsManager usageStatsManager) { super(appState, callback); - mContext = context; - mPm = mContext.getPackageManager(); - mNotifBackend = notifBackend; + mUsageStatsManager = usageStatsManager; } @Override protected void loadAllExtraInfo() { ArrayList apps = mAppSession.getAllApps(); - final int N = apps.size(); - for (int i = 0; i < N; i++) { - AppEntry app = apps.get(i); - app.extraInfo = mNotifBackend.loadAppRow(mContext, mPm, app.info); + if (apps == null) return; + + final Map map = getAggregatedUsageEvents(); + for (AppEntry entry : apps) { + NotificationsSentState stats = map.get(entry.info.packageName); + calculateAvgSentCounts(stats); + entry.extraInfo = stats; } } @Override - protected void updateExtraInfo(AppEntry app, String pkg, int uid) { - app.extraInfo = mNotifBackend.loadAppRow(mContext, mPm, app.info); + protected void updateExtraInfo(AppEntry entry, String pkg, int uid) { + Map map = getAggregatedUsageEvents(); + NotificationsSentState stats = map.get(entry.info.packageName); + calculateAvgSentCounts(stats); + entry.extraInfo = stats; } - public static final AppFilter FILTER_APP_NOTIFICATION_BLOCKED = new AppFilter() { + public static CharSequence getSummary(Context context, NotificationsSentState state, + boolean sortByRecency) { + if (sortByRecency) { + if (state.lastSent == 0) { + return context.getString(R.string.notifications_sent_never); + } + return StringUtil.formatRelativeTime( + context, System.currentTimeMillis() - state.lastSent, true); + } else { + if (state.avgSentWeekly > 0) { + return context.getString(R.string.notifications_sent_weekly, state.avgSentWeekly); + } + return context.getString(R.string.notifications_sent_daily, state.avgSentDaily); + } + } + + private void calculateAvgSentCounts(NotificationsSentState stats) { + if (stats != null) { + stats.avgSentDaily = Math.round((float) stats.sentCount / DAYS_TO_CHECK); + if (stats.sentCount < DAYS_TO_CHECK) { + stats.avgSentWeekly = stats.sentCount; + } + } + } + + protected Map getAggregatedUsageEvents() { + ArrayMap aggregatedStats = new ArrayMap<>(); + + long now = System.currentTimeMillis(); + long startTime = now - (DateUtils.DAY_IN_MILLIS * DAYS_TO_CHECK); + UsageEvents events = mUsageStatsManager.queryEvents(startTime, now); + if (events != null) { + UsageEvents.Event event = new UsageEvents.Event(); + while (events.hasNextEvent()) { + events.getNextEvent(event); + NotificationsSentState stats = aggregatedStats.get(event.getPackageName()); + if (stats == null) { + stats = new NotificationsSentState(); + aggregatedStats.put(event.getPackageName(), stats); + } + + if (event.getEventType() == UsageEvents.Event.NOTIFICATION_INTERRUPTION) { + if (event.getTimeStamp() > stats.lastSent) { + stats.lastSent = event.getTimeStamp(); + } + stats.sentCount++; + } + + } + } + return aggregatedStats; + } + + private static NotificationsSentState getNotificationsSentState(AppEntry entry) { + if (entry == null || entry.extraInfo == null) { + return null; + } + if (entry.extraInfo instanceof NotificationsSentState) { + return (NotificationsSentState) entry.extraInfo; + } + return null; + } + + public static final AppFilter FILTER_APP_NOTIFICATION_RECENCY = new AppFilter() { @Override public void init() { } @Override public boolean filterApp(AppEntry info) { - if (info == null || info.extraInfo == null) { - return false; - } - if (info.extraInfo instanceof AppRow) { - AppRow row = (AppRow) info.extraInfo; - return row.banned; + NotificationsSentState state = getNotificationsSentState(info); + if (state != null) { + return state.lastSent != 0; } return false; } }; + + public static final AppFilter FILTER_APP_NOTIFICATION_FREQUENCY = new AppFilter() { + @Override + public void init() { + } + + @Override + public boolean filterApp(AppEntry info) { + NotificationsSentState state = getNotificationsSentState(info); + if (state != null) { + return state.sentCount != 0; + } + return false; + } + }; + + public static final Comparator RECENT_NOTIFICATION_COMPARATOR + = new Comparator() { + @Override + public int compare(AppEntry object1, AppEntry object2) { + NotificationsSentState state1 = getNotificationsSentState(object1); + NotificationsSentState state2 = getNotificationsSentState(object2); + if (state1 == null && state2 != null) return -1; + if (state1 != null && state2 == null) return 1; + if (state1 != null && state2 != null) { + if (state1.lastSent < state2.lastSent) return 1; + if (state1.lastSent > state2.lastSent) return -1; + } + return ApplicationsState.ALPHA_COMPARATOR.compare(object1, object2); + } + }; + + public static final Comparator FREQUENCY_NOTIFICATION_COMPARATOR + = new Comparator() { + @Override + public int compare(AppEntry object1, AppEntry object2) { + NotificationsSentState state1 = getNotificationsSentState(object1); + NotificationsSentState state2 = getNotificationsSentState(object2); + if (state1 == null && state2 != null) return -1; + if (state1 != null && state2 == null) return 1; + if (state1 != null && state2 != null) { + if (state1.sentCount < state2.sentCount) return 1; + if (state1.sentCount > state2.sentCount) return -1; + } + return ApplicationsState.ALPHA_COMPARATOR.compare(object1, object2); + } + }; + + /** + * NotificationsSentState contains how often an app sends notifications and how recently it sent + * one. + */ + public static class NotificationsSentState { + public int avgSentDaily = 0; + public int avgSentWeekly = 0; + public long lastSent = 0; + public int sentCount = 0; + } } diff --git a/src/com/android/settings/applications/manageapplications/AppFilterRegistry.java b/src/com/android/settings/applications/manageapplications/AppFilterRegistry.java index 8ebb7a41b03..b05e8411455 100644 --- a/src/com/android/settings/applications/manageapplications/AppFilterRegistry.java +++ b/src/com/android/settings/applications/manageapplications/AppFilterRegistry.java @@ -41,7 +41,8 @@ public class AppFilterRegistry { FILTER_APPS_ENABLED, FILTER_APPS_INSTANT, FILTER_APPS_DISABLED, - FILTER_APPS_BLOCKED, + FILTER_APPS_RECENT, + FILTER_APPS_FREQUENT, FILTER_APPS_PERSONAL, FILTER_APPS_WORK, FILTER_APPS_USAGE_ACCESS, @@ -60,23 +61,24 @@ public class AppFilterRegistry { public static final int FILTER_APPS_ENABLED = 3; public static final int FILTER_APPS_INSTANT = 4; public static final int FILTER_APPS_DISABLED = 5; - public static final int FILTER_APPS_BLOCKED = 6; - public static final int FILTER_APPS_PERSONAL = 7; - public static final int FILTER_APPS_WORK = 8; - public static final int FILTER_APPS_USAGE_ACCESS = 9; - public static final int FILTER_APPS_WITH_OVERLAY = 10; - public static final int FILTER_APPS_WRITE_SETTINGS = 11; - public static final int FILTER_APPS_INSTALL_SOURCES = 12; - public static final int FILTER_APP_HAS_DIRECTORY_ACCESS = 13; - public static final int FILTER_APP_CAN_CHANGE_WIFI_STATE = 14; - // Next id: 15 + public static final int FILTER_APPS_RECENT = 6; + public static final int FILTER_APPS_FREQUENT = 7; + public static final int FILTER_APPS_PERSONAL = 8; + public static final int FILTER_APPS_WORK = 9; + public static final int FILTER_APPS_USAGE_ACCESS = 10; + public static final int FILTER_APPS_WITH_OVERLAY = 11; + public static final int FILTER_APPS_WRITE_SETTINGS = 12; + public static final int FILTER_APPS_INSTALL_SOURCES = 13; + public static final int FILTER_APP_HAS_DIRECTORY_ACCESS = 14; + public static final int FILTER_APP_CAN_CHANGE_WIFI_STATE = 15; + // Next id: 16 private static AppFilterRegistry sRegistry; private final AppFilterItem[] mFilters; private AppFilterRegistry() { - mFilters = new AppFilterItem[15]; + mFilters = new AppFilterItem[16]; // High power whitelist, on mFilters[FILTER_APPS_POWER_WHITELIST] = new AppFilterItem( @@ -118,11 +120,17 @@ public class AppFilterRegistry { FILTER_APPS_INSTANT, R.string.filter_instant_apps); - // Blocked Notifications - mFilters[FILTER_APPS_BLOCKED] = new AppFilterItem( - AppStateNotificationBridge.FILTER_APP_NOTIFICATION_BLOCKED, - FILTER_APPS_BLOCKED, - R.string.filter_notif_blocked_apps); + // Recent Notifications + mFilters[FILTER_APPS_RECENT] = new AppFilterItem( + AppStateNotificationBridge.FILTER_APP_NOTIFICATION_RECENCY, + FILTER_APPS_RECENT, + R.string.sort_order_recent_notification); + + // Frequent Notifications + mFilters[FILTER_APPS_FREQUENT] = new AppFilterItem( + AppStateNotificationBridge.FILTER_APP_NOTIFICATION_FREQUENCY, + FILTER_APPS_FREQUENT, + R.string.sort_order_frequent_notification); // Personal mFilters[FILTER_APPS_PERSONAL] = new AppFilterItem( @@ -196,6 +204,8 @@ public class AppFilterRegistry { return FILTER_APP_HAS_DIRECTORY_ACCESS; case ManageApplications.LIST_TYPE_WIFI_ACCESS: return FILTER_APP_CAN_CHANGE_WIFI_STATE; + case ManageApplications.LIST_TYPE_NOTIFICATION: + return FILTER_APPS_RECENT; default: return FILTER_APPS_ALL; } diff --git a/src/com/android/settings/applications/manageapplications/ManageApplications.java b/src/com/android/settings/applications/manageapplications/ManageApplications.java index b0857c5cc84..d144169af2c 100644 --- a/src/com/android/settings/applications/manageapplications/ManageApplications.java +++ b/src/com/android/settings/applications/manageapplications/ManageApplications.java @@ -17,11 +17,13 @@ package com.android.settings.applications.manageapplications; import static com.android.settings.applications.manageapplications.AppFilterRegistry - .FILTER_APPS_BLOCKED; + .FILTER_APPS_ALL; import static com.android.settings.applications.manageapplications.AppFilterRegistry .FILTER_APPS_DISABLED; import static com.android.settings.applications.manageapplications.AppFilterRegistry .FILTER_APPS_ENABLED; +import static com.android.settings.applications.manageapplications.AppFilterRegistry + .FILTER_APPS_FREQUENT; import static com.android.settings.applications.manageapplications.AppFilterRegistry .FILTER_APPS_INSTANT; import static com.android.settings.applications.manageapplications.AppFilterRegistry @@ -30,12 +32,15 @@ import static com.android.settings.applications.manageapplications.AppFilterRegi .FILTER_APPS_POWER_WHITELIST; import static com.android.settings.applications.manageapplications.AppFilterRegistry .FILTER_APPS_POWER_WHITELIST_ALL; +import static com.android.settings.applications.manageapplications.AppFilterRegistry + .FILTER_APPS_RECENT; import static com.android.settings.applications.manageapplications.AppFilterRegistry .FILTER_APPS_WORK; import android.annotation.Nullable; import android.annotation.StringRes; import android.app.Activity; +import android.app.usage.UsageStatsManager; import android.content.Context; import android.content.Intent; import android.content.pm.ApplicationInfo; @@ -81,6 +86,7 @@ import com.android.settings.applications.AppStateBaseBridge; import com.android.settings.applications.AppStateDirectoryAccessBridge; import com.android.settings.applications.AppStateInstallAppsBridge; import com.android.settings.applications.AppStateNotificationBridge; +import com.android.settings.applications.AppStateNotificationBridge.NotificationsSentState; import com.android.settings.applications.AppStateOverlayBridge; import com.android.settings.applications.AppStatePowerBridge; import com.android.settings.applications.AppStateUsageBridge; @@ -92,7 +98,6 @@ import com.android.settings.applications.DirectoryAccessDetails; import com.android.settings.applications.InstalledAppCounter; import com.android.settings.applications.UsageAccessDetails; import com.android.settings.applications.appinfo.AppInfoDashboardFragment; -import com.android.settings.applications.appinfo.AppNotificationPreferenceController; import com.android.settings.applications.appinfo.DrawOverlayDetails; import com.android.settings.applications.appinfo.ExternalSourcesDetails; import com.android.settings.applications.appinfo.WriteSettingsDetails; @@ -102,8 +107,6 @@ import com.android.settings.dashboard.SummaryLoader; import com.android.settings.fuelgauge.HighPowerDetail; import com.android.settings.notification.AppNotificationSettings; import com.android.settings.notification.ConfigureNotificationSettings; -import com.android.settings.notification.NotificationBackend; -import com.android.settings.notification.NotificationBackend.AppRow; import com.android.settings.widget.LoadingViewController; import com.android.settings.wifi.AppStateChangeWifiStateBridge; import com.android.settings.wifi.ChangeWifiStateDetails; @@ -217,7 +220,7 @@ public class ManageApplications extends InstrumentedFragment private View mSpinnerHeader; private Spinner mFilterSpinner; private FilterSpinnerAdapter mFilterAdapter; - private NotificationBackend mNotifBackend; + private UsageStatsManager mUsageStatsManager; private ResetAppsHelper mResetAppsHelper; private String mVolumeUuid; private int mStorageType; @@ -283,6 +286,12 @@ public class ManageApplications extends InstrumentedFragment } else if (className.equals(Settings.ChangeWifiStateActivity.class.getName())) { mListType = LIST_TYPE_WIFI_ACCESS; screenTitle = R.string.change_wifi_state_title; + } else if (className.equals(Settings.NotificationAppListActivity.class.getName())) { + mListType = LIST_TYPE_NOTIFICATION; + mUsageStatsManager = + (UsageStatsManager) getContext().getSystemService(Context.USAGE_STATS_SERVICE); + mSortOrder = R.id.sort_order_recent_notification; + screenTitle = R.string.app_notifications_title; } else { if (screenTitle == -1) { screenTitle = R.string.application_info_label; @@ -383,7 +392,9 @@ public class ManageApplications extends InstrumentedFragment } } if (mListType == LIST_TYPE_NOTIFICATION) { - mFilterAdapter.enableFilter(FILTER_APPS_BLOCKED); + mFilterAdapter.enableFilter(FILTER_APPS_RECENT); + mFilterAdapter.enableFilter(FILTER_APPS_FREQUENT); + mFilterAdapter.disableFilter(FILTER_APPS_ALL); } if (mListType == LIST_TYPE_HIGH_POWER) { mFilterAdapter.enableFilter(FILTER_APPS_POWER_WHITELIST_ALL); @@ -579,6 +590,7 @@ public class ManageApplications extends InstrumentedFragment HelpUtils.prepareHelpMenuItem(activity, menu, getHelpResource(), getClass().getName()); mOptionsMenu = menu; inflater.inflate(R.menu.manage_apps, menu); + updateOptionsMenu(); } @@ -620,6 +632,10 @@ public class ManageApplications extends InstrumentedFragment && mListType != LIST_TYPE_HIGH_POWER); mOptionsMenu.findItem(R.id.reset_app_preferences).setVisible(mListType == LIST_TYPE_MAIN); + + // Hide notification menu items, because sorting happens when filtering + mOptionsMenu.findItem(R.id.sort_order_recent_notification).setVisible(false); + mOptionsMenu.findItem(R.id.sort_order_frequent_notification).setVisible(false); } @Override @@ -846,8 +862,8 @@ public class ManageApplications extends InstrumentedFragment mContext = manageApplications.getActivity(); mAppFilter = appFilter; if (mManageApplications.mListType == LIST_TYPE_NOTIFICATION) { - mExtraInfoBridge = new AppStateNotificationBridge(mContext, mState, this, - manageApplications.mNotifBackend); + mExtraInfoBridge = new AppStateNotificationBridge(mState, this, + manageApplications.mUsageStatsManager); } else if (mManageApplications.mListType == LIST_TYPE_USAGE_ACCESS) { mExtraInfoBridge = new AppStateUsageBridge(mContext, mState, this); } else if (mManageApplications.mListType == LIST_TYPE_HIGH_POWER) { @@ -877,7 +893,15 @@ public class ManageApplications extends InstrumentedFragment public void setFilter(AppFilterItem appFilter) { mAppFilter = appFilter; - rebuild(); + + // Notification filters require resorting the list + if (FILTER_APPS_FREQUENT == appFilter.getFilterType()) { + rebuild(R.id.sort_order_frequent_notification); + } else if (FILTER_APPS_RECENT == appFilter.getFilterType()) { + rebuild(R.id.sort_order_recent_notification); + } else { + rebuild(); + } } public void setExtraViewController(FileViewHolderController extraViewController) { @@ -995,6 +1019,12 @@ public class ManageApplications extends InstrumentedFragment break; } break; + case R.id.sort_order_recent_notification: + comparatorObj = AppStateNotificationBridge.RECENT_NOTIFICATION_COMPARATOR; + break; + case R.id.sort_order_frequent_notification: + comparatorObj = AppStateNotificationBridge.FREQUENCY_NOTIFICATION_COMPARATOR; + break; default: comparatorObj = ApplicationsState.ALPHA_COMPARATOR; break; @@ -1235,9 +1265,9 @@ public class ManageApplications extends InstrumentedFragment switch (mManageApplications.mListType) { case LIST_TYPE_NOTIFICATION: if (entry.extraInfo != null) { - holder.setSummary( - AppNotificationPreferenceController.getNotificationSummary( - (AppRow) entry.extraInfo, mContext)); + holder.setSummary(AppStateNotificationBridge.getSummary(mContext, + (NotificationsSentState) entry.extraInfo, + (mLastSortMode == R.id.sort_order_recent_notification))); } else { holder.setSummary(null); } diff --git a/tests/robotests/src/com/android/settings/applications/AppStateNotificationBridgeTest.java b/tests/robotests/src/com/android/settings/applications/AppStateNotificationBridgeTest.java new file mode 100644 index 00000000000..e46111a2999 --- /dev/null +++ b/tests/robotests/src/com/android/settings/applications/AppStateNotificationBridgeTest.java @@ -0,0 +1,413 @@ +/* + * 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.applications; + +import static android.text.format.DateUtils.DAY_IN_MILLIS; + +import static com.android.settings.applications.AppStateNotificationBridge + .FILTER_APP_NOTIFICATION_FREQUENCY; +import static com.android.settings.applications.AppStateNotificationBridge + .FILTER_APP_NOTIFICATION_RECENCY; +import static com.android.settings.applications.AppStateNotificationBridge + .FREQUENCY_NOTIFICATION_COMPARATOR; +import static com.android.settings.applications.AppStateNotificationBridge + .RECENT_NOTIFICATION_COMPARATOR; + +import static com.google.common.truth.Truth.assertThat; + +import static junit.framework.Assert.assertFalse; +import static junit.framework.Assert.assertTrue; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import android.app.usage.UsageEvents; +import android.app.usage.UsageEvents.Event; +import android.app.usage.UsageStatsManager; +import android.content.Context; +import android.content.pm.ApplicationInfo; +import android.os.Looper; +import android.os.Parcel; + +import com.android.settings.R; +import com.android.settings.applications.AppStateNotificationBridge.NotificationsSentState; +import com.android.settings.testutils.SettingsRobolectricTestRunner; +import com.android.settingslib.applications.ApplicationsState; +import com.android.settingslib.applications.ApplicationsState.AppEntry; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.RuntimeEnvironment; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +@RunWith(SettingsRobolectricTestRunner.class) +public class AppStateNotificationBridgeTest { + + private static String PKG1 = "pkg1"; + private static String PKG2 = "pkg2"; + + @Mock + private ApplicationsState.Session mSession; + @Mock + private ApplicationsState mState; + @Mock + private UsageStatsManager mUsageStats; + private Context mContext; + private AppStateNotificationBridge mBridge; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + when(mState.newSession(any())).thenReturn(mSession); + when(mState.getBackgroundLooper()).thenReturn(mock(Looper.class)); + mContext = RuntimeEnvironment.application.getApplicationContext(); + + mBridge = new AppStateNotificationBridge(mState, + mock(AppStateBaseBridge.Callback.class), mUsageStats); + } + + private AppEntry getMockAppEntry(String pkg) { + AppEntry entry = mock(AppEntry.class); + entry.info = mock(ApplicationInfo.class); + entry.info.packageName = pkg; + return entry; + } + + private UsageEvents getUsageEvents(List events) { + UsageEvents usageEvents = new UsageEvents(events, new String[] {PKG1, PKG2}); + Parcel parcel = Parcel.obtain(); + parcel.setDataPosition(0); + usageEvents.writeToParcel(parcel, 0); + parcel.setDataPosition(0); + return UsageEvents.CREATOR.createFromParcel(parcel); + } + + @Test + public void testGetAggregatedUsageEvents_noEvents() { + when(mUsageStats.queryEvents(anyLong(), anyLong())).thenReturn(mock(UsageEvents.class)); + + assertThat(mBridge.getAggregatedUsageEvents()).isEmpty(); + } + + @Test + public void testGetAggregatedUsageEvents_onlyNotificationEvents() { + List events = new ArrayList<>(); + Event good = new Event(); + good.mEventType = Event.NOTIFICATION_INTERRUPTION; + good.mPackage = PKG1; + good.mTimeStamp = 1; + events.add(good); + Event bad = new Event(); + bad.mEventType = Event.CHOOSER_ACTION; + bad.mPackage = PKG1; + bad.mTimeStamp = 2; + events.add(bad); + + UsageEvents usageEvents = getUsageEvents(events); + when(mUsageStats.queryEvents(anyLong(), anyLong())).thenReturn(usageEvents); + + Map map = mBridge.getAggregatedUsageEvents(); + assertThat(map.get(PKG1).sentCount).isEqualTo(1); + } + + @Test + public void testGetAggregatedUsageEvents_multipleEventsAgg() { + List events = new ArrayList<>(); + Event good = new Event(); + good.mEventType = Event.NOTIFICATION_INTERRUPTION; + good.mPackage = PKG1; + good.mTimeStamp = 6; + events.add(good); + Event good1 = new Event(); + good1.mEventType = Event.NOTIFICATION_INTERRUPTION; + good1.mPackage = PKG1; + good1.mTimeStamp = 1; + events.add(good1); + + UsageEvents usageEvents = getUsageEvents(events); + when(mUsageStats.queryEvents(anyLong(), anyLong())).thenReturn(usageEvents); + + Map map = mBridge.getAggregatedUsageEvents(); + assertThat(map.get(PKG1).sentCount).isEqualTo(2); + assertThat(map.get(PKG1).lastSent).isEqualTo(6); + } + + @Test + public void testGetAggregatedUsageEvents_multiplePkgs() { + List events = new ArrayList<>(); + Event good = new Event(); + good.mEventType = Event.NOTIFICATION_INTERRUPTION; + good.mPackage = PKG1; + good.mTimeStamp = 6; + events.add(good); + Event good1 = new Event(); + good1.mEventType = Event.NOTIFICATION_INTERRUPTION; + good1.mPackage = PKG2; + good1.mTimeStamp = 1; + events.add(good1); + + UsageEvents usageEvents = getUsageEvents(events); + when(mUsageStats.queryEvents(anyLong(), anyLong())).thenReturn(usageEvents); + + Map map + = mBridge.getAggregatedUsageEvents(); + assertThat(map.get(PKG1).sentCount).isEqualTo(1); + assertThat(map.get(PKG2).sentCount).isEqualTo(1); + assertThat(map.get(PKG1).lastSent).isEqualTo(6); + assertThat(map.get(PKG2).lastSent).isEqualTo(1); + } + + @Test + public void testLoadAllExtraInfo_noEvents() { + when(mUsageStats.queryEvents(anyLong(), anyLong())).thenReturn(mock(UsageEvents.class)); + ArrayList apps = new ArrayList<>(); + apps.add(getMockAppEntry(PKG1)); + when(mSession.getAllApps()).thenReturn(apps); + + mBridge.loadAllExtraInfo(); + assertThat(apps.get(0).extraInfo).isNull(); + } + + @Test + public void testLoadAllExtraInfo_multipleEventsAgg() { + List events = new ArrayList<>(); + for (int i = 0; i < 7; i++) { + Event good = new Event(); + good.mEventType = Event.NOTIFICATION_INTERRUPTION; + good.mPackage = PKG1; + good.mTimeStamp = i; + events.add(good); + } + + UsageEvents usageEvents = getUsageEvents(events); + when(mUsageStats.queryEvents(anyLong(), anyLong())).thenReturn(usageEvents); + + ArrayList apps = new ArrayList<>(); + apps.add(getMockAppEntry(PKG1)); + when(mSession.getAllApps()).thenReturn(apps); + + mBridge.loadAllExtraInfo(); + assertThat(((NotificationsSentState) apps.get(0).extraInfo).sentCount).isEqualTo(7); + assertThat(((NotificationsSentState) apps.get(0).extraInfo).lastSent).isEqualTo(6); + assertThat(((NotificationsSentState) apps.get(0).extraInfo).avgSentDaily).isEqualTo(1); + assertThat(((NotificationsSentState) apps.get(0).extraInfo).avgSentWeekly).isEqualTo(0); + } + + @Test + public void testLoadAllExtraInfo_multiplePkgs() { + List events = new ArrayList<>(); + for (int i = 0; i < 8; i++) { + Event good = new Event(); + good.mEventType = Event.NOTIFICATION_INTERRUPTION; + good.mPackage = PKG1; + good.mTimeStamp = i; + events.add(good); + } + Event good1 = new Event(); + good1.mEventType = Event.NOTIFICATION_INTERRUPTION; + good1.mPackage = PKG2; + good1.mTimeStamp = 1; + events.add(good1); + + UsageEvents usageEvents = getUsageEvents(events); + when(mUsageStats.queryEvents(anyLong(), anyLong())).thenReturn(usageEvents); + + ArrayList apps = new ArrayList<>(); + apps.add(getMockAppEntry(PKG1)); + apps.add(getMockAppEntry(PKG2)); + when(mSession.getAllApps()).thenReturn(apps); + + mBridge.loadAllExtraInfo(); + assertThat(((NotificationsSentState) apps.get(0).extraInfo).sentCount).isEqualTo(8); + assertThat(((NotificationsSentState) apps.get(0).extraInfo).lastSent).isEqualTo(7); + assertThat(((NotificationsSentState) apps.get(0).extraInfo).avgSentWeekly).isEqualTo(0); + assertThat(((NotificationsSentState) apps.get(0).extraInfo).avgSentDaily).isEqualTo(1); + + assertThat(((NotificationsSentState) apps.get(1).extraInfo).sentCount).isEqualTo(1); + assertThat(((NotificationsSentState) apps.get(1).extraInfo).lastSent).isEqualTo(1); + assertThat(((NotificationsSentState) apps.get(1).extraInfo).avgSentWeekly).isEqualTo(1); + assertThat(((NotificationsSentState) apps.get(1).extraInfo).avgSentDaily).isEqualTo(0); + } + + @Test + public void testUpdateExtraInfo_noEvents() { + when(mUsageStats.queryEvents(anyLong(), anyLong())).thenReturn(mock(UsageEvents.class)); + AppEntry entry = getMockAppEntry(PKG1); + + mBridge.updateExtraInfo(entry, "", 0); + assertThat(entry.extraInfo).isNull(); + } + + @Test + public void testUpdateExtraInfo_multipleEventsAgg() { + List events = new ArrayList<>(); + for (int i = 0; i < 13; i++) { + Event good = new Event(); + good.mEventType = Event.NOTIFICATION_INTERRUPTION; + good.mPackage = PKG1; + good.mTimeStamp = i; + events.add(good); + } + + UsageEvents usageEvents = getUsageEvents(events); + when(mUsageStats.queryEvents(anyLong(), anyLong())).thenReturn(usageEvents); + + AppEntry entry = getMockAppEntry(PKG1); + mBridge.updateExtraInfo(entry, "", 0); + + assertThat(((NotificationsSentState) entry.extraInfo).sentCount).isEqualTo(13); + assertThat(((NotificationsSentState) entry.extraInfo).lastSent).isEqualTo(12); + assertThat(((NotificationsSentState) entry.extraInfo).avgSentDaily).isEqualTo(2); + assertThat(((NotificationsSentState) entry.extraInfo).avgSentWeekly).isEqualTo(0); + } + + @Test + public void testSummary_recency() { + NotificationsSentState neverSent = new NotificationsSentState(); + NotificationsSentState sent = new NotificationsSentState(); + sent.lastSent = System.currentTimeMillis() - (2 * DAY_IN_MILLIS); + + assertThat(AppStateNotificationBridge.getSummary(mContext, neverSent, true)).isEqualTo( + mContext.getString(R.string.notifications_sent_never)); + assertThat(AppStateNotificationBridge.getSummary(mContext, sent, true).toString()) + .contains("2"); + } + + @Test + public void testSummary_frequency() { + NotificationsSentState sentRarely = new NotificationsSentState(); + sentRarely.avgSentWeekly = 1; + NotificationsSentState sentOften = new NotificationsSentState(); + sentOften.avgSentDaily = 8; + + assertThat(AppStateNotificationBridge.getSummary(mContext, sentRarely, false).toString()) + .contains("1"); + assertThat(AppStateNotificationBridge.getSummary(mContext, sentOften, false).toString()) + .contains("8"); + } + + @Test + public void testFilterRecency() { + NotificationsSentState allowState = new NotificationsSentState(); + allowState.lastSent = 1; + AppEntry allow = mock(AppEntry.class); + allow.extraInfo = allowState; + + assertTrue(FILTER_APP_NOTIFICATION_RECENCY.filterApp(allow)); + + NotificationsSentState denyState = new NotificationsSentState(); + denyState.lastSent = 0; + AppEntry deny = mock(AppEntry.class); + deny.extraInfo = denyState; + + assertFalse(FILTER_APP_NOTIFICATION_RECENCY.filterApp(deny)); + } + + @Test + public void testFilterFrequency() { + NotificationsSentState allowState = new NotificationsSentState(); + allowState.sentCount = 1; + AppEntry allow = mock(AppEntry.class); + allow.extraInfo = allowState; + + assertTrue(FILTER_APP_NOTIFICATION_FREQUENCY.filterApp(allow)); + + NotificationsSentState denyState = new NotificationsSentState(); + denyState.sentCount = 0; + AppEntry deny = mock(AppEntry.class); + deny.extraInfo = denyState; + + assertFalse(FILTER_APP_NOTIFICATION_FREQUENCY.filterApp(deny)); + } + + @Test + public void testComparators_nullsNoCrash() { + List entries = new ArrayList<>(); + AppEntry a = mock(AppEntry.class); + a.label = "1"; + AppEntry b = mock(AppEntry.class); + b.label = "2"; + entries.add(a); + entries.add(b); + + entries.sort(RECENT_NOTIFICATION_COMPARATOR); + entries.sort(FREQUENCY_NOTIFICATION_COMPARATOR); + } + + @Test + public void testRecencyComparator() { + List entries = new ArrayList<>(); + + NotificationsSentState earlier = new NotificationsSentState(); + earlier.lastSent = 1; + AppEntry earlyEntry = mock(AppEntry.class); + earlyEntry.extraInfo = earlier; + entries.add(earlyEntry); + + NotificationsSentState later = new NotificationsSentState(); + later.lastSent = 8; + AppEntry lateEntry = mock(AppEntry.class); + lateEntry.extraInfo = later; + entries.add(lateEntry); + + entries.sort(RECENT_NOTIFICATION_COMPARATOR); + + assertThat(entries).containsExactly(lateEntry, earlyEntry); + } + + @Test + public void testFrequencyComparator() { + List entries = new ArrayList<>(); + + NotificationsSentState notFrequentWeekly = new NotificationsSentState(); + notFrequentWeekly.sentCount = 2; + AppEntry notFrequentWeeklyEntry = mock(AppEntry.class); + notFrequentWeeklyEntry.extraInfo = notFrequentWeekly; + entries.add(notFrequentWeeklyEntry); + + NotificationsSentState notFrequentDaily = new NotificationsSentState(); + notFrequentDaily.sentCount = 7; + AppEntry notFrequentDailyEntry = mock(AppEntry.class); + notFrequentDailyEntry.extraInfo = notFrequentDaily; + entries.add(notFrequentDailyEntry); + + NotificationsSentState veryFrequentWeekly = new NotificationsSentState(); + veryFrequentWeekly.sentCount = 6; + AppEntry veryFrequentWeeklyEntry = mock(AppEntry.class); + veryFrequentWeeklyEntry.extraInfo = veryFrequentWeekly; + entries.add(veryFrequentWeeklyEntry); + + NotificationsSentState veryFrequentDaily = new NotificationsSentState(); + veryFrequentDaily.sentCount = 19; + AppEntry veryFrequentDailyEntry = mock(AppEntry.class); + veryFrequentDailyEntry.extraInfo = veryFrequentDaily; + entries.add(veryFrequentDailyEntry); + + entries.sort(FREQUENCY_NOTIFICATION_COMPARATOR); + + assertThat(entries).containsExactly(veryFrequentDailyEntry, notFrequentDailyEntry, + veryFrequentWeeklyEntry, notFrequentWeeklyEntry); + } +} diff --git a/tests/robotests/src/com/android/settings/applications/RecentAppsPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/applications/RecentAppsPreferenceControllerTest.java index 51a16f2b328..6556a882484 100644 --- a/tests/robotests/src/com/android/settings/applications/RecentAppsPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/applications/RecentAppsPreferenceControllerTest.java @@ -312,7 +312,7 @@ public class RecentAppsPreferenceControllerTest { mController.displayPreference(mScreen); - verify(mCategory).addPreference(argThat(summaryMatches("0 min. ago"))); + verify(mCategory).addPreference(argThat(summaryMatches("0 minutes ago"))); } private static ArgumentMatcher summaryMatches(String expected) { diff --git a/tests/robotests/src/com/android/settings/applications/manageapplications/AppFilterItemTest.java b/tests/robotests/src/com/android/settings/applications/manageapplications/AppFilterItemTest.java index cf0e2990d50..9b088cf3932 100644 --- a/tests/robotests/src/com/android/settings/applications/manageapplications/AppFilterItemTest.java +++ b/tests/robotests/src/com/android/settings/applications/manageapplications/AppFilterItemTest.java @@ -16,7 +16,6 @@ package com.android.settings.applications.manageapplications; -import static com.android.settings.applications.manageapplications.AppFilterRegistry.FILTER_APPS_BLOCKED; import static com.android.settings.applications.manageapplications.AppFilterRegistry.FILTER_APPS_ENABLED; import static com.android.settings.applications.manageapplications.AppFilterRegistry.FILTER_APPS_USAGE_ACCESS; import static com.google.common.truth.Truth.assertThat; @@ -80,7 +79,7 @@ public class AppFilterItemTest { @Test public void hash_differentItem_differentHash() { final AppFilterItem item = AppFilterRegistry.getInstance().get(FILTER_APPS_USAGE_ACCESS); - final AppFilterItem item2 = AppFilterRegistry.getInstance().get(FILTER_APPS_BLOCKED); + final AppFilterItem item2 = AppFilterRegistry.getInstance().get(FILTER_APPS_ENABLED); assertThat(item.hashCode()).isNotEqualTo(item2.hashCode()); } diff --git a/tests/robotests/src/com/android/settings/applications/manageapplications/AppFilterRegistryTest.java b/tests/robotests/src/com/android/settings/applications/manageapplications/AppFilterRegistryTest.java index a62a8c33257..4c94e0a03c5 100644 --- a/tests/robotests/src/com/android/settings/applications/manageapplications/AppFilterRegistryTest.java +++ b/tests/robotests/src/com/android/settings/applications/manageapplications/AppFilterRegistryTest.java @@ -19,6 +19,9 @@ package com.android.settings.applications.manageapplications; import static com.android.settings.applications.manageapplications.AppFilterRegistry.FILTER_APPS_ALL; import static com.android.settings.applications.manageapplications.AppFilterRegistry.FILTER_APPS_INSTALL_SOURCES; import static com.android.settings.applications.manageapplications.AppFilterRegistry.FILTER_APPS_POWER_WHITELIST; + +import static com.android.settings.applications.manageapplications.AppFilterRegistry + .FILTER_APPS_RECENT; import static com.android.settings.applications.manageapplications.AppFilterRegistry.FILTER_APPS_USAGE_ACCESS; import static com.android.settings.applications.manageapplications.AppFilterRegistry.FILTER_APPS_WITH_OVERLAY; import static com.android.settings.applications.manageapplications.AppFilterRegistry.FILTER_APPS_WRITE_SETTINGS; @@ -45,24 +48,25 @@ public class AppFilterRegistryTest { @Test public void getDefaultType_shouldMatchForAllListType() { - final AppFilterRegistry registry = AppFilterRegistry.getInstance(); - assertThat(registry.getDefaultFilterType(LIST_TYPE_USAGE_ACCESS)) - .isEqualTo(FILTER_APPS_USAGE_ACCESS); - assertThat(registry.getDefaultFilterType(LIST_TYPE_HIGH_POWER)) - .isEqualTo(FILTER_APPS_POWER_WHITELIST); - assertThat(registry.getDefaultFilterType(LIST_TYPE_OVERLAY)) - .isEqualTo(FILTER_APPS_WITH_OVERLAY); - assertThat(registry.getDefaultFilterType(LIST_TYPE_WRITE_SETTINGS)) - .isEqualTo(FILTER_APPS_WRITE_SETTINGS); - assertThat(registry.getDefaultFilterType(LIST_TYPE_MANAGE_SOURCES)) - .isEqualTo(FILTER_APPS_INSTALL_SOURCES); + final AppFilterRegistry registry = AppFilterRegistry.getInstance(); + assertThat(registry.getDefaultFilterType(LIST_TYPE_USAGE_ACCESS)) + .isEqualTo(FILTER_APPS_USAGE_ACCESS); + assertThat(registry.getDefaultFilterType(LIST_TYPE_HIGH_POWER)) + .isEqualTo(FILTER_APPS_POWER_WHITELIST); + assertThat(registry.getDefaultFilterType(LIST_TYPE_OVERLAY)) + .isEqualTo(FILTER_APPS_WITH_OVERLAY); + assertThat(registry.getDefaultFilterType(LIST_TYPE_WRITE_SETTINGS)) + .isEqualTo(FILTER_APPS_WRITE_SETTINGS); + assertThat(registry.getDefaultFilterType(LIST_TYPE_MANAGE_SOURCES)) + .isEqualTo(FILTER_APPS_INSTALL_SOURCES); - assertThat(registry.getDefaultFilterType(LIST_TYPE_MAIN)).isEqualTo(FILTER_APPS_ALL); - assertThat(registry.getDefaultFilterType(LIST_TYPE_NOTIFICATION)).isEqualTo(FILTER_APPS_ALL); - assertThat(registry.getDefaultFilterType(LIST_TYPE_STORAGE)).isEqualTo(FILTER_APPS_ALL); + assertThat(registry.getDefaultFilterType(LIST_TYPE_MAIN)).isEqualTo(FILTER_APPS_ALL); + assertThat(registry.getDefaultFilterType(LIST_TYPE_NOTIFICATION)) + .isEqualTo(FILTER_APPS_RECENT); + assertThat(registry.getDefaultFilterType(LIST_TYPE_STORAGE)).isEqualTo(FILTER_APPS_ALL); - assertThat(registry.getDefaultFilterType(LIST_TYPE_GAMES)).isEqualTo(FILTER_APPS_ALL); - assertThat(registry.getDefaultFilterType(LIST_TYPE_MOVIES)).isEqualTo(FILTER_APPS_ALL); - assertThat(registry.getDefaultFilterType(LIST_TYPE_PHOTOGRAPHY)).isEqualTo(FILTER_APPS_ALL); + assertThat(registry.getDefaultFilterType(LIST_TYPE_GAMES)).isEqualTo(FILTER_APPS_ALL); + assertThat(registry.getDefaultFilterType(LIST_TYPE_MOVIES)).isEqualTo(FILTER_APPS_ALL); + assertThat(registry.getDefaultFilterType(LIST_TYPE_PHOTOGRAPHY)).isEqualTo(FILTER_APPS_ALL); } } diff --git a/tests/robotests/src/com/android/settings/applications/manageapplications/ManageApplicationsTest.java b/tests/robotests/src/com/android/settings/applications/manageapplications/ManageApplicationsTest.java index ca9ddcffc4a..f60c7b0733f 100644 --- a/tests/robotests/src/com/android/settings/applications/manageapplications/ManageApplicationsTest.java +++ b/tests/robotests/src/com/android/settings/applications/manageapplications/ManageApplicationsTest.java @@ -67,12 +67,16 @@ public class ManageApplicationsTest { @Mock private Menu mMenu; private MenuItem mAppReset; + private MenuItem mSortRecent; + private MenuItem mSortFrequent; private ManageApplications mFragment; @Before public void setUp() { MockitoAnnotations.initMocks(this); mAppReset = new RoboMenuItem(R.id.reset_app_preferences); + mSortRecent = new RoboMenuItem(R.id.sort_order_recent_notification); + mSortFrequent = new RoboMenuItem(R.id.sort_order_frequent_notification); ReflectionHelpers.setStaticField(ApplicationsState.class, "sInstance", mState); when(mState.newSession(any())).thenReturn(mSession); when(mState.getBackgroundLooper()).thenReturn(Looper.myLooper()); @@ -100,6 +104,18 @@ public class ManageApplicationsTest { assertThat(mMenu.findItem(R.id.reset_app_preferences).isVisible()).isFalse(); } + @Test + public void updateMenu_hideNotificationOptions() { + setUpOptionMenus(); + ReflectionHelpers.setField(mFragment, "mListType", LIST_TYPE_NOTIFICATION); + ReflectionHelpers.setField(mFragment, "mOptionsMenu", mMenu); + + mFragment.updateOptionsMenu(); + assertThat(mMenu.findItem(R.id.sort_order_recent_notification).isVisible()).isFalse(); + assertThat(mMenu.findItem(R.id.sort_order_frequent_notification).isVisible()).isFalse(); + } + + @Test public void onCreateView_shouldNotShowLoadingContainer() { final ManageApplications fragment = spy(new ManageApplications()); @@ -220,6 +236,12 @@ public class ManageApplicationsTest { if (id == mAppReset.getItemId()) { return mAppReset; } + if (id == mSortFrequent.getItemId()) { + return mSortFrequent; + } + if (id == mSortRecent.getItemId()) { + return mSortRecent; + } return new RoboMenuItem(id); }); } diff --git a/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageSummaryLegacyTest.java b/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageSummaryLegacyTest.java index 093adfe0181..0e6efbc57ce 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageSummaryLegacyTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageSummaryLegacyTest.java @@ -360,7 +360,7 @@ public class PowerUsageSummaryLegacyTest { mFragment.updateLastFullChargePreference(TIME_SINCE_LAST_FULL_CHARGE_MS); - assertThat(mLastFullChargePref.getSubtitle()).isEqualTo("2 hr. ago"); + assertThat(mLastFullChargePref.getSubtitle()).isEqualTo("2 hours ago"); } @Test diff --git a/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageSummaryTest.java b/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageSummaryTest.java index 24b789cd3e9..d021c5d857f 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageSummaryTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageSummaryTest.java @@ -196,7 +196,7 @@ public class PowerUsageSummaryTest { mFragment.updateLastFullChargePreference(); assertThat(mLastFullChargePref.getTitle()).isEqualTo("Last full charge"); - assertThat(mLastFullChargePref.getSubtitle()).isEqualTo("2 hr. ago"); + assertThat(mLastFullChargePref.getSubtitle()).isEqualTo("2 hours ago"); } @Test diff --git a/tests/robotests/src/com/android/settings/notification/RecentNotifyingAppsPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/RecentNotifyingAppsPreferenceControllerTest.java index 13ac8687fcb..13826b2ac85 100644 --- a/tests/robotests/src/com/android/settings/notification/RecentNotifyingAppsPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/notification/RecentNotifyingAppsPreferenceControllerTest.java @@ -290,7 +290,7 @@ public class RecentNotifyingAppsPreferenceControllerTest { mController.displayPreference(mScreen); - verify(mCategory).addPreference(argThat(summaryMatches("0 min. ago"))); + verify(mCategory).addPreference(argThat(summaryMatches("0 minutes ago"))); } private static ArgumentMatcher summaryMatches(String expected) {