From d06333167d3c4dbb8b1f65ec352db618c3246701 Mon Sep 17 00:00:00 2001 From: Jason Chiu Date: Fri, 29 May 2020 17:06:52 +0800 Subject: [PATCH] Cleanup notification channel slice Fixes: 144897605 Test: robotest Change-Id: I1b654f31c6b001ef6f1eed95a87ca0b2dd1afc2e --- res/values/strings.xml | 14 - .../ContextualCardFeatureProvider.java | 5 - .../ContextualCardFeatureProviderImpl.java | 36 -- .../contextualcards/ContextualCardLoader.java | 6 +- .../SettingsContextualCardProvider.java | 9 - .../ContextualNotificationChannelSlice.java | 63 --- .../slices/NotificationChannelSlice.java | 503 ------------------ .../slices/NotificationChannelWorker.java | 77 --- .../NotificationMultiChannelAppRow.java | 54 -- .../slices/SliceFullCardRendererHelper.java | 25 +- .../settings/slices/CustomSliceRegistry.java | 24 - ...ContextualCardFeatureProviderImplTest.java | 79 --- ...ontextualNotificationChannelSliceTest.java | 107 ---- .../slices/NotificationChannelSliceTest.java | 420 --------------- .../slices/NotificationChannelWorkerTest.java | 112 ---- .../NotificationMultiChannelAppRowTest.java | 82 --- .../ShadowRestrictedLockUtilsInternal.java | 12 - 17 files changed, 10 insertions(+), 1618 deletions(-) delete mode 100644 src/com/android/settings/homepage/contextualcards/slices/ContextualNotificationChannelSlice.java delete mode 100644 src/com/android/settings/homepage/contextualcards/slices/NotificationChannelSlice.java delete mode 100644 src/com/android/settings/homepage/contextualcards/slices/NotificationChannelWorker.java delete mode 100644 src/com/android/settings/homepage/contextualcards/slices/NotificationMultiChannelAppRow.java delete mode 100644 tests/robotests/src/com/android/settings/homepage/contextualcards/slices/ContextualNotificationChannelSliceTest.java delete mode 100644 tests/robotests/src/com/android/settings/homepage/contextualcards/slices/NotificationChannelSliceTest.java delete mode 100644 tests/robotests/src/com/android/settings/homepage/contextualcards/slices/NotificationChannelWorkerTest.java delete mode 100644 tests/robotests/src/com/android/settings/homepage/contextualcards/slices/NotificationMultiChannelAppRowTest.java diff --git a/res/values/strings.xml b/res/values/strings.xml index 5ba2b7a2c79..5f67c6aaf78 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -11890,20 +11890,6 @@ %1$d apps have full access to your device - - Manage %1$s notifications - - No suggested application - - - %1$d notification channel. - %1$d notification channels. - - - %1$d notification channels. Tap to manage all. - - You recently installed this app. - Switch output diff --git a/src/com/android/settings/homepage/contextualcards/ContextualCardFeatureProvider.java b/src/com/android/settings/homepage/contextualcards/ContextualCardFeatureProvider.java index 60bffdea3cb..7f29ecb836e 100644 --- a/src/com/android/settings/homepage/contextualcards/ContextualCardFeatureProvider.java +++ b/src/com/android/settings/homepage/contextualcards/ContextualCardFeatureProvider.java @@ -19,8 +19,6 @@ package com.android.settings.homepage.contextualcards; import android.content.Context; import android.database.Cursor; -import androidx.slice.Slice; - /** Feature provider for the contextual card feature. */ public interface ContextualCardFeatureProvider { /** Get contextual cards from the card provider */ @@ -35,7 +33,4 @@ public interface ContextualCardFeatureProvider { * @return The number of rows updated */ int markCardAsDismissed(Context context, String cardName); - - /** Log package when user clicks contextual notification channel card. */ - void logNotificationPackage(Slice slice); } diff --git a/src/com/android/settings/homepage/contextualcards/ContextualCardFeatureProviderImpl.java b/src/com/android/settings/homepage/contextualcards/ContextualCardFeatureProviderImpl.java index f4bb84c4f61..5059d90a15e 100644 --- a/src/com/android/settings/homepage/contextualcards/ContextualCardFeatureProviderImpl.java +++ b/src/com/android/settings/homepage/contextualcards/ContextualCardFeatureProviderImpl.java @@ -16,33 +16,20 @@ package com.android.settings.homepage.contextualcards; -import static android.content.Context.MODE_PRIVATE; - import static com.android.settings.homepage.contextualcards.CardDatabaseHelper.CARD_TABLE; import android.content.ContentValues; import android.content.Context; -import android.content.SharedPreferences; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.os.Build; import android.text.format.DateUtils; -import android.util.ArraySet; import android.util.Log; import androidx.annotation.VisibleForTesting; -import androidx.slice.Slice; -import androidx.slice.SliceMetadata; -import androidx.slice.core.SliceAction; -import com.android.settings.SettingsActivity; -import com.android.settings.applications.AppInfoBase; -import com.android.settings.homepage.contextualcards.slices.ContextualNotificationChannelSlice; -import com.android.settings.slices.CustomSliceRegistry; import com.android.settingslib.utils.ThreadUtils; -import java.util.Set; - public class ContextualCardFeatureProviderImpl implements ContextualCardFeatureProvider { private static final String TAG = "ContextualCardFeatureProvider"; @@ -79,29 +66,6 @@ public class ContextualCardFeatureProviderImpl implements ContextualCardFeatureP return rowsUpdated; } - @Override - public void logNotificationPackage(Slice slice) { - if (slice == null || !slice.getUri().equals( - CustomSliceRegistry.CONTEXTUAL_NOTIFICATION_CHANNEL_SLICE_URI)) { - return; - } - - final SliceAction primaryAction = SliceMetadata.from(mContext, slice).getPrimaryAction(); - final String currentPackage = primaryAction.getAction().getIntent() - .getBundleExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT_ARGUMENTS) - .getString(AppInfoBase.ARG_PACKAGE_NAME); - - final SharedPreferences prefs = mContext.getSharedPreferences( - ContextualNotificationChannelSlice.PREFS, MODE_PRIVATE); - final Set interactedPackages = prefs.getStringSet( - ContextualNotificationChannelSlice.PREF_KEY_INTERACTED_PACKAGES, new ArraySet<>()); - - final Set newInteractedPackages = new ArraySet<>(interactedPackages); - newInteractedPackages.add(currentPackage); - prefs.edit().putStringSet(ContextualNotificationChannelSlice.PREF_KEY_INTERACTED_PACKAGES, - newInteractedPackages).apply(); - } - @VisibleForTesting int resetDismissedTime(long threshold) { final SQLiteDatabase database = diff --git a/src/com/android/settings/homepage/contextualcards/ContextualCardLoader.java b/src/com/android/settings/homepage/contextualcards/ContextualCardLoader.java index 744bb4edfda..4d1a1d476bf 100644 --- a/src/com/android/settings/homepage/contextualcards/ContextualCardLoader.java +++ b/src/com/android/settings/homepage/contextualcards/ContextualCardLoader.java @@ -18,7 +18,6 @@ package com.android.settings.homepage.contextualcards; import static com.android.settings.intelligence.ContextualCardProto.ContextualCard.Category.STICKY_VALUE; import static com.android.settings.slices.CustomSliceRegistry.BLUETOOTH_DEVICES_SLICE_URI; -import static com.android.settings.slices.CustomSliceRegistry.CONTEXTUAL_NOTIFICATION_CHANNEL_SLICE_URI; import static com.android.settings.slices.CustomSliceRegistry.CONTEXTUAL_WIFI_SLICE_URI; import android.app.settings.SettingsEnums; @@ -201,7 +200,7 @@ public class ContextualCardLoader extends AsyncLoaderCompat cards.add(card); } } catch (ExecutionException | InterruptedException | TimeoutException e) { - Log.w(TAG, "Failed to get eligible state for card, likely timeout. Skipping", e); + Log.w(TAG, "Failed to get eligible state for card: " + e.toString()); } } return cards; @@ -209,8 +208,7 @@ public class ContextualCardLoader extends AsyncLoaderCompat private boolean isLargeCard(ContextualCard card) { return card.getSliceUri().equals(CONTEXTUAL_WIFI_SLICE_URI) - || card.getSliceUri().equals(BLUETOOTH_DEVICES_SLICE_URI) - || card.getSliceUri().equals(CONTEXTUAL_NOTIFICATION_CHANNEL_SLICE_URI); + || card.getSliceUri().equals(BLUETOOTH_DEVICES_SLICE_URI); } public interface CardContentLoaderListener { diff --git a/src/com/android/settings/homepage/contextualcards/SettingsContextualCardProvider.java b/src/com/android/settings/homepage/contextualcards/SettingsContextualCardProvider.java index 1494293341f..067fcf90e00 100644 --- a/src/com/android/settings/homepage/contextualcards/SettingsContextualCardProvider.java +++ b/src/com/android/settings/homepage/contextualcards/SettingsContextualCardProvider.java @@ -56,14 +56,6 @@ public class SettingsContextualCardProvider extends ContextualCardProvider { .setCardName(CustomSliceRegistry.BATTERY_FIX_SLICE_URI.toString()) .setCardCategory(ContextualCard.Category.IMPORTANT) .build(); - final String contextualNotificationChannelSliceUri = - CustomSliceRegistry.CONTEXTUAL_NOTIFICATION_CHANNEL_SLICE_URI.toString(); - final ContextualCard notificationChannelCard = - ContextualCard.newBuilder() - .setSliceUri(contextualNotificationChannelSliceUri) - .setCardName(contextualNotificationChannelSliceUri) - .setCardCategory(ContextualCard.Category.POSSIBLE) - .build(); final String contextualAdaptiveSleepSliceUri = CustomSliceRegistry.CONTEXTUAL_ADAPTIVE_SLEEP_URI.toString(); final ContextualCard contextualAdaptiveSleepCard = @@ -89,7 +81,6 @@ public class SettingsContextualCardProvider extends ContextualCardProvider { .addCard(connectedDeviceCard) .addCard(lowStorageCard) .addCard(batteryFixCard) - .addCard(notificationChannelCard) .addCard(contextualAdaptiveSleepCard) .addCard(contextualFaceSettingsCard) .addCard(darkThemeCard) diff --git a/src/com/android/settings/homepage/contextualcards/slices/ContextualNotificationChannelSlice.java b/src/com/android/settings/homepage/contextualcards/slices/ContextualNotificationChannelSlice.java deleted file mode 100644 index 17cae777b75..00000000000 --- a/src/com/android/settings/homepage/contextualcards/slices/ContextualNotificationChannelSlice.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (C) 2019 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.homepage.contextualcards.slices; - -import static android.content.Context.MODE_PRIVATE; - -import android.content.Context; -import android.net.Uri; -import android.util.ArraySet; - -import com.android.settings.R; -import com.android.settings.slices.CustomSliceRegistry; -import com.android.settings.slices.SliceBackgroundWorker; - -import java.util.Set; - -public class ContextualNotificationChannelSlice extends NotificationChannelSlice { - - public static final String PREFS = "notification_channel_slice_prefs"; - public static final String PREF_KEY_INTERACTED_PACKAGES = "interacted_packages"; - - public ContextualNotificationChannelSlice(Context context) { - super(context); - } - - @Override - public Uri getUri() { - return CustomSliceRegistry.CONTEXTUAL_NOTIFICATION_CHANNEL_SLICE_URI; - } - - @Override - protected CharSequence getSubTitle(String packageName, int uid) { - return mContext.getText(R.string.recently_installed_app); - } - - @Override - protected boolean isUserInteracted(String packageName) { - // Check the package has been interacted on current slice or not. - final Set interactedPackages = - mContext.getSharedPreferences(PREFS, MODE_PRIVATE) - .getStringSet(PREF_KEY_INTERACTED_PACKAGES, new ArraySet<>()); - return interactedPackages.contains(packageName); - } - - @Override - public Class getBackgroundWorkerClass() { - return NotificationChannelWorker.class; - } -} diff --git a/src/com/android/settings/homepage/contextualcards/slices/NotificationChannelSlice.java b/src/com/android/settings/homepage/contextualcards/slices/NotificationChannelSlice.java deleted file mode 100644 index 2716e4cf1df..00000000000 --- a/src/com/android/settings/homepage/contextualcards/slices/NotificationChannelSlice.java +++ /dev/null @@ -1,503 +0,0 @@ -/* - * Copyright (C) 2019 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.homepage.contextualcards.slices; - -import static android.app.NotificationManager.IMPORTANCE_LOW; -import static android.app.NotificationManager.IMPORTANCE_NONE; -import static android.app.slice.Slice.EXTRA_TOGGLE_STATE; - -import android.app.Application; -import android.app.NotificationChannel; -import android.app.NotificationChannelGroup; -import android.app.PendingIntent; -import android.app.settings.SettingsEnums; -import android.content.Context; -import android.content.Intent; -import android.content.pm.PackageInfo; -import android.content.pm.PackageManager; -import android.graphics.drawable.Drawable; -import android.net.Uri; -import android.os.Bundle; -import android.os.UserHandle; -import android.provider.Settings; -import android.text.TextUtils; -import android.util.Log; - -import androidx.core.graphics.drawable.IconCompat; -import androidx.slice.Slice; -import androidx.slice.builders.ListBuilder; -import androidx.slice.builders.SliceAction; - -import com.android.internal.annotations.VisibleForTesting; -import com.android.settings.R; -import com.android.settings.SubSettings; -import com.android.settings.Utils; -import com.android.settings.applications.AppAndNotificationDashboardFragment; -import com.android.settings.applications.AppInfoBase; -import com.android.settings.core.SubSettingLauncher; -import com.android.settings.notification.app.AppNotificationSettings; -import com.android.settings.notification.app.ChannelNotificationSettings; -import com.android.settings.notification.NotificationBackend; -import com.android.settings.notification.NotificationBackend.NotificationsSentState; -import com.android.settings.notification.app.ChannelListPreferenceController; -import com.android.settings.slices.CustomSliceRegistry; -import com.android.settings.slices.CustomSliceable; -import com.android.settings.slices.SliceBroadcastReceiver; -import com.android.settings.slices.SliceBuilderUtils; -import com.android.settingslib.RestrictedLockUtils; -import com.android.settingslib.RestrictedLockUtilsInternal; -import com.android.settingslib.applications.ApplicationsState; -import com.android.settingslib.utils.ThreadUtils; - -import java.util.ArrayList; -import java.util.Comparator; -import java.util.List; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.Future; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; -import java.util.stream.Collectors; - -public class NotificationChannelSlice implements CustomSliceable { - - /** - * Recently app condition: - * App was installed between 3 and 7 days ago. - */ - @VisibleForTesting - static final long DURATION_START_DAYS = TimeUnit.DAYS.toMillis(7); - @VisibleForTesting - static final long DURATION_END_DAYS = TimeUnit.DAYS.toMillis(3); - - /** - * Notification count condition: - * App has sent at least ~10 notifications. - */ - @VisibleForTesting - static final int MIN_NOTIFICATION_SENT_COUNT = 10; - - /** - * Limit rows when the number of notification channel is more than {@link - * #DEFAULT_EXPANDED_ROW_COUNT}. - */ - @VisibleForTesting - static final int DEFAULT_EXPANDED_ROW_COUNT = 3; - - private static final String TAG = "NotifChannelSlice"; - private static final String PACKAGE_NAME = "package_name"; - private static final String PACKAGE_UID = "package_uid"; - private static final String CHANNEL_ID = "channel_id"; - private static final long TASK_TIMEOUT_MS = 100; - - /** - * Sort notification channel with weekly average sent count by descending. - * - * Note: - * When the sent count of notification channels is the same, follow the sorting mechanism from - * {@link ChannelListPreferenceController}. - * Since slice view only shows displayable notification channels, so those deleted ones are - * excluded from the comparison here. - */ - private static final Comparator CHANNEL_STATE_COMPARATOR = - (left, right) -> { - final NotificationsSentState leftState = left.getNotificationsSentState(); - final NotificationsSentState rightState = right.getNotificationsSentState(); - if (rightState.avgSentWeekly != leftState.avgSentWeekly) { - return rightState.avgSentWeekly - leftState.avgSentWeekly; - } - - final NotificationChannel leftChannel = left.getNotificationChannel(); - final NotificationChannel rightChannel = right.getNotificationChannel(); - if (TextUtils.equals(leftChannel.getId(), NotificationChannel.DEFAULT_CHANNEL_ID)) { - return 1; - } else if (TextUtils.equals(rightChannel.getId(), - NotificationChannel.DEFAULT_CHANNEL_ID)) { - return -1; - } - - return leftChannel.getId().compareTo(rightChannel.getId()); - }; - - protected final Context mContext; - @VisibleForTesting - NotificationBackend mNotificationBackend; - private NotificationBackend.AppRow mAppRow; - private String mPackageName; - private int mUid; - - public NotificationChannelSlice(Context context) { - mContext = context; - mNotificationBackend = new NotificationBackend(); - } - - @Override - public Slice getSlice() { - final ListBuilder listBuilder = - new ListBuilder(mContext, getUri(), ListBuilder.INFINITY) - .setAccentColor(COLOR_NOT_TINTED); - /** - * Get package which is satisfied with: - * 1. Recently installed. - * 2. Multiple channels. - * 3. Sent at least ~10 notifications. - */ - mPackageName = getEligibleNotificationsPackage(getRecentlyInstalledPackages()); - if (mPackageName == null) { - // Return a header with IsError flag, if package is not found. - return listBuilder.setHeader(getNoSuggestedAppHeader()) - .setIsError(true).build(); - } - mUid = getApplicationUid(mPackageName); - - // Add notification channel header. - final IconCompat icon = getApplicationIcon(mPackageName); - final CharSequence title = mContext.getString(R.string.manage_app_notification, - Utils.getApplicationLabel(mContext, mPackageName)); - listBuilder.addRow(new ListBuilder.RowBuilder() - .setTitleItem(icon, ListBuilder.ICON_IMAGE) - .setTitle(title) - .setSubtitle(getSubTitle(mPackageName, mUid)) - .setPrimaryAction(getPrimarySliceAction(icon, title, getIntent()))); - - // Add notification channel rows. - final List rows = getNotificationChannelRows(icon); - for (ListBuilder.RowBuilder rowBuilder : rows) { - listBuilder.addRow(rowBuilder); - } - - return listBuilder.build(); - } - - @Override - public Uri getUri() { - return CustomSliceRegistry.NOTIFICATION_CHANNEL_SLICE_URI; - } - - @Override - public void onNotifyChange(Intent intent) { - final boolean newState = intent.getBooleanExtra(EXTRA_TOGGLE_STATE, false); - final String packageName = intent.getStringExtra(PACKAGE_NAME); - final int uid = intent.getIntExtra(PACKAGE_UID, -1); - final String channelId = intent.getStringExtra(CHANNEL_ID); - final NotificationChannel channel = mNotificationBackend.getChannel(packageName, uid, - channelId); - final int importance = newState ? IMPORTANCE_LOW : IMPORTANCE_NONE; - channel.setImportance(importance); - channel.lockFields(NotificationChannel.USER_LOCKED_IMPORTANCE); - mNotificationBackend.updateChannel(packageName, uid, channel); - } - - @Override - public Intent getIntent() { - final Bundle args = new Bundle(); - args.putString(AppInfoBase.ARG_PACKAGE_NAME, mPackageName); - args.putInt(AppInfoBase.ARG_PACKAGE_UID, mUid); - - return new SubSettingLauncher(mContext) - .setDestination(AppNotificationSettings.class.getName()) - .setTitleRes(R.string.notifications_title) - .setArguments(args) - .setSourceMetricsCategory(SettingsEnums.SLICE) - .toIntent(); - } - - /** - * Check the package has been interacted by user or not. - * Will use to filter package in {@link #getRecentlyInstalledPackages()}. - * - * @param packageName The app package name. - * @return true if the package was interacted, false otherwise. - */ - protected boolean isUserInteracted(String packageName) { - return false; - } - - @VisibleForTesting - IconCompat getApplicationIcon(String packageName) { - final Drawable drawable; - try { - drawable = mContext.getPackageManager().getApplicationIcon(packageName); - } catch (PackageManager.NameNotFoundException e) { - Log.w(TAG, "No such package to get application icon."); - return null; - } - - return Utils.createIconWithDrawable(drawable); - } - - @VisibleForTesting - int getApplicationUid(String packageName) { - final ApplicationsState.AppEntry appEntry = - ApplicationsState.getInstance((Application) mContext.getApplicationContext()) - .getEntry(packageName, UserHandle.myUserId()); - - return appEntry.info.uid; - } - - private SliceAction buildRowSliceAction(NotificationChannel channel, IconCompat icon) { - final Bundle channelArgs = new Bundle(); - channelArgs.putInt(AppInfoBase.ARG_PACKAGE_UID, mUid); - channelArgs.putString(AppInfoBase.ARG_PACKAGE_NAME, mPackageName); - channelArgs.putString(Settings.EXTRA_CHANNEL_ID, channel.getId()); - - final Intent channelIntent = new SubSettingLauncher(mContext) - .setDestination(ChannelNotificationSettings.class.getName()) - .setArguments(channelArgs) - .setTitleRes(R.string.notification_channel_title) - .setSourceMetricsCategory(SettingsEnums.SLICE) - .toIntent(); - - return SliceAction.createDeeplink( - PendingIntent.getActivity(mContext, channel.hashCode(), channelIntent, 0), icon, - ListBuilder.ICON_IMAGE, channel.getName()); - } - - private ListBuilder.HeaderBuilder getNoSuggestedAppHeader() { - final IconCompat icon = IconCompat.createWithResource(mContext, - R.drawable.ic_homepage_apps); - final CharSequence titleNoSuggestedApp = mContext.getString(R.string.no_suggested_app); - final SliceAction primarySliceActionForNoSuggestedApp = getPrimarySliceAction(icon, - titleNoSuggestedApp, getAppAndNotificationPageIntent()); - - return new ListBuilder.HeaderBuilder() - .setTitle(titleNoSuggestedApp) - .setPrimaryAction(primarySliceActionForNoSuggestedApp); - } - - private List getNotificationChannelRows(IconCompat icon) { - final List notificationChannelRows = new ArrayList<>(); - final List displayableChannels = getDisplayableChannels(mAppRow); - - for (NotificationChannel channel : displayableChannels) { - notificationChannelRows.add(new ListBuilder.RowBuilder() - .setTitle(channel.getName()) - .setSubtitle(NotificationBackend.getSentSummary( - mContext, mAppRow.sentByChannel.get(channel.getId()), false)) - .setPrimaryAction(buildRowSliceAction(channel, icon)) - .addEndItem(SliceAction.createToggle(getToggleIntent(channel.getId()), - null /* actionTitle */, channel.getImportance() != IMPORTANCE_NONE))); - } - - return notificationChannelRows; - } - - private PendingIntent getToggleIntent(String channelId) { - // Send broadcast to enable/disable channel. - final Intent intent = new Intent(getUri().toString()) - .setClass(mContext, SliceBroadcastReceiver.class) - .putExtra(PACKAGE_NAME, mPackageName) - .putExtra(PACKAGE_UID, mUid) - .putExtra(CHANNEL_ID, channelId); - - return PendingIntent.getBroadcast(mContext, intent.hashCode(), intent, 0); - } - - private List getRecentlyInstalledPackages() { - final long startTime = System.currentTimeMillis() - DURATION_START_DAYS; - final long endTime = System.currentTimeMillis() - DURATION_END_DAYS; - - // Get recently installed packages between 3 and 7 days ago. - final List recentlyInstalledPackages = new ArrayList<>(); - final List installedPackages = - mContext.getPackageManager().getInstalledPackages(0); - for (PackageInfo packageInfo : installedPackages) { - // Not include system app and interacted app. - if (packageInfo.applicationInfo.isSystemApp() - || isUserInteracted(packageInfo.packageName)) { - continue; - } - - if (packageInfo.firstInstallTime >= startTime - && packageInfo.firstInstallTime <= endTime) { - recentlyInstalledPackages.add(packageInfo); - } - } - - return recentlyInstalledPackages; - } - - private SliceAction getPrimarySliceAction(IconCompat icon, CharSequence title, Intent intent) { - return SliceAction.createDeeplink( - PendingIntent.getActivity(mContext, intent.hashCode(), intent, 0), - icon, - ListBuilder.ICON_IMAGE, - title); - } - - private List getDisplayableChannels(NotificationBackend.AppRow appRow) { - final List channelGroupList = - mNotificationBackend.getGroups(appRow.pkg, appRow.uid).getList(); - final List channels = channelGroupList.stream() - .flatMap(group -> group.getChannels().stream().filter( - channel -> isChannelEnabled(group, channel, appRow))) - .collect(Collectors.toList()); - - // Pack the notification channel with notification sent state for sorting. - final List channelStates = new ArrayList<>(); - for (NotificationChannel channel : channels) { - NotificationsSentState sentState = appRow.sentByChannel.get(channel.getId()); - if (sentState == null) { - sentState = new NotificationsSentState(); - } - channelStates.add(new NotificationChannelState(sentState, channel)); - } - - // Sort the notification channels with notification sent count by descending. - return channelStates.stream() - .sorted(CHANNEL_STATE_COMPARATOR) - .map(state -> state.getNotificationChannel()) - .limit(DEFAULT_EXPANDED_ROW_COUNT) - .collect(Collectors.toList()); - } - - private String getEligibleNotificationsPackage(List packageInfoList) { - if (packageInfoList.isEmpty()) { - return null; - } - - // Create tasks to get notification data for multi-channel packages. - final List> appRowTasks = new ArrayList<>(); - for (PackageInfo packageInfo : packageInfoList) { - final NotificationMultiChannelAppRow appRow = new NotificationMultiChannelAppRow( - mContext, mNotificationBackend, packageInfo); - appRowTasks.add(ThreadUtils.postOnBackgroundThread(appRow)); - } - - // Get the package which has sent at least ~10 notifications and not turn off channels. - int maxSentCount = 0; - String maxSentCountPackage = null; - for (Future appRowTask : appRowTasks) { - NotificationBackend.AppRow appRow = null; - try { - appRow = appRowTask.get(TASK_TIMEOUT_MS, TimeUnit.MILLISECONDS); - } catch (ExecutionException | InterruptedException | TimeoutException e) { - Log.w(TAG, "Failed to get notification data.", e); - } - - // Ignore packages which are banned notifications or block all displayable channels. - if (appRow == null || appRow.banned || isAllChannelsBlocked( - getDisplayableChannels(appRow))) { - continue; - } - - // Get sent notification count from app. - final int sentCount = appRow.sentByApp.sentCount; - if (sentCount >= MIN_NOTIFICATION_SENT_COUNT && sentCount > maxSentCount) { - maxSentCount = sentCount; - maxSentCountPackage = appRow.pkg; - mAppRow = appRow; - } - } - - return maxSentCountPackage; - } - - private boolean isAllChannelsBlocked(List channels) { - for (NotificationChannel channel : channels) { - if (channel.getImportance() != IMPORTANCE_NONE) { - return false; - } - } - return true; - } - - protected CharSequence getSubTitle(String packageName, int uid) { - final int channelCount = mNotificationBackend.getChannelCount(packageName, uid); - - if (channelCount > DEFAULT_EXPANDED_ROW_COUNT) { - return mContext.getString( - R.string.notification_many_channel_count_summary, channelCount); - } - - return mContext.getResources().getQuantityString( - R.plurals.notification_few_channel_count_summary, channelCount, channelCount); - } - - private Intent getAppAndNotificationPageIntent() { - final String screenTitle = mContext.getText(R.string.app_and_notification_dashboard_title) - .toString(); - - return SliceBuilderUtils.buildSearchResultPageIntent(mContext, - AppAndNotificationDashboardFragment.class.getName(), "" /* key */, - screenTitle, - SettingsEnums.SLICE) - .setClassName(mContext.getPackageName(), SubSettings.class.getName()) - .setData(getUri()); - } - - private boolean isChannelEnabled(NotificationChannelGroup group, NotificationChannel channel, - NotificationBackend.AppRow appRow) { - final RestrictedLockUtils.EnforcedAdmin suspendedAppsAdmin = - RestrictedLockUtilsInternal.checkIfApplicationIsSuspended(mContext, mPackageName, - mUid); - - return suspendedAppsAdmin == null - && isChannelBlockable(channel, appRow) - && isChannelConfigurable(channel, appRow) - && !group.isBlocked(); - } - - private boolean isChannelConfigurable(NotificationChannel channel, - NotificationBackend.AppRow appRow) { - if (channel != null && appRow != null) { - return !channel.isImportanceLockedByOEM(); - } - - return false; - } - - private boolean isChannelBlockable(NotificationChannel channel, - NotificationBackend.AppRow appRow) { - if (channel != null && appRow != null) { - if (!appRow.systemApp) { - return true; - } - - return channel.isBlockable() - || channel.getImportance() == IMPORTANCE_NONE; - } - - return false; - } - - /** - * This class is used to sort notification channels according to notification sent count and - * notification id in {@link NotificationChannelSlice#CHANNEL_STATE_COMPARATOR}. - * - * Include {@link NotificationsSentState#avgSentWeekly} and {@link NotificationChannel#getId()} - * to get the number of notifications being sent and notification id. - */ - private static class NotificationChannelState { - - final private NotificationsSentState mNotificationsSentState; - final private NotificationChannel mNotificationChannel; - - public NotificationChannelState(NotificationsSentState notificationsSentState, - NotificationChannel notificationChannel) { - mNotificationsSentState = notificationsSentState; - mNotificationChannel = notificationChannel; - } - - public NotificationChannel getNotificationChannel() { - return mNotificationChannel; - } - - public NotificationsSentState getNotificationsSentState() { - return mNotificationsSentState; - } - } -} diff --git a/src/com/android/settings/homepage/contextualcards/slices/NotificationChannelWorker.java b/src/com/android/settings/homepage/contextualcards/slices/NotificationChannelWorker.java deleted file mode 100644 index f1d0d593cfa..00000000000 --- a/src/com/android/settings/homepage/contextualcards/slices/NotificationChannelWorker.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (C) 2019 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.homepage.contextualcards.slices; - -import static android.content.Context.MODE_PRIVATE; - -import static com.android.settings.homepage.contextualcards.slices.ContextualNotificationChannelSlice.PREFS; -import static com.android.settings.homepage.contextualcards.slices.ContextualNotificationChannelSlice.PREF_KEY_INTERACTED_PACKAGES; - -import android.content.Context; -import android.content.SharedPreferences; -import android.content.pm.PackageInfo; -import android.net.Uri; -import android.util.ArraySet; - -import com.android.settings.slices.SliceBackgroundWorker; - -import java.io.IOException; -import java.util.List; -import java.util.Set; -import java.util.stream.Collectors; - -public class NotificationChannelWorker extends SliceBackgroundWorker { - - public NotificationChannelWorker(Context context, Uri uri) { - super(context, uri); - } - - @Override - protected void onSlicePinned() { - } - - @Override - protected void onSliceUnpinned() { - removeUninstalledPackages(); - } - - @Override - public void close() throws IOException { - } - - private void removeUninstalledPackages() { - final SharedPreferences prefs = getContext().getSharedPreferences(PREFS, MODE_PRIVATE); - final Set interactedPackages = - prefs.getStringSet(PREF_KEY_INTERACTED_PACKAGES, new ArraySet()); - if (interactedPackages.isEmpty()) { - return; - } - - final List installedPackageInfos = - getContext().getPackageManager().getInstalledPackages(0); - final List installedPackages = installedPackageInfos.stream() - .map(packageInfo -> packageInfo.packageName) - .collect(Collectors.toList()); - final Set newInteractedPackages = new ArraySet<>(); - for (String packageName : interactedPackages) { - if (installedPackages.contains(packageName)) { - newInteractedPackages.add(packageName); - } - } - prefs.edit().putStringSet(PREF_KEY_INTERACTED_PACKAGES, newInteractedPackages).apply(); - } -} diff --git a/src/com/android/settings/homepage/contextualcards/slices/NotificationMultiChannelAppRow.java b/src/com/android/settings/homepage/contextualcards/slices/NotificationMultiChannelAppRow.java deleted file mode 100644 index bf91f53f3aa..00000000000 --- a/src/com/android/settings/homepage/contextualcards/slices/NotificationMultiChannelAppRow.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (C) 2019 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.homepage.contextualcards.slices; - -import android.app.role.RoleManager; -import android.content.Context; -import android.content.pm.PackageInfo; - -import com.android.settings.notification.NotificationBackend; - -import java.util.concurrent.Callable; - -/** - * This class is responsible for getting notification app row from package which has multiple - * notification channels.{@link NotificationChannelSlice} uses it to improve latency. - */ -class NotificationMultiChannelAppRow implements Callable { - - private final Context mContext; - private final NotificationBackend mNotificationBackend; - private final PackageInfo mPackageInfo; - - public NotificationMultiChannelAppRow(Context context, NotificationBackend notificationBackend, - PackageInfo packageInfo) { - mContext = context; - mNotificationBackend = notificationBackend; - mPackageInfo = packageInfo; - } - - @Override - public NotificationBackend.AppRow call() throws Exception { - final int channelCount = mNotificationBackend.getChannelCount( - mPackageInfo.applicationInfo.packageName, mPackageInfo.applicationInfo.uid); - if (channelCount > 1) { - return mNotificationBackend.loadAppRow(mContext, mContext.getPackageManager(), - mContext.getSystemService(RoleManager.class), mPackageInfo); - } - return null; - } -} diff --git a/src/com/android/settings/homepage/contextualcards/slices/SliceFullCardRendererHelper.java b/src/com/android/settings/homepage/contextualcards/slices/SliceFullCardRendererHelper.java index 3f35fb5ba1d..fd60959ab39 100644 --- a/src/com/android/settings/homepage/contextualcards/slices/SliceFullCardRendererHelper.java +++ b/src/com/android/settings/homepage/contextualcards/slices/SliceFullCardRendererHelper.java @@ -26,7 +26,6 @@ import androidx.slice.widget.SliceView; import com.android.settings.R; import com.android.settings.homepage.contextualcards.ContextualCard; -import com.android.settings.homepage.contextualcards.ContextualCardFeatureProvider; import com.android.settings.homepage.contextualcards.logging.ContextualCardLogUtils; import com.android.settings.overlay.FeatureFactory; import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; @@ -50,27 +49,19 @@ class SliceFullCardRendererHelper { final SliceViewHolder cardHolder = (SliceViewHolder) holder; cardHolder.sliceView.setScrollable(false); cardHolder.sliceView.setTag(card.getSliceUri()); - //TODO(b/114009676): We will soon have a field to decide what slice mode we should set. cardHolder.sliceView.setMode(SliceView.MODE_LARGE); cardHolder.sliceView.setSlice(slice); // Set this listener so we can log the interaction users make on the slice - cardHolder.sliceView.setOnSliceActionListener( - (eventInfo, sliceItem) -> { - final String log = ContextualCardLogUtils.buildCardClickLog(card, eventInfo.rowIndex, - eventInfo.actionType, cardHolder.getAdapterPosition()); + cardHolder.sliceView.setOnSliceActionListener((eventInfo, sliceItem) -> { + final String log = ContextualCardLogUtils.buildCardClickLog(card, eventInfo.rowIndex, + eventInfo.actionType, cardHolder.getAdapterPosition()); - final MetricsFeatureProvider metricsFeatureProvider = - FeatureFactory.getFactory(mContext).getMetricsFeatureProvider(); + final MetricsFeatureProvider metricsFeatureProvider = + FeatureFactory.getFactory(mContext).getMetricsFeatureProvider(); - metricsFeatureProvider.action(mContext, - SettingsEnums.ACTION_CONTEXTUAL_CARD_CLICK, log); - - final ContextualCardFeatureProvider contextualCardFeatureProvider = - FeatureFactory.getFactory(mContext).getContextualCardFeatureProvider( - mContext); - - contextualCardFeatureProvider.logNotificationPackage(slice); - }); + metricsFeatureProvider.action(mContext, + SettingsEnums.ACTION_CONTEXTUAL_CARD_CLICK, log); + }); // Customize slice view for Settings cardHolder.sliceView.setShowTitleItems(true); diff --git a/src/com/android/settings/slices/CustomSliceRegistry.java b/src/com/android/settings/slices/CustomSliceRegistry.java index 78a2943b1ef..12397e4c8b3 100644 --- a/src/com/android/settings/slices/CustomSliceRegistry.java +++ b/src/com/android/settings/slices/CustomSliceRegistry.java @@ -33,11 +33,9 @@ import com.android.settings.homepage.contextualcards.deviceinfo.StorageSlice; import com.android.settings.homepage.contextualcards.slices.BatteryFixSlice; import com.android.settings.homepage.contextualcards.slices.BluetoothDevicesSlice; import com.android.settings.homepage.contextualcards.slices.ContextualAdaptiveSleepSlice; -import com.android.settings.homepage.contextualcards.slices.ContextualNotificationChannelSlice; import com.android.settings.homepage.contextualcards.slices.DarkThemeSlice; import com.android.settings.homepage.contextualcards.slices.FaceSetupSlice; import com.android.settings.homepage.contextualcards.slices.LowStorageSlice; -import com.android.settings.homepage.contextualcards.slices.NotificationChannelSlice; import com.android.settings.location.LocationSlice; import com.android.settings.media.MediaOutputGroupSlice; import com.android.settings.media.MediaOutputIndicatorSlice; @@ -97,16 +95,6 @@ public class CustomSliceRegistry { .appendPath("bluetooth_devices") .build(); - /** - * Backing Uri for Contextual Notification channel Slice. - */ - public static final Uri CONTEXTUAL_NOTIFICATION_CHANNEL_SLICE_URI = new Uri.Builder() - .scheme(ContentResolver.SCHEME_CONTENT) - .authority(SettingsSliceProvider.SLICE_AUTHORITY) - .appendPath(SettingsSlicesContract.PATH_SETTING_ACTION) - .appendPath("contextual_notification_channel") - .build(); - /** * Backing Uri for the Wifi Slice. */ @@ -180,15 +168,6 @@ public class CustomSliceRegistry { .appendEncodedPath(SettingsSlicesContract.PATH_SETTING_ACTION) .appendPath("mobile_data") .build(); - /** - * Backing Uri for Notification channel Slice. - */ - public static final Uri NOTIFICATION_CHANNEL_SLICE_URI = new Uri.Builder() - .scheme(ContentResolver.SCHEME_CONTENT) - .authority(SettingsSliceProvider.SLICE_AUTHORITY) - .appendPath(SettingsSlicesContract.PATH_SETTING_ACTION) - .appendPath("notification_channel") - .build(); /** * Backing Uri for the storage slice. */ @@ -333,8 +312,6 @@ public class CustomSliceRegistry { sUriToSlice.put(BATTERY_FIX_SLICE_URI, BatteryFixSlice.class); sUriToSlice.put(BLUETOOTH_DEVICES_SLICE_URI, BluetoothDevicesSlice.class); sUriToSlice.put(CONTEXTUAL_ADAPTIVE_SLEEP_URI, ContextualAdaptiveSleepSlice.class); - sUriToSlice.put(CONTEXTUAL_NOTIFICATION_CHANNEL_SLICE_URI, - ContextualNotificationChannelSlice.class); sUriToSlice.put(CONTEXTUAL_WIFI_SLICE_URI, ContextualWifiSlice.class); sUriToSlice.put(FACE_ENROLL_SLICE_URI, FaceSetupSlice.class); sUriToSlice.put(FLASHLIGHT_SLICE_URI, FlashlightSlice.class); @@ -343,7 +320,6 @@ public class CustomSliceRegistry { sUriToSlice.put(MEDIA_OUTPUT_INDICATOR_SLICE_URI, MediaOutputIndicatorSlice.class); sUriToSlice.put(MEDIA_OUTPUT_SLICE_URI, MediaOutputSlice.class); sUriToSlice.put(MOBILE_DATA_SLICE_URI, MobileDataSlice.class); - sUriToSlice.put(NOTIFICATION_CHANNEL_SLICE_URI, NotificationChannelSlice.class); sUriToSlice.put(STORAGE_SLICE_URI, StorageSlice.class); sUriToSlice.put(WIFI_SLICE_URI, WifiSlice.class); sUriToSlice.put(DARK_THEME_SLICE_URI, DarkThemeSlice.class); diff --git a/tests/robotests/src/com/android/settings/homepage/contextualcards/ContextualCardFeatureProviderImplTest.java b/tests/robotests/src/com/android/settings/homepage/contextualcards/ContextualCardFeatureProviderImplTest.java index 029dde886d9..6f327ab4c25 100644 --- a/tests/robotests/src/com/android/settings/homepage/contextualcards/ContextualCardFeatureProviderImplTest.java +++ b/tests/robotests/src/com/android/settings/homepage/contextualcards/ContextualCardFeatureProviderImplTest.java @@ -16,40 +16,17 @@ package com.android.settings.homepage.contextualcards; -import static android.content.Context.MODE_PRIVATE; - -import static com.android.settings.homepage.contextualcards.slices.ContextualNotificationChannelSlice.PREFS; -import static com.android.settings.homepage.contextualcards.slices.ContextualNotificationChannelSlice.PREF_KEY_INTERACTED_PACKAGES; -import static com.android.settings.slices.CustomSliceRegistry.CONTEXTUAL_NOTIFICATION_CHANNEL_SLICE_URI; -import static com.android.settings.slices.CustomSliceRegistry.FLASHLIGHT_SLICE_URI; - import static com.google.common.truth.Truth.assertThat; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.spy; - import android.annotation.Nullable; -import android.app.PendingIntent; import android.content.ContentValues; import android.content.Context; -import android.content.Intent; -import android.content.SharedPreferences; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; -import android.net.Uri; -import android.os.Bundle; -import android.util.ArraySet; -import androidx.core.graphics.drawable.IconCompat; -import androidx.slice.Slice; import androidx.slice.SliceProvider; -import androidx.slice.builders.ListBuilder; -import androidx.slice.builders.SliceAction; import androidx.slice.widget.SliceLiveData; -import com.android.settings.R; -import com.android.settings.SettingsActivity; -import com.android.settings.applications.AppInfoBase; import com.android.settings.intelligence.ContextualCardProto; import org.junit.After; @@ -61,14 +38,12 @@ import org.robolectric.RuntimeEnvironment; import java.util.ArrayList; import java.util.List; -import java.util.Set; @RunWith(RobolectricTestRunner.class) public class ContextualCardFeatureProviderImplTest { private Context mContext; private ContextualCardFeatureProviderImpl mImpl; - private SharedPreferences mSharedPreferences; private CardDatabaseHelper mCardDatabaseHelper; private SQLiteDatabase mDatabase; @@ -76,7 +51,6 @@ public class ContextualCardFeatureProviderImplTest { public void setUp() { mContext = RuntimeEnvironment.application; mImpl = new ContextualCardFeatureProviderImpl(mContext); - mSharedPreferences = mContext.getSharedPreferences(PREFS, MODE_PRIVATE); // Set-up specs for SliceMetadata. SliceProvider.setSpecs(SliceLiveData.SUPPORTED_SPECS); mCardDatabaseHelper = CardDatabaseHelper.getInstance(mContext); @@ -87,7 +61,6 @@ public class ContextualCardFeatureProviderImplTest { public void tearDown() { CardDatabaseHelper.getInstance(mContext).close(); CardDatabaseHelper.sCardDatabaseHelper = null; - removeInteractedPackageFromSharedPreference(); } @Test @@ -128,37 +101,12 @@ public class ContextualCardFeatureProviderImplTest { assertThat(rowsUpdated).isEqualTo(0); } - @Test - public void logNotificationPackage_isContextualNotificationChannel_shouldLogPackage() { - final String packageName = "com.android.test.app"; - final Slice slice = buildSlice(CONTEXTUAL_NOTIFICATION_CHANNEL_SLICE_URI, packageName); - - mImpl.logNotificationPackage(slice); - - final Set interactedPackages = mSharedPreferences.getStringSet( - PREF_KEY_INTERACTED_PACKAGES, new ArraySet<>()); - assertThat(interactedPackages.contains(packageName)).isTrue(); - } - - @Test - public void logNotificationPackage_isNotContextualNotificationChannel_shouldNotLogPackage() { - final String packageName = "com.android.test.app"; - final Slice slice = buildSlice(FLASHLIGHT_SLICE_URI, packageName); - - mImpl.logNotificationPackage(slice); - - final Set interactedPackages = mSharedPreferences.getStringSet( - PREF_KEY_INTERACTED_PACKAGES, new ArraySet<>()); - assertThat(interactedPackages.contains(packageName)).isFalse(); - } - private static void insertFakeCard( SQLiteDatabase db, String name, double score, String uri, @Nullable Long time) { final ContentValues value = new ContentValues(); value.put(CardDatabaseHelper.CardColumns.NAME, name); value.put(CardDatabaseHelper.CardColumns.SCORE, score); value.put(CardDatabaseHelper.CardColumns.SLICE_URI, uri); - value.put(CardDatabaseHelper.CardColumns.TYPE, ContextualCard.CardType.SLICE); value.put(CardDatabaseHelper.CardColumns.CATEGORY, ContextualCardProto.ContextualCard.Category.DEFAULT.getNumber()); @@ -173,31 +121,4 @@ public class ContextualCardFeatureProviderImplTest { db.insert(CardDatabaseHelper.CARD_TABLE, null, value); } - - private Slice buildSlice(Uri sliceUri, String packageName) { - final Bundle args = new Bundle(); - args.putString(AppInfoBase.ARG_PACKAGE_NAME, packageName); - final Intent intent = new Intent("action"); - intent.putExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT_ARGUMENTS, args); - - final PendingIntent pendingIntent = spy( - PendingIntent.getActivity(mContext, 0 /* requestCode */, intent, 0 /* flags */)); - doReturn(intent).when(pendingIntent).getIntent(); - final IconCompat icon = IconCompat.createWithResource(mContext, R.drawable.empty_icon); - final SliceAction action = SliceAction.createDeeplink(pendingIntent, icon, - ListBuilder.SMALL_IMAGE, "title"); - - return new ListBuilder(mContext, sliceUri, ListBuilder.INFINITY) - .addRow(new ListBuilder.RowBuilder() - .addEndItem(icon, ListBuilder.ICON_IMAGE) - .setTitle("title") - .setPrimaryAction(action)) - .build(); - } - - private void removeInteractedPackageFromSharedPreference() { - if (mSharedPreferences.contains(PREF_KEY_INTERACTED_PACKAGES)) { - mSharedPreferences.edit().remove(PREF_KEY_INTERACTED_PACKAGES).apply(); - } - } } diff --git a/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/ContextualNotificationChannelSliceTest.java b/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/ContextualNotificationChannelSliceTest.java deleted file mode 100644 index 8541a30c9a9..00000000000 --- a/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/ContextualNotificationChannelSliceTest.java +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright (C) 2019 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.homepage.contextualcards.slices; - -import static android.content.Context.MODE_PRIVATE; - -import static com.android.settings.homepage.contextualcards.slices.ContextualNotificationChannelSlice.PREFS; -import static com.android.settings.homepage.contextualcards.slices.ContextualNotificationChannelSlice.PREF_KEY_INTERACTED_PACKAGES; - -import static com.google.common.truth.Truth.assertThat; - -import android.content.Context; -import android.content.SharedPreferences; -import android.net.Uri; -import android.util.ArraySet; - -import com.android.settings.R; -import com.android.settings.slices.CustomSliceRegistry; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; - -import java.util.Set; - -@RunWith(RobolectricTestRunner.class) -public class ContextualNotificationChannelSliceTest { - - private static final String PACKAGE_NAME = "package_name"; - - private Context mContext; - private ContextualNotificationChannelSlice mNotificationChannelSlice; - private SharedPreferences mSharedPreferences; - - @Before - public void setUp() { - mContext = RuntimeEnvironment.application; - mNotificationChannelSlice = new ContextualNotificationChannelSlice(mContext); - mSharedPreferences = mContext.getSharedPreferences(PREFS, MODE_PRIVATE); - } - - @After - public void tearDown() { - removeInteractedPackageFromSharedPreference(); - } - - @Test - public void getUri_shouldBeContextualNotificationChannelSliceUri() { - final Uri uri = mNotificationChannelSlice.getUri(); - - assertThat(uri).isEqualTo(CustomSliceRegistry.CONTEXTUAL_NOTIFICATION_CHANNEL_SLICE_URI); - } - - @Test - public void getSubTitle_shouldBeRecentlyInstalledApp() { - final CharSequence subTitle = mNotificationChannelSlice.getSubTitle("com.test.package", 0); - - assertThat(subTitle).isEqualTo(mContext.getText(R.string.recently_installed_app)); - } - - @Test - public void isUserInteracted_hasInteractedPackage_shouldBeTrue() { - addInteractedPackageToSharedPreference(); - - final boolean isInteracted = mNotificationChannelSlice.isUserInteracted(PACKAGE_NAME); - - assertThat(isInteracted).isTrue(); - } - - @Test - public void isUserInteracted_noInteractedPackage_shouldBeFalse() { - final boolean isInteracted = mNotificationChannelSlice.isUserInteracted(PACKAGE_NAME); - - assertThat(isInteracted).isFalse(); - } - - private void addInteractedPackageToSharedPreference() { - final Set interactedPackages = new ArraySet<>(); - interactedPackages.add(PACKAGE_NAME); - - mSharedPreferences.edit().putStringSet(PREF_KEY_INTERACTED_PACKAGES, - interactedPackages).apply(); - } - - private void removeInteractedPackageFromSharedPreference() { - if (mSharedPreferences.contains(PREF_KEY_INTERACTED_PACKAGES)) { - mSharedPreferences.edit().remove(PREF_KEY_INTERACTED_PACKAGES).apply(); - } - } -} diff --git a/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/NotificationChannelSliceTest.java b/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/NotificationChannelSliceTest.java deleted file mode 100644 index 335e99f0742..00000000000 --- a/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/NotificationChannelSliceTest.java +++ /dev/null @@ -1,420 +0,0 @@ -/* - * Copyright (C) 2019 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.homepage.contextualcards.slices; - -import static android.app.NotificationManager.IMPORTANCE_LOW; -import static android.app.NotificationManager.IMPORTANCE_NONE; -import static android.app.slice.Slice.HINT_LIST_ITEM; -import static android.app.slice.SliceItem.FORMAT_SLICE; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.spy; -import static org.robolectric.Shadows.shadowOf; - -import android.app.NotificationChannel; -import android.app.NotificationChannelGroup; -import android.app.role.RoleManager; -import android.content.Context; -import android.content.pm.ApplicationInfo; -import android.content.pm.PackageInfo; -import android.content.pm.PackageManager; -import android.content.pm.ParceledListSlice; -import android.util.ArrayMap; - -import androidx.core.graphics.drawable.IconCompat; -import androidx.slice.Slice; -import androidx.slice.SliceItem; -import androidx.slice.SliceMetadata; -import androidx.slice.SliceProvider; -import androidx.slice.core.SliceQuery; -import androidx.slice.widget.SliceLiveData; - -import com.android.settings.R; -import com.android.settings.notification.NotificationBackend; -import com.android.settings.notification.NotificationBackend.AppRow; -import com.android.settings.notification.NotificationBackend.NotificationsSentState; -import com.android.settings.testutils.shadow.ShadowRestrictedLockUtilsInternal; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; -import org.robolectric.annotation.Config; -import org.robolectric.shadows.ShadowPackageManager; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Map; - -@RunWith(RobolectricTestRunner.class) -public class NotificationChannelSliceTest { - private static final String APP_LABEL = "Example App"; - private static final int CHANNEL_COUNT = 3; - private static final String CHANNEL_NAME_PREFIX = "channel"; - private static final int NOTIFICATION_COUNT = - NotificationChannelSlice.MIN_NOTIFICATION_SENT_COUNT + 1; - private static final String PACKAGE_NAME = "com.test.notification.channel.slice"; - private static final int UID = 2019; - - @Mock - private NotificationBackend mNotificationBackend; - private Context mContext; - private IconCompat mIcon; - private NotificationChannelSlice mNotificationChannelSlice; - private ShadowPackageManager mPackageManager; - - @Before - public void setUp() { - MockitoAnnotations.initMocks(this); - mContext = RuntimeEnvironment.application; - - // Shadow PackageManager to add mock package. - mPackageManager = shadowOf(mContext.getPackageManager()); - - // Set-up specs for SliceMetadata. - SliceProvider.setSpecs(SliceLiveData.SUPPORTED_SPECS); - - mNotificationChannelSlice = spy(new NotificationChannelSlice(mContext)); - - doReturn(UID).when(mNotificationChannelSlice).getApplicationUid(any(String.class)); - mIcon = IconCompat.createWithResource(mContext, R.drawable.ic_settings_24dp); - doReturn(mIcon).when(mNotificationChannelSlice).getApplicationIcon(any(String.class)); - - // Assign mock NotificationBackend to build notification related data. - mNotificationChannelSlice.mNotificationBackend = mNotificationBackend; - } - - @After - public void tearDown() { - mPackageManager.removePackage(PACKAGE_NAME); - ShadowRestrictedLockUtilsInternal.reset(); - } - - @Test - @Config(shadows = ShadowRestrictedLockUtilsInternal.class) - public void getSlice_hasSuggestedApp_shouldHaveNotificationChannelTitle() { - addMockPackageToPackageManager(true /* isRecentlyInstalled */, - ApplicationInfo.FLAG_INSTALLED); - mockNotificationBackend(CHANNEL_COUNT, NOTIFICATION_COUNT, false /* banned */, - false /* isChannelBlocked */); - - final Slice slice = mNotificationChannelSlice.getSlice(); - - final SliceMetadata metadata = SliceMetadata.from(mContext, slice); - assertThat(metadata.getTitle()).isEqualTo( - mContext.getString(R.string.manage_app_notification, APP_LABEL)); - } - - @Test - @Config(shadows = ShadowRestrictedLockUtilsInternal.class) - public void getSlice_hasSuggestedApp_shouldSortByNotificationSentCount() { - addMockPackageToPackageManager(true /* isRecentlyInstalled */, - ApplicationInfo.FLAG_INSTALLED); - mockNotificationBackend(CHANNEL_COUNT, NOTIFICATION_COUNT, false /* banned */, - false /* isChannelBlocked */); - - final Slice slice = mNotificationChannelSlice.getSlice(); - - // Get all RowBuilders from Slice. - final List rowItems = SliceQuery.findAll(slice, FORMAT_SLICE, HINT_LIST_ITEM, - null /* nonHints */); - - // Ensure the total size of rows is equal to the notification channel count with header. - assertThat(rowItems).isNotNull(); - assertThat(rowItems.size()).isEqualTo(CHANNEL_COUNT + 1); - - // Remove the header of slice. - rowItems.remove(0); - - // Test the rows of slice are sorted with notification sent count by descending. - for (int i = 0; i < rowItems.size(); i++) { - // Assert the summary text is the same as expectation. - assertThat(getSummaryFromSliceItem(rowItems.get(i))).isEqualTo( - mContext.getResources().getQuantityString(R.plurals.notifications_sent_weekly, - CHANNEL_COUNT - i, CHANNEL_COUNT - i)); - } - } - - @Test - public void getSlice_noRecentlyInstalledApp_shouldHaveNoSuggestedAppTitle() { - addMockPackageToPackageManager(false /* isRecentlyInstalled */, - ApplicationInfo.FLAG_INSTALLED); - mockNotificationBackend(CHANNEL_COUNT, NOTIFICATION_COUNT, false /* banned */, - false /* isChannelBlocked */); - - final Slice slice = mNotificationChannelSlice.getSlice(); - - final SliceMetadata metadata = SliceMetadata.from(mContext, slice); - assertThat(metadata.getTitle()).isEqualTo(mContext.getString(R.string.no_suggested_app)); - } - - @Test - public void getSlice_noMultiChannelApp_shouldHaveNoSuggestedAppTitle() { - addMockPackageToPackageManager(true /* isRecentlyInstalled */, - ApplicationInfo.FLAG_INSTALLED); - mockNotificationBackend(1 /* channelCount */, NOTIFICATION_COUNT, false /* banned */, - false /* isChannelBlocked */); - - final Slice slice = mNotificationChannelSlice.getSlice(); - - final SliceMetadata metadata = SliceMetadata.from(mContext, slice); - assertThat(metadata.getTitle()).isEqualTo(mContext.getString(R.string.no_suggested_app)); - } - - @Test - @Config(shadows = ShadowRestrictedLockUtilsInternal.class) - public void getSlice_insufficientNotificationSentCount_shouldHaveNoSuggestedAppTitle() { - addMockPackageToPackageManager(true /* isRecentlyInstalled */, - ApplicationInfo.FLAG_INSTALLED); - mockNotificationBackend(CHANNEL_COUNT, 1 /* notificationCount */, false /* banned */, - false /* isChannelBlocked */); - - final Slice slice = mNotificationChannelSlice.getSlice(); - - final SliceMetadata metadata = SliceMetadata.from(mContext, slice); - assertThat(metadata.getTitle()).isEqualTo(mContext.getString(R.string.no_suggested_app)); - } - - @Test - public void getSlice_isSystemApp_shouldHaveNoSuggestedAppTitle() { - addMockPackageToPackageManager(true /* isRecentlyInstalled */, ApplicationInfo.FLAG_SYSTEM); - mockNotificationBackend(CHANNEL_COUNT, NOTIFICATION_COUNT, false /* banned */, - false /* isChannelBlocked */); - - final Slice slice = mNotificationChannelSlice.getSlice(); - - final SliceMetadata metadata = SliceMetadata.from(mContext, slice); - assertThat(metadata.getTitle()).isEqualTo(mContext.getString(R.string.no_suggested_app)); - } - - @Test - public void getSlice_isNotificationBanned_shouldHaveNoSuggestedAppTitle() { - addMockPackageToPackageManager(true /* isRecentlyInstalled */, - ApplicationInfo.FLAG_INSTALLED); - mockNotificationBackend(CHANNEL_COUNT, NOTIFICATION_COUNT, true /* banned */, - false /* isChannelBlocked */); - - final Slice slice = mNotificationChannelSlice.getSlice(); - - final SliceMetadata metadata = SliceMetadata.from(mContext, slice); - assertThat(metadata.getTitle()).isEqualTo(mContext.getString(R.string.no_suggested_app)); - } - - @Test - @Config(shadows = ShadowRestrictedLockUtilsInternal.class) - public void getSlice_exceedDefaultRowCount_shouldOnlyShowDefaultRows() { - addMockPackageToPackageManager(true /* isRecentlyInstalled */, - ApplicationInfo.FLAG_INSTALLED); - mockNotificationBackend(NotificationChannelSlice.DEFAULT_EXPANDED_ROW_COUNT * 2, - NOTIFICATION_COUNT, false /* banned */, false /* isChannelBlocked */); - - final Slice slice = mNotificationChannelSlice.getSlice(); - - // Get the number of RowBuilders from Slice. - final int rows = SliceQuery.findAll(slice, FORMAT_SLICE, HINT_LIST_ITEM, - null /* nonHints */).size(); - // The header of this slice is built by RowBuilder. Hence, the row count will contain it. - assertThat(rows).isEqualTo(NotificationChannelSlice.DEFAULT_EXPANDED_ROW_COUNT + 1); - } - - @Test - @Config(shadows = ShadowRestrictedLockUtilsInternal.class) - public void getSlice_channelCountIsLessThanDefaultRows_subTitleShouldNotHaveTapToManagerAll() { - addMockPackageToPackageManager(true /* isRecentlyInstalled */, - ApplicationInfo.FLAG_INSTALLED); - mockNotificationBackend(CHANNEL_COUNT - 1, NOTIFICATION_COUNT, false /* banned */, - false /* isChannelBlocked */); - - final Slice slice = mNotificationChannelSlice.getSlice(); - - final SliceMetadata metadata = SliceMetadata.from(mContext, slice); - assertThat(metadata.getSubtitle()).isEqualTo(mContext.getResources().getQuantityString( - R.plurals.notification_few_channel_count_summary, CHANNEL_COUNT - 1, - CHANNEL_COUNT - 1)); - } - - @Test - @Config(shadows = ShadowRestrictedLockUtilsInternal.class) - public void getSlice_channelCountIsEqualToDefaultRows_subTitleShouldNotHaveTapToManagerAll() { - addMockPackageToPackageManager(true /* isRecentlyInstalled */, - ApplicationInfo.FLAG_INSTALLED); - mockNotificationBackend(CHANNEL_COUNT, NOTIFICATION_COUNT, false /* banned */, - false /* isChannelBlocked */); - - final Slice slice = mNotificationChannelSlice.getSlice(); - - final SliceMetadata metadata = SliceMetadata.from(mContext, slice); - assertThat(metadata.getSubtitle()).isEqualTo(mContext.getResources().getQuantityString( - R.plurals.notification_few_channel_count_summary, CHANNEL_COUNT, CHANNEL_COUNT)); - } - - @Test - @Config(shadows = ShadowRestrictedLockUtilsInternal.class) - public void getSlice_channelCountIsMoreThanDefaultRows_subTitleShouldHaveTapToManagerAll() { - addMockPackageToPackageManager(true /* isRecentlyInstalled */, - ApplicationInfo.FLAG_INSTALLED); - mockNotificationBackend(CHANNEL_COUNT + 1, NOTIFICATION_COUNT, false /* banned */, - false /* isChannelBlocked */); - - final Slice slice = mNotificationChannelSlice.getSlice(); - - final SliceMetadata metadata = SliceMetadata.from(mContext, slice); - assertThat(metadata.getSubtitle()).isEqualTo( - mContext.getString(R.string.notification_many_channel_count_summary, - CHANNEL_COUNT + 1)); - } - - @Test - @Config(shadows = ShadowRestrictedLockUtilsInternal.class) - public void getSlice_isAllDisplayableChannelBlocked_shouldHaveNoSuggestedAppTitle() { - addMockPackageToPackageManager(true /* isRecentlyInstalled */, - ApplicationInfo.FLAG_INSTALLED); - mockNotificationBackend(CHANNEL_COUNT, NOTIFICATION_COUNT, false /* banned */, - true /* isChannelBlocked */); - - final Slice slice = mNotificationChannelSlice.getSlice(); - - final SliceMetadata metadata = SliceMetadata.from(mContext, slice); - assertThat(metadata.getTitle()).isEqualTo(mContext.getString(R.string.no_suggested_app)); - } - - @Test - @Config(shadows = ShadowRestrictedLockUtilsInternal.class) - public void getSlice_isInteractedPackage_shouldHaveNoSuggestedAppTitle() { - addMockPackageToPackageManager(true /* isRecentlyInstalled */, - ApplicationInfo.FLAG_INSTALLED); - mockNotificationBackend(CHANNEL_COUNT, NOTIFICATION_COUNT, false /* banned */, - false /* isChannelBlocked */); - doReturn(true).when(mNotificationChannelSlice).isUserInteracted(any(String.class)); - - final Slice slice = mNotificationChannelSlice.getSlice(); - - final SliceMetadata metadata = SliceMetadata.from(mContext, slice); - assertThat(metadata.getTitle()).isEqualTo(mContext.getString(R.string.no_suggested_app)); - } - - private void addMockPackageToPackageManager(boolean isRecentlyInstalled, int flags) { - final ApplicationInfo applicationInfo = new ApplicationInfo(); - applicationInfo.name = APP_LABEL; - applicationInfo.uid = UID; - applicationInfo.flags = flags; - applicationInfo.packageName = PACKAGE_NAME; - - final PackageInfo packageInfo = new PackageInfo(); - packageInfo.packageName = PACKAGE_NAME; - packageInfo.applicationInfo = applicationInfo; - packageInfo.firstInstallTime = createAppInstallTime(isRecentlyInstalled); - mPackageManager.addPackage(packageInfo); - } - - private long createAppInstallTime(boolean isRecentlyInstalled) { - if (isRecentlyInstalled) { - return System.currentTimeMillis() - NotificationChannelSlice.DURATION_END_DAYS; - } - - return System.currentTimeMillis(); - } - - private void mockNotificationBackend(int channelCount, int notificationCount, boolean banned, - boolean isChannelBlocked) { - final List channels = buildNotificationChannel(channelCount, - isChannelBlocked); - final AppRow appRow = buildAppRow(channelCount, notificationCount, banned); - - doReturn(buildNotificationChannelGroups(channels)).when(mNotificationBackend).getGroups( - any(String.class), any(int.class)); - doReturn(appRow).when(mNotificationBackend).loadAppRow(any(Context.class), - any(PackageManager.class), any(RoleManager.class), any(PackageInfo.class)); - doReturn(channelCount).when(mNotificationBackend).getChannelCount( - any(String.class), any(int.class)); - } - - private AppRow buildAppRow(int channelCount, int sentCount, boolean banned) { - final AppRow appRow = new AppRow(); - appRow.pkg = PACKAGE_NAME; - appRow.uid = UID; - appRow.banned = banned; - appRow.channelCount = channelCount; - appRow.sentByApp = new NotificationsSentState(); - appRow.sentByApp.sentCount = sentCount; - appRow.sentByChannel = buildNotificationSentStates(channelCount, sentCount); - - return appRow; - } - - private List buildNotificationChannel(int channelCount, - boolean isChannelBlock) { - final List channels = new ArrayList<>(); - for (int i = 0; i < channelCount; i++) { - channels.add(new NotificationChannel(CHANNEL_NAME_PREFIX + i, CHANNEL_NAME_PREFIX + i, - isChannelBlock ? IMPORTANCE_NONE : IMPORTANCE_LOW)); - } - - return channels; - } - - private ParceledListSlice buildNotificationChannelGroups( - List channels) { - final NotificationChannelGroup notificationChannelGroup = new NotificationChannelGroup( - "group", "group"); - notificationChannelGroup.setBlocked(false); - notificationChannelGroup.setChannels(channels); - - return new ParceledListSlice(Arrays.asList(notificationChannelGroup)); - } - - private Map buildNotificationSentStates(int channelCount, - int sentCount) { - final Map states = new ArrayMap<>(); - for (int i = 0; i < channelCount; i++) { - final NotificationsSentState state = new NotificationsSentState(); - // Set the avgSentWeekly for each channel: channel0 is 1, channel1: 2, channel2: 3. - state.avgSentWeekly = i + 1; - state.sentCount = sentCount; - states.put(CHANNEL_NAME_PREFIX + i, state); - } - - return states; - } - - private CharSequence getSummaryFromSliceItem(SliceItem rowItem) { - if (rowItem == null) { - return null; - } - - final Slice rowSlice = rowItem.getSlice(); - if (rowSlice == null) { - return null; - } - - final List rowSliceItems = rowSlice.getItems(); - if (rowSliceItems == null || rowSliceItems.size() < 2) { - return null; - } - - // Index 0: title; Index 1: summary. - return rowSliceItems.get(1).getText(); - } -} diff --git a/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/NotificationChannelWorkerTest.java b/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/NotificationChannelWorkerTest.java deleted file mode 100644 index 6ac8b708262..00000000000 --- a/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/NotificationChannelWorkerTest.java +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Copyright (C) 2019 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.homepage.contextualcards.slices; - -import static android.content.Context.MODE_PRIVATE; - -import static com.android.settings.homepage.contextualcards.slices.ContextualNotificationChannelSlice.PREFS; -import static com.android.settings.homepage.contextualcards.slices.ContextualNotificationChannelSlice.PREF_KEY_INTERACTED_PACKAGES; - -import static com.google.common.truth.Truth.assertThat; - -import static org.robolectric.Shadows.shadowOf; - -import android.content.Context; -import android.content.SharedPreferences; -import android.content.pm.PackageInfo; -import android.net.Uri; -import android.util.ArraySet; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; -import org.robolectric.shadows.ShadowPackageManager; - -import java.util.Set; - -@RunWith(RobolectricTestRunner.class) -public class NotificationChannelWorkerTest { - private static final Uri URI = Uri.parse("content://com.android.settings.slices/test"); - private static final String PACKAGE_NAME = "com.test.notification.channel.slice"; - - private Context mContext; - private NotificationChannelWorker mNotificationChannelWorker; - private ShadowPackageManager mPackageManager; - private SharedPreferences mSharedPreferences; - - - @Before - public void setUp() { - mContext = RuntimeEnvironment.application; - mNotificationChannelWorker = new NotificationChannelWorker(mContext, URI); - - // Shadow PackageManager to add mock package. - mPackageManager = shadowOf(mContext.getPackageManager()); - - mSharedPreferences = mContext.getSharedPreferences(PREFS, MODE_PRIVATE); - addInteractedPackageToSharedPreference(); - } - - @After - public void tearDown() { - mPackageManager.removePackage(PACKAGE_NAME); - removeInteractedPackageFromSharedPreference(); - } - - @Test - public void onSliceUnpinned_interactedPackageIsUninstalled_shouldRemovePackage() { - mNotificationChannelWorker.onSliceUnpinned(); - - final Set interactedPackages = mSharedPreferences.getStringSet( - PREF_KEY_INTERACTED_PACKAGES, new ArraySet<>()); - assertThat(interactedPackages.contains(PACKAGE_NAME)).isFalse(); - } - - @Test - public void onSliceUnpinned_interactedPackageIsInstalled_shouldKeepPackage() { - mockInteractedPackageAsInstalled(); - - mNotificationChannelWorker.onSliceUnpinned(); - - final Set interactedPackages = mSharedPreferences.getStringSet( - PREF_KEY_INTERACTED_PACKAGES, new ArraySet<>()); - assertThat(interactedPackages.contains(PACKAGE_NAME)).isTrue(); - } - - private void mockInteractedPackageAsInstalled() { - final PackageInfo packageInfo = new PackageInfo(); - packageInfo.packageName = PACKAGE_NAME; - mPackageManager.addPackage(packageInfo); - } - - private void addInteractedPackageToSharedPreference() { - final Set interactedPackages = new ArraySet<>(); - interactedPackages.add(PACKAGE_NAME); - - mSharedPreferences.edit().putStringSet(PREF_KEY_INTERACTED_PACKAGES, - interactedPackages).apply(); - } - - private void removeInteractedPackageFromSharedPreference() { - if (mSharedPreferences.contains(PREF_KEY_INTERACTED_PACKAGES)) { - mSharedPreferences.edit().remove(PREF_KEY_INTERACTED_PACKAGES).apply(); - } - } -} diff --git a/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/NotificationMultiChannelAppRowTest.java b/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/NotificationMultiChannelAppRowTest.java deleted file mode 100644 index c6222f1d23a..00000000000 --- a/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/NotificationMultiChannelAppRowTest.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright (C) 2019 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.homepage.contextualcards.slices; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.verify; - -import android.app.role.RoleManager; -import android.content.Context; -import android.content.pm.ApplicationInfo; -import android.content.pm.PackageInfo; -import android.content.pm.PackageManager; - -import com.android.settings.notification.NotificationBackend; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; - -@RunWith(RobolectricTestRunner.class) -public class NotificationMultiChannelAppRowTest { - - @Mock - private NotificationBackend mNotificationBackend; - private Context mContext; - private NotificationMultiChannelAppRow mNotificationMultiChannelAppRow; - private PackageInfo mPackageInfo; - - @Before - public void setUp() { - MockitoAnnotations.initMocks(this); - - mContext = RuntimeEnvironment.application; - mPackageInfo = new PackageInfo(); - mPackageInfo.applicationInfo = new ApplicationInfo(); - mPackageInfo.applicationInfo.packageName = "com.android.test"; - mNotificationMultiChannelAppRow = new NotificationMultiChannelAppRow(mContext, - mNotificationBackend, mPackageInfo); - } - - @Test - public void call_isMultiChannel_shouldLoadAppRow() throws Exception { - doReturn(3).when(mNotificationBackend).getChannelCount(any(String.class), - any(int.class)); - - mNotificationMultiChannelAppRow.call(); - - verify(mNotificationBackend).loadAppRow(any(Context.class), any(PackageManager.class), - any(RoleManager.class), any(PackageInfo.class)); - } - - @Test - public void call_isNotMultiChannel_shouldNotLoadAppRow() throws Exception { - doReturn(1).when(mNotificationBackend).getChannelCount(any(String.class), - any(int.class)); - - mNotificationMultiChannelAppRow.call(); - - verify(mNotificationBackend, never()).loadAppRow(any(Context.class), - any(PackageManager.class), any(RoleManager.class), any(PackageInfo.class)); - } -} diff --git a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowRestrictedLockUtilsInternal.java b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowRestrictedLockUtilsInternal.java index d98379cb2c1..e39056cedf3 100644 --- a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowRestrictedLockUtilsInternal.java +++ b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowRestrictedLockUtilsInternal.java @@ -37,7 +37,6 @@ public class ShadowRestrictedLockUtilsInternal { private static DevicePolicyManager sDevicePolicyManager; private static String[] sDisabledTypes; private static int sKeyguardDisabledFeatures; - private static boolean sIsSuspended; @Resetter public static void reset() { @@ -46,7 +45,6 @@ public class ShadowRestrictedLockUtilsInternal { sKeyguardDisabledFeatures = 0; sDisabledTypes = new String[0]; sMaximumTimeToLockIsSet = false; - sIsSuspended = false; } @Implementation @@ -103,12 +101,6 @@ public class ShadowRestrictedLockUtilsInternal { return sMaximumTimeToLockIsSet ? new EnforcedAdmin() : null; } - @Implementation - protected static EnforcedAdmin checkIfApplicationIsSuspended(Context context, - String packageName, int userId) { - return sIsSuspended ? new EnforcedAdmin() : null; - } - public static void setRestricted(boolean restricted) { sIsRestricted = restricted; } @@ -140,8 +132,4 @@ public class ShadowRestrictedLockUtilsInternal { public static void setMaximumTimeToLockIsSet(boolean isSet) { sMaximumTimeToLockIsSet = isSet; } - - public static void setSuspended(boolean suspended) { - sIsRestricted = suspended; - } }