Loading res/values/strings.xml +7 −0 Original line number Diff line number Diff line Loading @@ -8774,6 +8774,13 @@ <!-- App Info > Notifications: Title for section where notifications bundles can be configured [CHAR LIMIT=80]--> <string name="notification_bundles">Notification bundles</string> <!-- App Info > Notifications: Title for section controlling whether this app may show notifications in a promoted format [CHAR LIMIT=80] --> <string name="live_notifications">Live notifications</string> <!-- App Info > Notifications: Text on the switch to enable or disable an app from showing notifications in a live/promoted format [CHAR LIMIT=50] --> <string name="live_notifications_switch">Show live info</string> <!-- App Info > Notifications: Text accompanying the "Show live info" switch explaining the purpose of the setting --> <string name="live_notifications_desc">Pinned notifications display live info from apps, and always appear on the status bar and lock screen</string> <!-- Configure Notifications: Title for the notification bubbles option. [CHAR LIMIT=60] --> <string name="notification_bubbles_title">Bubbles</string> <!-- Title for the toggle shown on the app-level bubbles page [CHAR LIMIT=60] --> res/xml/app_notification_settings.xml +17 −0 Original line number Diff line number Diff line Loading @@ -30,6 +30,23 @@ <Preference android:key="block_desc" /> <!-- Whether the app can show promoted notifications --> <PreferenceCategory android:title="@string/live_notifications" android:key="promoted_category" android:visibility="gone"> <com.android.settingslib.RestrictedSwitchPreference android:key="promoted_switch" android:title="@string/live_notifications_switch" /> <Preference android:key="promoted_desc" android:summary="@string/live_notifications_desc" android:selectable="false"/> </PreferenceCategory> <!-- Conversations added here --> <PreferenceCategory android:title="@string/conversations_category_title" Loading src/com/android/settings/notification/NotificationBackend.java +34 −2 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ import static android.content.pm.LauncherApps.ShortcutQuery.FLAG_MATCH_PINNED_BY import static com.android.server.notification.Flags.notificationHideUnusedChannels; import android.app.Flags; import android.app.INotificationManager; import android.app.NotificationChannel; import android.app.NotificationChannelGroup; Loading Loading @@ -66,11 +67,9 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Set; public class NotificationBackend { private static final String TAG = "NotificationBackend"; Loading Loading @@ -102,6 +101,9 @@ public class NotificationBackend { row.blockedChannelCount = getBlockedChannelCount(row.pkg, row.uid); row.channelCount = getChannelCount(row.pkg, row.uid); recordAggregatedUsageEvents(context, row); if (Flags.uiRichOngoing()) { row.canBePromoted = canBePromoted(row.pkg, row.uid); } return row; } Loading Loading @@ -707,6 +709,35 @@ public class NotificationBackend { } } /** * Retrieves whether the app with given package and uid is permitted to post promoted * notifications. */ public boolean canBePromoted(String pkg, int uid) { try { return sINM.appCanBePromoted(pkg, uid); } catch (Exception e) { Log.w(TAG, "Error calling NoMan", e); return false; } } /** * Sets whether the app with given package and uid is permitted to post promoted notifications. */ public void setCanBePromoted(String pkg, int uid, boolean allowed) { // We shouldn't get here with the flag off, but just in case, do nothing. if (!Flags.uiRichOngoing()) { Log.wtf(TAG, "tried to setCanBePromoted without flag on"); return; } try { sINM.setCanBePromoted(pkg, uid, allowed, /* fromUser= */ true); } catch (Exception e) { Log.w(TAG, "Error calling NoMan", e); } } @VisibleForTesting void setNm(INotificationManager inm) { sINM = inm; Loading Loading @@ -748,5 +779,6 @@ public class NotificationBackend { public Map<String, NotificationsSentState> sentByChannel; public NotificationsSentState sentByApp; public boolean showAllChannels = true; public boolean canBePromoted; } } src/com/android/settings/notification/app/AppNotificationSettings.java +1 −0 Original line number Diff line number Diff line Loading @@ -104,6 +104,7 @@ public class AppNotificationSettings extends NotificationSettings { mControllers.add(new ShowMorePreferenceController( context, mDependentFieldListener, mBackend)); mControllers.add(new BundleListPreferenceController(context, mBackend)); mControllers.add(new PromotedNotificationsPreferenceController(context, mBackend)); return new ArrayList<>(mControllers); } } src/com/android/settings/notification/app/PromotedNotificationsPreferenceController.java 0 → 100644 +83 −0 Original line number Diff line number Diff line /* * Copyright (C) 2024 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.app; import android.app.Flags; import android.content.Context; import androidx.annotation.NonNull; import androidx.preference.Preference; import androidx.preference.PreferenceCategory; import com.android.settings.notification.NotificationBackend; import com.android.settingslib.RestrictedSwitchPreference; public class PromotedNotificationsPreferenceController extends NotificationPreferenceController implements Preference.OnPreferenceChangeListener { private static final String KEY_PROMOTED_CATEGORY = "promoted_category"; private static final String KEY_PROMOTED_SWITCH = "promoted_switch"; public PromotedNotificationsPreferenceController(@NonNull Context context, @NonNull NotificationBackend backend) { super(context, backend); } @Override @NonNull public String getPreferenceKey() { return KEY_PROMOTED_CATEGORY; } @Override public boolean isAvailable() { if (!Flags.uiRichOngoing()) { return false; } return super.isAvailable(); } @Override boolean isIncludedInFilter() { // not a channel-specific preference; only at the app level return false; } /** * Updates the state of the promoted notifications switch. Because this controller governs * the full PreferenceCategory, we must find the switch preference within the category first. */ public void updateState(@NonNull Preference preference) { PreferenceCategory category = (PreferenceCategory) preference; RestrictedSwitchPreference pref = category.findPreference(KEY_PROMOTED_SWITCH); if (pref != null && mAppRow != null) { pref.setDisabledByAdmin(mAdmin); pref.setEnabled(!pref.isDisabledByAdmin()); pref.setChecked(mAppRow.canBePromoted); pref.setOnPreferenceChangeListener(this); } } @Override public boolean onPreferenceChange(@NonNull Preference preference, @NonNull Object newValue) { final boolean canBePromoted = (Boolean) newValue; if (mAppRow != null && mAppRow.canBePromoted != canBePromoted) { mAppRow.canBePromoted = canBePromoted; mBackend.setCanBePromoted(mAppRow.pkg, mAppRow.uid, canBePromoted); } return true; } } Loading
res/values/strings.xml +7 −0 Original line number Diff line number Diff line Loading @@ -8774,6 +8774,13 @@ <!-- App Info > Notifications: Title for section where notifications bundles can be configured [CHAR LIMIT=80]--> <string name="notification_bundles">Notification bundles</string> <!-- App Info > Notifications: Title for section controlling whether this app may show notifications in a promoted format [CHAR LIMIT=80] --> <string name="live_notifications">Live notifications</string> <!-- App Info > Notifications: Text on the switch to enable or disable an app from showing notifications in a live/promoted format [CHAR LIMIT=50] --> <string name="live_notifications_switch">Show live info</string> <!-- App Info > Notifications: Text accompanying the "Show live info" switch explaining the purpose of the setting --> <string name="live_notifications_desc">Pinned notifications display live info from apps, and always appear on the status bar and lock screen</string> <!-- Configure Notifications: Title for the notification bubbles option. [CHAR LIMIT=60] --> <string name="notification_bubbles_title">Bubbles</string> <!-- Title for the toggle shown on the app-level bubbles page [CHAR LIMIT=60] -->
res/xml/app_notification_settings.xml +17 −0 Original line number Diff line number Diff line Loading @@ -30,6 +30,23 @@ <Preference android:key="block_desc" /> <!-- Whether the app can show promoted notifications --> <PreferenceCategory android:title="@string/live_notifications" android:key="promoted_category" android:visibility="gone"> <com.android.settingslib.RestrictedSwitchPreference android:key="promoted_switch" android:title="@string/live_notifications_switch" /> <Preference android:key="promoted_desc" android:summary="@string/live_notifications_desc" android:selectable="false"/> </PreferenceCategory> <!-- Conversations added here --> <PreferenceCategory android:title="@string/conversations_category_title" Loading
src/com/android/settings/notification/NotificationBackend.java +34 −2 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ import static android.content.pm.LauncherApps.ShortcutQuery.FLAG_MATCH_PINNED_BY import static com.android.server.notification.Flags.notificationHideUnusedChannels; import android.app.Flags; import android.app.INotificationManager; import android.app.NotificationChannel; import android.app.NotificationChannelGroup; Loading Loading @@ -66,11 +67,9 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Set; public class NotificationBackend { private static final String TAG = "NotificationBackend"; Loading Loading @@ -102,6 +101,9 @@ public class NotificationBackend { row.blockedChannelCount = getBlockedChannelCount(row.pkg, row.uid); row.channelCount = getChannelCount(row.pkg, row.uid); recordAggregatedUsageEvents(context, row); if (Flags.uiRichOngoing()) { row.canBePromoted = canBePromoted(row.pkg, row.uid); } return row; } Loading Loading @@ -707,6 +709,35 @@ public class NotificationBackend { } } /** * Retrieves whether the app with given package and uid is permitted to post promoted * notifications. */ public boolean canBePromoted(String pkg, int uid) { try { return sINM.appCanBePromoted(pkg, uid); } catch (Exception e) { Log.w(TAG, "Error calling NoMan", e); return false; } } /** * Sets whether the app with given package and uid is permitted to post promoted notifications. */ public void setCanBePromoted(String pkg, int uid, boolean allowed) { // We shouldn't get here with the flag off, but just in case, do nothing. if (!Flags.uiRichOngoing()) { Log.wtf(TAG, "tried to setCanBePromoted without flag on"); return; } try { sINM.setCanBePromoted(pkg, uid, allowed, /* fromUser= */ true); } catch (Exception e) { Log.w(TAG, "Error calling NoMan", e); } } @VisibleForTesting void setNm(INotificationManager inm) { sINM = inm; Loading Loading @@ -748,5 +779,6 @@ public class NotificationBackend { public Map<String, NotificationsSentState> sentByChannel; public NotificationsSentState sentByApp; public boolean showAllChannels = true; public boolean canBePromoted; } }
src/com/android/settings/notification/app/AppNotificationSettings.java +1 −0 Original line number Diff line number Diff line Loading @@ -104,6 +104,7 @@ public class AppNotificationSettings extends NotificationSettings { mControllers.add(new ShowMorePreferenceController( context, mDependentFieldListener, mBackend)); mControllers.add(new BundleListPreferenceController(context, mBackend)); mControllers.add(new PromotedNotificationsPreferenceController(context, mBackend)); return new ArrayList<>(mControllers); } }
src/com/android/settings/notification/app/PromotedNotificationsPreferenceController.java 0 → 100644 +83 −0 Original line number Diff line number Diff line /* * Copyright (C) 2024 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.app; import android.app.Flags; import android.content.Context; import androidx.annotation.NonNull; import androidx.preference.Preference; import androidx.preference.PreferenceCategory; import com.android.settings.notification.NotificationBackend; import com.android.settingslib.RestrictedSwitchPreference; public class PromotedNotificationsPreferenceController extends NotificationPreferenceController implements Preference.OnPreferenceChangeListener { private static final String KEY_PROMOTED_CATEGORY = "promoted_category"; private static final String KEY_PROMOTED_SWITCH = "promoted_switch"; public PromotedNotificationsPreferenceController(@NonNull Context context, @NonNull NotificationBackend backend) { super(context, backend); } @Override @NonNull public String getPreferenceKey() { return KEY_PROMOTED_CATEGORY; } @Override public boolean isAvailable() { if (!Flags.uiRichOngoing()) { return false; } return super.isAvailable(); } @Override boolean isIncludedInFilter() { // not a channel-specific preference; only at the app level return false; } /** * Updates the state of the promoted notifications switch. Because this controller governs * the full PreferenceCategory, we must find the switch preference within the category first. */ public void updateState(@NonNull Preference preference) { PreferenceCategory category = (PreferenceCategory) preference; RestrictedSwitchPreference pref = category.findPreference(KEY_PROMOTED_SWITCH); if (pref != null && mAppRow != null) { pref.setDisabledByAdmin(mAdmin); pref.setEnabled(!pref.isDisabledByAdmin()); pref.setChecked(mAppRow.canBePromoted); pref.setOnPreferenceChangeListener(this); } } @Override public boolean onPreferenceChange(@NonNull Preference preference, @NonNull Object newValue) { final boolean canBePromoted = (Boolean) newValue; if (mAppRow != null && mAppRow.canBePromoted != canBePromoted) { mAppRow.canBePromoted = canBePromoted; mBackend.setCanBePromoted(mAppRow.pkg, mAppRow.uid, canBePromoted); } return true; } }