Add ability to exclude apps from adjustments
Specifically bundling and summarization Test: BundleManageAppsPreferenceControllerTest Test: AdjustmentExcludedAppsPreferenceControllerTest Test: SummarizationManageAppsPreferenceControllerTest Flag: android.app.nm_summarization Flag: android.app.notification_classification_ui Bug: 390415383 Bug: 377697346 Change-Id: Ica4b77212f4660624bfe12be7e6c9c584cd2c812
This commit is contained in:
@@ -56,4 +56,27 @@
|
||||
android:key="recs"
|
||||
android:title="@*android:string/recs_notification_channel_label"
|
||||
settings:controller="com.android.settings.notification.BundleTypePreferenceController"/>
|
||||
|
||||
<PreferenceCategory
|
||||
android:key="notification_bundle_excluded_apps_list"
|
||||
android:title="@string/notification_excluded_apps"
|
||||
settings:controller="com.android.settings.notification.AdjustmentExcludedAppsPreferenceController">
|
||||
<com.android.settingslib.widget.TopIntroPreference
|
||||
android:key="excluded_description"
|
||||
android:title="@string/notification_bundle_excluded_description"/>
|
||||
|
||||
<!-- apps are added here -->
|
||||
|
||||
<Preference
|
||||
android:key="notification_bundle_manage_apps"
|
||||
android:order="1000"
|
||||
android:icon="@drawable/ic_chevron_right_24dp"
|
||||
android:title="@string/notification_summarization_manage_excluded_apps"
|
||||
settings:controller="com.android.settings.notification.BundleManageAppsPreferenceController"
|
||||
android:fragment="com.android.settings.applications.manageapplications.ManageApplications">
|
||||
<extra
|
||||
android:name="classname"
|
||||
android:value="com.android.settings.Settings$NotificationExcludeClassificationActivity"/>
|
||||
</Preference>
|
||||
</PreferenceCategory>
|
||||
</PreferenceScreen>
|
||||
|
@@ -36,4 +36,29 @@
|
||||
android:key="global_pref"
|
||||
android:title="@string/notification_summarization_main_control_title"
|
||||
settings:controller="com.android.settings.notification.SummarizationGlobalPreferenceController" />
|
||||
|
||||
<PreferenceCategory
|
||||
android:key="notification_summarization_excluded_apps_list"
|
||||
android:title="@string/notification_excluded_apps"
|
||||
settings:controller="com.android.settings.notification.AdjustmentExcludedAppsPreferenceController">
|
||||
<com.android.settingslib.widget.TopIntroPreference
|
||||
android:key="excluded_description"
|
||||
android:title="@string/notification_summarization_excluded_description"/>
|
||||
|
||||
<!-- apps are added here -->
|
||||
|
||||
<Preference
|
||||
android:key="notification_summarization_manage_apps"
|
||||
android:order="1000"
|
||||
android:icon="@drawable/ic_chevron_right_24dp"
|
||||
android:title="@string/notification_summarization_manage_excluded_apps"
|
||||
settings:controller="com.android.settings.notification.SummarizationManageAppsPreferenceController"
|
||||
android:fragment="com.android.settings.applications.manageapplications.ManageApplications">
|
||||
<extra
|
||||
android:name="classname"
|
||||
android:value="com.android.settings.Settings$NotificationExcludeSummarizationActivity"/>
|
||||
</Preference>
|
||||
</PreferenceCategory>
|
||||
|
||||
|
||||
</PreferenceScreen>
|
||||
|
@@ -358,6 +358,8 @@ public class Settings extends SettingsActivity {
|
||||
public static class AppBubbleNotificationSettingsActivity extends SettingsActivity { /* empty */ }
|
||||
public static class NotificationAssistantSettingsActivity extends SettingsActivity{ /* empty */ }
|
||||
public static class NotificationAppListActivity extends SettingsActivity { /* empty */ }
|
||||
public static class NotificationExcludeSummarizationActivity extends SettingsActivity { /* empty */ }
|
||||
public static class NotificationExcludeClassificationActivity extends SettingsActivity { /* empty */ }
|
||||
/** Activity to manage Cloned Apps page */
|
||||
public static class ClonedAppsListActivity extends SettingsActivity { /* empty */ }
|
||||
/** Activity to manage Aspect Ratio app list page */
|
||||
|
@@ -270,6 +270,8 @@ public class ManageApplications extends InstrumentedFragment
|
||||
public static final int LIST_TYPE_NFC_TAG_APPS = 18;
|
||||
public static final int LIST_TYPE_TURN_SCREEN_ON = 19;
|
||||
public static final int LIST_TYPE_USER_ASPECT_RATIO_APPS = 20;
|
||||
public static final int LIST_TYPE_NOTIFICATION_EXCLUDE_SUMMARIZATION = 21;
|
||||
public static final int LIST_TYPE_NOTIFICATION_EXCLUDE_CLASSIFICATION = 22;
|
||||
|
||||
// List types that should show instant apps.
|
||||
public static final Set<Integer> LIST_TYPES_WITH_INSTANT = new ArraySet<>(Arrays.asList(
|
||||
|
@@ -31,6 +31,8 @@ import com.android.settings.Settings.ManageExternalSourcesActivity
|
||||
import com.android.settings.Settings.ManageExternalStorageActivity
|
||||
import com.android.settings.Settings.MediaManagementAppsActivity
|
||||
import com.android.settings.Settings.NotificationAppListActivity
|
||||
import com.android.settings.Settings.NotificationExcludeClassificationActivity
|
||||
import com.android.settings.Settings.NotificationExcludeSummarizationActivity
|
||||
import com.android.settings.Settings.NotificationReviewPermissionsActivity
|
||||
import com.android.settings.Settings.OverlaySettingsActivity
|
||||
import com.android.settings.Settings.StorageUseActivity
|
||||
@@ -44,6 +46,8 @@ import com.android.settings.applications.manageapplications.ManageApplications.L
|
||||
import com.android.settings.applications.manageapplications.ManageApplications.LIST_TYPE_USER_ASPECT_RATIO_APPS
|
||||
import com.android.settings.applications.manageapplications.ManageApplications.LIST_TYPE_BATTERY_OPTIMIZATION
|
||||
import com.android.settings.applications.manageapplications.ManageApplications.LIST_TYPE_CLONED_APPS
|
||||
import com.android.settings.applications.manageapplications.ManageApplications.LIST_TYPE_NOTIFICATION_EXCLUDE_CLASSIFICATION
|
||||
import com.android.settings.applications.manageapplications.ManageApplications.LIST_TYPE_NOTIFICATION_EXCLUDE_SUMMARIZATION
|
||||
import com.android.settings.applications.manageapplications.ManageApplications.LIST_TYPE_GAMES
|
||||
import com.android.settings.applications.manageapplications.ManageApplications.LIST_TYPE_HIGH_POWER
|
||||
import com.android.settings.applications.manageapplications.ManageApplications.LIST_TYPE_LONG_BACKGROUND_TASKS
|
||||
@@ -99,6 +103,9 @@ object ManageApplicationsUtil {
|
||||
ChangeNfcTagAppsActivity::class to LIST_TYPE_NFC_TAG_APPS,
|
||||
TurnScreenOnSettingsActivity::class to LIST_TYPE_TURN_SCREEN_ON,
|
||||
UserAspectRatioAppListActivity::class to LIST_TYPE_USER_ASPECT_RATIO_APPS,
|
||||
NotificationExcludeSummarizationActivity::class to LIST_TYPE_NOTIFICATION_EXCLUDE_SUMMARIZATION,
|
||||
NotificationExcludeClassificationActivity::class to LIST_TYPE_NOTIFICATION_EXCLUDE_CLASSIFICATION,
|
||||
|
||||
)
|
||||
|
||||
@JvmField
|
||||
@@ -117,7 +124,7 @@ object ManageApplicationsUtil {
|
||||
LIST_TYPE_MEDIA_MANAGEMENT_APPS -> MediaManagementAppsAppListProvider.getAppListRoute()
|
||||
LIST_TYPE_ALARMS_AND_REMINDERS -> AlarmsAndRemindersAppListProvider.getAppListRoute()
|
||||
LIST_TYPE_WIFI_ACCESS -> WifiControlAppListProvider.getAppListRoute()
|
||||
LIST_TYPE_NOTIFICATION -> AppListNotificationsPageProvider.name
|
||||
LIST_TYPE_NOTIFICATION -> AppListNotificationsPageProvider.AllApps.name
|
||||
LIST_TYPE_APPS_LOCALE -> AppLanguagesPageProvider.name
|
||||
LIST_TYPE_MAIN -> AllAppListPageProvider.name
|
||||
LIST_TYPE_NFC_TAG_APPS -> NfcTagAppsSettingsProvider.getAppListRoute()
|
||||
@@ -128,6 +135,8 @@ object ManageApplicationsUtil {
|
||||
//LIST_TYPE_STORAGE -> StorageAppListPageProvider.Apps.name
|
||||
//LIST_TYPE_GAMES -> StorageAppListPageProvider.Games.name
|
||||
LIST_TYPE_BATTERY_OPTIMIZATION -> BatteryOptimizationModeAppListPageProvider.name
|
||||
LIST_TYPE_NOTIFICATION_EXCLUDE_SUMMARIZATION -> AppListNotificationsPageProvider.ExcludeSummarization.name
|
||||
LIST_TYPE_NOTIFICATION_EXCLUDE_CLASSIFICATION -> AppListNotificationsPageProvider.ExcludeClassification.name
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,212 @@
|
||||
/*
|
||||
* Copyright (C) 2025 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.settings.notification;
|
||||
|
||||
import static android.service.notification.Adjustment.KEY_SUMMARIZATION;
|
||||
import static android.service.notification.Adjustment.KEY_TYPE;
|
||||
|
||||
import android.app.Flags;
|
||||
import android.content.Context;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.service.notification.Adjustment;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
import androidx.core.text.BidiFormatter;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.preference.Preference;
|
||||
import androidx.preference.PreferenceCategory;
|
||||
import androidx.preference.PreferenceScreen;
|
||||
|
||||
import com.android.settings.core.BasePreferenceController;
|
||||
import com.android.settings.core.PreferenceControllerMixin;
|
||||
import com.android.settingslib.applications.AppUtils;
|
||||
import com.android.settingslib.applications.ApplicationsState;
|
||||
import com.android.settingslib.utils.ThreadUtils;
|
||||
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Adds a preference to the PreferenceCategory for every app excluded from an adjustment key
|
||||
*/
|
||||
public class AdjustmentExcludedAppsPreferenceController extends BasePreferenceController
|
||||
implements PreferenceControllerMixin {
|
||||
|
||||
@NonNull private NotificationBackend mBackend;
|
||||
|
||||
@Nullable String mAdjustmentKey;
|
||||
@Nullable @VisibleForTesting ApplicationsState mApplicationsState;
|
||||
@VisibleForTesting PreferenceCategory mPreferenceCategory;
|
||||
@VisibleForTesting Context mPrefContext;
|
||||
|
||||
private ApplicationsState.Session mAppSession;
|
||||
|
||||
public AdjustmentExcludedAppsPreferenceController(@NonNull Context context,
|
||||
@NonNull String preferenceKey) {
|
||||
super(context, preferenceKey);
|
||||
mBackend = new NotificationBackend();
|
||||
}
|
||||
|
||||
protected void onAttach(@Nullable ApplicationsState appState, @Nullable Fragment host,
|
||||
@NonNull NotificationBackend helperBackend, @Adjustment.Keys String adjustment) {
|
||||
mApplicationsState = appState;
|
||||
mBackend = helperBackend;
|
||||
mAdjustmentKey = adjustment;
|
||||
|
||||
if (mApplicationsState != null && host != null) {
|
||||
mAppSession = mApplicationsState.newSession(mAppSessionCallbacks, host.getLifecycle());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void displayPreference(@NonNull PreferenceScreen screen) {
|
||||
mPreferenceCategory = screen.findPreference(getPreferenceKey());
|
||||
mPrefContext = screen.getContext();
|
||||
updateAppList();
|
||||
super.displayPreference(screen);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAvailabilityStatus() {
|
||||
if (!(Flags.nmSummarization() || Flags.nmSummarizationUi()
|
||||
|| Flags.notificationClassificationUi())) {
|
||||
return CONDITIONALLY_UNAVAILABLE;
|
||||
}
|
||||
if (KEY_SUMMARIZATION.equals(mAdjustmentKey)
|
||||
&& mBackend.isNotificationSummarizationSupported()) {
|
||||
return AVAILABLE;
|
||||
}
|
||||
if (KEY_TYPE.equals(mAdjustmentKey) && mBackend.isNotificationBundlingSupported()) {
|
||||
return AVAILABLE;
|
||||
}
|
||||
return CONDITIONALLY_UNAVAILABLE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Call this method to trigger the app list to refresh.
|
||||
*/
|
||||
public void updateAppList() {
|
||||
if (mAppSession == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
ApplicationsState.AppFilter filter = android.multiuser.Flags.enablePrivateSpaceFeatures()
|
||||
&& android.multiuser.Flags.handleInterleavedSettingsForPrivateSpace()
|
||||
? ApplicationsState.FILTER_ENABLED_NOT_QUIET
|
||||
: ApplicationsState.FILTER_ALL_ENABLED;
|
||||
mAppSession.rebuild(filter, ApplicationsState.ALPHA_COMPARATOR);
|
||||
}
|
||||
|
||||
// Set the icon for the given preference to the entry icon from cache if available, or look
|
||||
// it up.
|
||||
private void updateIcon(Preference pref, ApplicationsState.AppEntry entry) {
|
||||
synchronized (entry) {
|
||||
final Drawable cachedIcon = AppUtils.getIconFromCache(entry);
|
||||
if (cachedIcon != null && entry.mounted) {
|
||||
pref.setIcon(cachedIcon);
|
||||
} else {
|
||||
ListenableFuture unused = ThreadUtils.postOnBackgroundThread(() -> {
|
||||
final Drawable icon = AppUtils.getIcon(mPrefContext, entry);
|
||||
if (icon != null) {
|
||||
ThreadUtils.postOnMainThread(() -> pref.setIcon(icon));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
void updateAppList(List<ApplicationsState.AppEntry> apps) {
|
||||
if (mPreferenceCategory == null || apps == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<String> excludedApps = List.of(mBackend.getAdjustmentDeniedPackages(mAdjustmentKey));
|
||||
|
||||
for (ApplicationsState.AppEntry app : apps) {
|
||||
String pkg = app.info.packageName;
|
||||
final String key = getKey(pkg, app.info.uid);
|
||||
boolean doesAppPassCriteria = false;
|
||||
|
||||
if (excludedApps.contains(pkg)) {
|
||||
doesAppPassCriteria = true;
|
||||
}
|
||||
Preference pref = mPreferenceCategory.findPreference(key);
|
||||
if (pref == null) {
|
||||
if (doesAppPassCriteria) {
|
||||
// does not exist but should
|
||||
pref = new Preference(mPrefContext);
|
||||
pref.setKey(key);
|
||||
pref.setTitle(BidiFormatter.getInstance().unicodeWrap(app.label));
|
||||
updateIcon(pref, app);
|
||||
mPreferenceCategory.addPreference(pref);
|
||||
}
|
||||
} else if (!doesAppPassCriteria) {
|
||||
// exists but shouldn't anymore
|
||||
mPreferenceCategory.removePreference(pref);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a unique key to identify an AppPreference
|
||||
*/
|
||||
static String getKey(String pkg, int uid) {
|
||||
return "all|" + pkg + "|" + uid;
|
||||
}
|
||||
|
||||
private final ApplicationsState.Callbacks mAppSessionCallbacks =
|
||||
new ApplicationsState.Callbacks() {
|
||||
|
||||
@Override
|
||||
public void onRunningStateChanged(boolean running) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPackageListChanged() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRebuildComplete(@NonNull ArrayList<ApplicationsState.AppEntry> apps) {
|
||||
updateAppList(apps);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPackageIconChanged() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPackageSizeChanged(@NonNull String packageName) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAllSizesComputed() { }
|
||||
|
||||
@Override
|
||||
public void onLauncherInfoChanged() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoadEntriesCompleted() {
|
||||
updateAppList();
|
||||
}
|
||||
};
|
||||
}
|
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright (C) 2025 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.settings.notification;
|
||||
|
||||
import android.app.Flags;
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.android.settings.core.BasePreferenceController;
|
||||
|
||||
public class BundleManageAppsPreferenceController extends
|
||||
BasePreferenceController {
|
||||
|
||||
NotificationBackend mBackend;
|
||||
|
||||
public BundleManageAppsPreferenceController(@NonNull Context context,
|
||||
@NonNull String preferenceKey) {
|
||||
super(context, preferenceKey);
|
||||
mBackend = new NotificationBackend();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAvailabilityStatus() {
|
||||
if (Flags.notificationClassificationUi() && mBackend.isNotificationBundlingSupported()) {
|
||||
return AVAILABLE;
|
||||
}
|
||||
return CONDITIONALLY_UNAVAILABLE;
|
||||
}
|
||||
}
|
@@ -16,6 +16,11 @@
|
||||
|
||||
package com.android.settings.notification;
|
||||
|
||||
import static android.service.notification.Adjustment.KEY_SUMMARIZATION;
|
||||
import static android.service.notification.Adjustment.KEY_TYPE;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.Application;
|
||||
import android.app.settings.SettingsEnums;
|
||||
import android.content.Context;
|
||||
import android.app.Flags;
|
||||
@@ -25,6 +30,7 @@ import androidx.lifecycle.Lifecycle;
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.dashboard.DashboardFragment;
|
||||
import com.android.settings.search.BaseSearchIndexProvider;
|
||||
import com.android.settingslib.applications.ApplicationsState;
|
||||
import com.android.settingslib.search.SearchIndexable;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -49,6 +55,26 @@ public class BundlePreferenceFragment extends DashboardFragment {
|
||||
return "BundlePreferenceFragment";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttach(Context context) {
|
||||
super.onAttach(context);
|
||||
if (use(AdjustmentExcludedAppsPreferenceController.class) != null) {
|
||||
final Activity activity = getActivity();
|
||||
Application app = null;
|
||||
ApplicationsState appState = null;
|
||||
if (activity != null) {
|
||||
app = activity.getApplication();
|
||||
} else {
|
||||
app = null;
|
||||
}
|
||||
if (app != null) {
|
||||
appState = ApplicationsState.getInstance(app);
|
||||
}
|
||||
use(AdjustmentExcludedAppsPreferenceController.class).onAttach(
|
||||
appState, this, new NotificationBackend(), KEY_TYPE);
|
||||
}
|
||||
}
|
||||
|
||||
public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
|
||||
new BaseSearchIndexProvider(R.xml.bundle_notifications_settings) {
|
||||
|
||||
|
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (C) 2025 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.settings.notification;
|
||||
|
||||
import android.app.Flags;
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.android.settings.core.BasePreferenceController;
|
||||
|
||||
public class SummarizationManageAppsPreferenceController extends
|
||||
BasePreferenceController {
|
||||
|
||||
NotificationBackend mBackend;
|
||||
|
||||
public SummarizationManageAppsPreferenceController(@NonNull Context context,
|
||||
@NonNull String preferenceKey) {
|
||||
super(context, preferenceKey);
|
||||
mBackend = new NotificationBackend();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAvailabilityStatus() {
|
||||
if ((Flags.nmSummarization() || Flags.nmSummarizationUi())
|
||||
&& mBackend.isNotificationSummarizationSupported()) {
|
||||
return AVAILABLE;
|
||||
}
|
||||
return CONDITIONALLY_UNAVAILABLE;
|
||||
}
|
||||
}
|
@@ -16,13 +16,19 @@
|
||||
|
||||
package com.android.settings.notification;
|
||||
|
||||
import static android.service.notification.Adjustment.KEY_SUMMARIZATION;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.Application;
|
||||
import android.app.Flags;
|
||||
import android.app.settings.SettingsEnums;
|
||||
import android.content.Context;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.dashboard.DashboardFragment;
|
||||
import com.android.settings.notification.app.HeaderPreferenceController;
|
||||
import com.android.settings.search.BaseSearchIndexProvider;
|
||||
import com.android.settingslib.applications.ApplicationsState;
|
||||
import com.android.settingslib.search.SearchIndexable;
|
||||
|
||||
/**
|
||||
@@ -45,6 +51,26 @@ public class SummarizationPreferenceFragment extends DashboardFragment {
|
||||
return "SummarizationPreferenceFragment";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttach(Context context) {
|
||||
super.onAttach(context);
|
||||
if (use(AdjustmentExcludedAppsPreferenceController.class) != null) {
|
||||
final Activity activity = getActivity();
|
||||
Application app = null;
|
||||
ApplicationsState appState = null;
|
||||
if (activity != null) {
|
||||
app = activity.getApplication();
|
||||
} else {
|
||||
app = null;
|
||||
}
|
||||
if (app != null) {
|
||||
appState = ApplicationsState.getInstance(app);
|
||||
}
|
||||
use(AdjustmentExcludedAppsPreferenceController.class).onAttach(
|
||||
appState, this, new NotificationBackend(), KEY_SUMMARIZATION);
|
||||
}
|
||||
}
|
||||
|
||||
public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
|
||||
new BaseSearchIndexProvider(R.xml.summarization_notifications_settings) {
|
||||
|
||||
|
@@ -45,7 +45,6 @@ import com.android.settings.spa.app.specialaccess.WifiControlAppListProvider
|
||||
import com.android.settings.spa.app.specialaccess.WriteSystemPreferencesAppListProvider
|
||||
import com.android.settings.spa.app.storage.StorageAppListPageProvider
|
||||
import com.android.settings.spa.core.instrumentation.SpaLogMetricsProvider
|
||||
import com.android.settings.spa.core.instrumentation.SpaLogProvider
|
||||
import com.android.settings.spa.development.UsageStatsPageProvider
|
||||
import com.android.settings.spa.development.compat.PlatformCompatAppListPageProvider
|
||||
import com.android.settings.spa.home.HomePageProvider
|
||||
@@ -106,7 +105,9 @@ open class SettingsSpaEnvironment(context: Context) : SpaEnvironment(context) {
|
||||
AppInfoSettingsProvider,
|
||||
SpecialAppAccessPageProvider,
|
||||
NotificationMainPageProvider,
|
||||
AppListNotificationsPageProvider,
|
||||
AppListNotificationsPageProvider.AllApps,
|
||||
AppListNotificationsPageProvider.ExcludeClassification,
|
||||
AppListNotificationsPageProvider.ExcludeSummarization,
|
||||
SystemMainPageProvider,
|
||||
LanguageAndInputPageProvider,
|
||||
AppLanguagesPageProvider,
|
||||
|
@@ -17,34 +17,72 @@
|
||||
package com.android.settings.spa.notification
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import com.android.settings.R
|
||||
import com.android.settingslib.spa.framework.common.SettingsPageProvider
|
||||
import com.android.settingslib.spa.framework.compose.navigator
|
||||
import com.android.settingslib.spa.framework.compose.rememberContext
|
||||
import com.android.settingslib.spa.widget.preference.Preference
|
||||
import com.android.settingslib.spa.widget.preference.PreferenceModel
|
||||
import com.android.settingslib.spaprivileged.template.app.AppList
|
||||
import com.android.settingslib.spaprivileged.template.app.AppListInput
|
||||
import com.android.settingslib.spaprivileged.template.app.AppListPage
|
||||
|
||||
object AppListNotificationsPageProvider : SettingsPageProvider {
|
||||
override val name = "AppListNotifications"
|
||||
|
||||
sealed class AppListNotificationsPageProvider(private val type: ListType) : SettingsPageProvider {
|
||||
@Composable
|
||||
override fun Page(arguments: Bundle?) {
|
||||
AppListPage(
|
||||
title = stringResource(R.string.app_notifications_title),
|
||||
listModel = rememberContext(::AppNotificationsListModel),
|
||||
)
|
||||
NotificationsAppListPage(type)
|
||||
}
|
||||
|
||||
object AllApps : AppListNotificationsPageProvider(ListType.Apps) {
|
||||
override val name = "AppListNotifications"
|
||||
|
||||
@Composable
|
||||
fun EntryItem() {
|
||||
val summary = stringResource(R.string.app_notification_field_summary)
|
||||
Preference(object : PreferenceModel {
|
||||
override val title = stringResource(R.string.app_notifications_title)
|
||||
override val title = stringResource(ListType.Apps.titleResource)
|
||||
override val summary = { summary }
|
||||
override val onClick = navigator(name)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
object ExcludeSummarization : AppListNotificationsPageProvider(ListType.ExcludeSummarization) {
|
||||
override val name = "NotificationsExcludeSummarization"
|
||||
}
|
||||
|
||||
object ExcludeClassification : AppListNotificationsPageProvider(ListType.ExcludeClassification) {
|
||||
override val name = "NotificationsExcludeClassification"
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun NotificationsAppListPage(
|
||||
type: ListType,
|
||||
appList: @Composable AppListInput<AppNotificationsRecord>.() -> Unit = { AppList() }
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
AppListPage(
|
||||
title = stringResource(type.titleResource),
|
||||
listModel = remember(context) { AppNotificationsListModel(context, type) },
|
||||
appList = appList,
|
||||
)
|
||||
}
|
||||
|
||||
sealed class ListType(
|
||||
@StringRes val titleResource: Int
|
||||
) {
|
||||
object Apps : ListType(
|
||||
titleResource = R.string.app_notifications_title,
|
||||
)
|
||||
object ExcludeSummarization : ListType(
|
||||
titleResource = R.string.notification_summarization_manage_excluded_apps_title,
|
||||
)
|
||||
object ExcludeClassification : ListType(
|
||||
titleResource = R.string.notification_bundle_manage_excluded_apps_title,
|
||||
)
|
||||
}
|
@@ -17,12 +17,16 @@
|
||||
package com.android.settings.spa.notification
|
||||
|
||||
import android.content.pm.ApplicationInfo
|
||||
import android.service.notification.Adjustment
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import com.android.settings.spa.app.storage.StorageAppListModel
|
||||
import com.android.settings.spa.app.storage.StorageType
|
||||
|
||||
class AppNotificationController(
|
||||
private val repository: AppNotificationRepository,
|
||||
private val app: ApplicationInfo,
|
||||
private val listType: ListType,
|
||||
) {
|
||||
val isEnabled: LiveData<Boolean>
|
||||
get() = _isEnabled
|
||||
@@ -47,4 +51,62 @@ class AppNotificationController(
|
||||
postValue(it)
|
||||
}
|
||||
}
|
||||
|
||||
val isAllowed: LiveData<Boolean>
|
||||
get() = _isAllowed
|
||||
|
||||
fun getAllowed() = _isAllowed.get()
|
||||
|
||||
fun setAllowed(enabled: Boolean) {
|
||||
when (listType) {
|
||||
ListType.ExcludeSummarization -> {
|
||||
if (repository.setAdjustmentSupportedForPackage(
|
||||
app, Adjustment.KEY_SUMMARIZATION, enabled)) {
|
||||
_isAllowed.postValue(enabled)
|
||||
}
|
||||
}
|
||||
ListType.ExcludeClassification -> {
|
||||
if (repository.setAdjustmentSupportedForPackage(
|
||||
app, Adjustment.KEY_TYPE, enabled)) {
|
||||
_isAllowed.postValue(enabled)
|
||||
}
|
||||
}
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
|
||||
private val _isAllowed = object : MutableLiveData<Boolean>() {
|
||||
override fun onActive() {
|
||||
when (listType) {
|
||||
ListType.ExcludeSummarization -> {
|
||||
postValue(repository.isAdjustmentSupportedForPackage(
|
||||
app, Adjustment.KEY_SUMMARIZATION))
|
||||
}
|
||||
ListType.ExcludeClassification -> {
|
||||
postValue(repository.isAdjustmentSupportedForPackage(
|
||||
app, Adjustment.KEY_TYPE))
|
||||
}
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onInactive() {
|
||||
}
|
||||
|
||||
fun get(): Boolean = when (listType) {
|
||||
ListType.ExcludeSummarization -> {
|
||||
value ?: repository.isAdjustmentSupportedForPackage(
|
||||
app, Adjustment.KEY_SUMMARIZATION).also {
|
||||
postValue(it)
|
||||
}
|
||||
}
|
||||
ListType.ExcludeClassification -> {
|
||||
value ?: repository.isAdjustmentSupportedForPackage(
|
||||
app, Adjustment.KEY_TYPE).also {
|
||||
postValue(it)
|
||||
}
|
||||
}
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -126,6 +126,20 @@ class AppNotificationRepository(
|
||||
}
|
||||
}
|
||||
|
||||
fun isAdjustmentSupportedForPackage(app: ApplicationInfo, key: String): Boolean =
|
||||
notificationManager.isAdjustmentSupportedForPackage(key, app.packageName)
|
||||
|
||||
fun setAdjustmentSupportedForPackage(app: ApplicationInfo, key: String, enabled: Boolean):
|
||||
Boolean {
|
||||
return try {
|
||||
notificationManager.setAdjustmentSupportedForPackage(key, app.packageName, enabled)
|
||||
true
|
||||
} catch (e: Exception) {
|
||||
Log.w(TAG, "Error calling INotificationManager", e)
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fun isUserUnlocked(user: Int): Boolean {
|
||||
return try {
|
||||
userManager.isUserUnlocked(user)
|
||||
|
@@ -36,6 +36,7 @@ import com.android.settingslib.spaprivileged.model.app.AppListModel
|
||||
import com.android.settingslib.spaprivileged.model.app.AppRecord
|
||||
import com.android.settingslib.spaprivileged.model.app.userId
|
||||
import com.android.settingslib.spaprivileged.template.app.AppListItemModel
|
||||
import com.android.settingslib.spaprivileged.template.app.AppListSwitchItem
|
||||
import com.android.settingslib.spaprivileged.template.app.AppListTwoTargetSwitchItem
|
||||
import com.android.settingslib.utils.StringUtil
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
@@ -52,6 +53,7 @@ data class AppNotificationsRecord(
|
||||
|
||||
class AppNotificationsListModel(
|
||||
private val context: Context,
|
||||
private val listType: ListType
|
||||
) : AppListModel<AppNotificationsRecord> {
|
||||
private val repository = AppNotificationRepository(context)
|
||||
private val now = System.currentTimeMillis()
|
||||
@@ -64,7 +66,7 @@ class AppNotificationsListModel(
|
||||
AppNotificationsRecord(
|
||||
app = app,
|
||||
sentState = usageEvents[app.packageName],
|
||||
controller = AppNotificationController(repository, app),
|
||||
controller = AppNotificationController(repository, app, listType),
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -129,6 +131,22 @@ class AppNotificationsListModel(
|
||||
|
||||
@Composable
|
||||
override fun AppListItemModel<AppNotificationsRecord>.AppItem() {
|
||||
when (listType) {
|
||||
ListType.ExcludeSummarization -> {
|
||||
AppListSwitchItem(
|
||||
checked = record.controller.isAllowed.observeAsCallback(),
|
||||
changeable = { true },
|
||||
onCheckedChange = record.controller::setAllowed,
|
||||
)
|
||||
}
|
||||
ListType.ExcludeClassification -> {
|
||||
AppListSwitchItem(
|
||||
checked = record.controller.isAllowed.observeAsCallback(),
|
||||
changeable = { true },
|
||||
onCheckedChange = record.controller::setAllowed,
|
||||
)
|
||||
}
|
||||
else -> {
|
||||
val changeable by produceState(initialValue = false) {
|
||||
withContext(Dispatchers.Default) {
|
||||
value = repository.isChangeable(record.app)
|
||||
@@ -141,6 +159,8 @@ class AppNotificationsListModel(
|
||||
onCheckedChange = record.controller::setEnabled,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun navigateToAppNotificationSettings(app: ApplicationInfo) {
|
||||
AppInfoBase.startAppInfoFragment(
|
||||
|
@@ -41,7 +41,7 @@ object NotificationMainPageProvider : SettingsPageProvider {
|
||||
@Composable
|
||||
override fun Page(arguments: Bundle?) {
|
||||
RegularScaffold(title = getTitle(arguments)) {
|
||||
AppListNotificationsPageProvider.EntryItem()
|
||||
AppListNotificationsPageProvider.AllApps.EntryItem()
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -0,0 +1,151 @@
|
||||
/*
|
||||
* Copyright (C) 2025 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.settings.notification;
|
||||
|
||||
import static android.service.notification.Adjustment.KEY_SUMMARIZATION;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.app.Flags;
|
||||
import android.app.INotificationManager;
|
||||
import android.content.Context;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.platform.test.annotations.EnableFlags;
|
||||
import android.platform.test.flag.junit.SetFlagsRule;
|
||||
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.preference.Preference;
|
||||
import androidx.preference.PreferenceCategory;
|
||||
import androidx.preference.PreferenceManager;
|
||||
import androidx.preference.PreferenceScreen;
|
||||
|
||||
import com.android.settingslib.applications.ApplicationsState;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
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 java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
@EnableFlags({Flags.FLAG_NM_SUMMARIZATION_UI, Flags.FLAG_NM_SUMMARIZATION,
|
||||
Flags.FLAG_NOTIFICATION_CLASSIFICATION_UI})
|
||||
public class AdjustmentExcludedAppsPreferenceControllerTest {
|
||||
|
||||
@Rule
|
||||
public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
|
||||
|
||||
@Mock
|
||||
private NotificationBackend mBackend;
|
||||
@Mock
|
||||
private ApplicationsState mApplicationState;
|
||||
private AdjustmentExcludedAppsPreferenceController mController;
|
||||
private Context mContext;
|
||||
@Mock
|
||||
INotificationManager mInm;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mContext = RuntimeEnvironment.application;
|
||||
|
||||
mController = new AdjustmentExcludedAppsPreferenceController(mContext, "key");
|
||||
mController.onAttach(null, mock(Fragment.class), mBackend, KEY_SUMMARIZATION);
|
||||
PreferenceScreen screen = new PreferenceManager(mContext).createPreferenceScreen(mContext);
|
||||
mController.mPreferenceCategory = new PreferenceCategory(mContext);
|
||||
screen.addPreference(mController.mPreferenceCategory);
|
||||
|
||||
mController.mApplicationsState = mApplicationState;
|
||||
mController.mPrefContext = mContext;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsAvailable() {
|
||||
when(mBackend.isNotificationBundlingSupported()).thenReturn(true);
|
||||
when(mBackend.isNotificationSummarizationSupported()).thenReturn(true);
|
||||
assertThat(mController.isAvailable()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isAvailable_flagEnabledNasDoesNotSupport_shouldReturnFalse() throws Exception {
|
||||
when(mInm.getUnsupportedAdjustmentTypes()).thenReturn(List.of(KEY_SUMMARIZATION));
|
||||
assertThat(mController.isAvailable()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateAppList() throws Exception {
|
||||
when(mBackend.getAdjustmentDeniedPackages(KEY_SUMMARIZATION)).thenReturn(
|
||||
new String[] {"cannot", "cannot2"});
|
||||
|
||||
// GIVEN there are four apps, and two have KEY_SUMMARIZATION off
|
||||
ApplicationsState.AppEntry canSummarize =
|
||||
mock(ApplicationsState.AppEntry.class);
|
||||
canSummarize.info = new ApplicationInfo();
|
||||
canSummarize.info.packageName = "canSummarize";
|
||||
canSummarize.info.uid = 0;
|
||||
|
||||
ApplicationsState.AppEntry canSummarize2 = mock(ApplicationsState.AppEntry.class);
|
||||
canSummarize2.info = new ApplicationInfo();
|
||||
canSummarize2.info.packageName = "canSummarizeTwo";
|
||||
canSummarize2.info.uid = 0;
|
||||
|
||||
ApplicationsState.AppEntry cannot =
|
||||
mock(ApplicationsState.AppEntry.class);
|
||||
cannot.info = new ApplicationInfo();
|
||||
cannot.info.packageName = "cannot";
|
||||
cannot.info.uid = 0;
|
||||
|
||||
ApplicationsState.AppEntry cannot2 =
|
||||
mock(ApplicationsState.AppEntry.class);
|
||||
cannot2.info = new ApplicationInfo();
|
||||
cannot2.info.packageName = "cannot2";
|
||||
cannot2.info.uid = 0;
|
||||
|
||||
List<ApplicationsState.AppEntry> appEntries = new ArrayList<>();
|
||||
appEntries.add(canSummarize);
|
||||
appEntries.add(canSummarize2);
|
||||
appEntries.add(cannot);
|
||||
appEntries.add(cannot2);
|
||||
|
||||
// WHEN the controller updates the app list with the app entries
|
||||
mController.updateAppList(appEntries);
|
||||
|
||||
// THEN only the 'cannot' entries make it to the app list
|
||||
assertThat(mController.mPreferenceCategory.getPreferenceCount()).isEqualTo(2);
|
||||
assertThat((Preference) mController.mPreferenceCategory.findPreference(
|
||||
AdjustmentExcludedAppsPreferenceController.getKey(
|
||||
cannot.info.packageName,cannot.info.uid))).isNotNull();
|
||||
assertThat((Preference) mController.mPreferenceCategory.findPreference(
|
||||
AdjustmentExcludedAppsPreferenceController.getKey(
|
||||
cannot2.info.packageName,cannot2.info.uid))).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateAppList_nullApps() {
|
||||
mController.updateAppList(null);
|
||||
assertThat(mController.mPreferenceCategory.getPreferenceCount()).isEqualTo(0);
|
||||
}
|
||||
}
|
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright (C) 2025 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.settings.notification;
|
||||
|
||||
import static android.service.notification.Adjustment.KEY_SUMMARIZATION;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.app.Flags;
|
||||
import android.app.INotificationManager;
|
||||
import android.content.Context;
|
||||
import android.platform.test.flag.junit.SetFlagsRule;
|
||||
import android.service.notification.Adjustment;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
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 java.util.List;
|
||||
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
public class BundleManageAppsPreferenceControllerTest {
|
||||
@Rule
|
||||
public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
|
||||
|
||||
private static final String PREFERENCE_KEY = "preference_key";
|
||||
|
||||
private Context mContext;
|
||||
BundleManageAppsPreferenceController mController;
|
||||
@Mock
|
||||
INotificationManager mInm;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mContext = RuntimeEnvironment.application;
|
||||
mSetFlagsRule.enableFlags(Flags.FLAG_NOTIFICATION_CLASSIFICATION_UI);
|
||||
mController = new BundleManageAppsPreferenceController(mContext, PREFERENCE_KEY);
|
||||
mController.mBackend.setNm(mInm);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isAvailable_flagEnabledNasSupports_shouldReturnTrue() {
|
||||
assertThat(mController.isAvailable()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isAvailable_flagEnabledNasDoesNotSupport_shouldReturnFalse() throws Exception {
|
||||
when(mInm.getUnsupportedAdjustmentTypes()).thenReturn(List.of(Adjustment.KEY_TYPE));
|
||||
assertThat(mController.isAvailable()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isAvailable_flagDisabledNasSupports_shouldReturnFalse() {
|
||||
mSetFlagsRule.disableFlags(Flags.FLAG_NOTIFICATION_CLASSIFICATION_UI);
|
||||
assertThat(mController.isAvailable()).isFalse();
|
||||
}
|
||||
}
|
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright (C) 2025 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.settings.notification;
|
||||
|
||||
import static android.service.notification.Adjustment.KEY_IMPORTANCE;
|
||||
import static android.service.notification.Adjustment.KEY_SUMMARIZATION;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.app.Flags;
|
||||
import android.app.INotificationManager;
|
||||
import android.content.Context;
|
||||
import android.platform.test.flag.junit.SetFlagsRule;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
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 java.util.List;
|
||||
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
public class SummarizationManageAppsPreferenceControllerTest {
|
||||
@Rule
|
||||
public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
|
||||
|
||||
private static final String PREFERENCE_KEY = "preference_key";
|
||||
|
||||
private Context mContext;
|
||||
SummarizationManageAppsPreferenceController mController;
|
||||
@Mock
|
||||
INotificationManager mInm;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mContext = RuntimeEnvironment.application;
|
||||
mSetFlagsRule.enableFlags(Flags.FLAG_NM_SUMMARIZATION, Flags.FLAG_NM_SUMMARIZATION_UI);
|
||||
mController = new SummarizationManageAppsPreferenceController(mContext, PREFERENCE_KEY);
|
||||
mController.mBackend.setNm(mInm);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isAvailable_flagEnabledNasSupports_shouldReturnTrue() {
|
||||
assertThat(mController.isAvailable()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isAvailable_flagEnabledNasDoesNotSupport_shouldReturnFalse() throws Exception {
|
||||
when(mInm.getUnsupportedAdjustmentTypes()).thenReturn(List.of(KEY_SUMMARIZATION));
|
||||
assertThat(mController.isAvailable()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isAvailable_flagDisabledNasSupports_shouldReturnFalse() {
|
||||
mSetFlagsRule.disableFlags(Flags.FLAG_NM_SUMMARIZATION);
|
||||
mSetFlagsRule.disableFlags(Flags.FLAG_NM_SUMMARIZATION_UI);
|
||||
assertThat(mController.isAvailable()).isFalse();
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user