diff --git a/res/values/strings.xml b/res/values/strings.xml index 50556de6e0b..21ab9179933 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -8935,6 +8935,9 @@ This app has not posted any notifications + + Show unused categories + Additional settings in the app diff --git a/res/xml/app_notification_settings.xml b/res/xml/app_notification_settings.xml index f96a375224e..091de7536da 100644 --- a/res/xml/app_notification_settings.xml +++ b/res/xml/app_notification_settings.xml @@ -55,6 +55,11 @@ android:key="channels" android:layout="@layout/empty_view" /> + + sentByChannel; public NotificationsSentState sentByApp; + public boolean showAllChannels = true; } } diff --git a/src/com/android/settings/notification/app/AppNotificationSettings.java b/src/com/android/settings/notification/app/AppNotificationSettings.java index 89756b7b839..3d3f3429e9a 100644 --- a/src/com/android/settings/notification/app/AppNotificationSettings.java +++ b/src/com/android/settings/notification/app/AppNotificationSettings.java @@ -16,16 +16,10 @@ package com.android.settings.notification.app; -import static com.android.server.notification.Flags.notificationHideUnusedChannels; - - import android.app.settings.SettingsEnums; import android.content.Context; import android.text.TextUtils; import android.util.Log; -import android.view.Menu; -import android.view.MenuInflater; -import android.view.MenuItem; import com.android.internal.widget.LockPatternUtils; import com.android.settings.R; @@ -107,38 +101,8 @@ public class AppNotificationSettings extends NotificationSettings { mControllers.add(new BubbleSummaryPreferenceController(context, mBackend)); mControllers.add(new NotificationsOffPreferenceController(context)); mControllers.add(new DeletedChannelsPreferenceController(context, mBackend)); + mControllers.add(new ShowMorePreferenceController( + context, mDependentFieldListener, mBackend)); return new ArrayList<>(mControllers); } - - private final int SHOW_ALL_CHANNELS = 1; - - @Override - public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { - if (notificationHideUnusedChannels()) { - menu.add(Menu.NONE, SHOW_ALL_CHANNELS, Menu.NONE, - mShowAll ? R.string.hide_unused_channels : R.string.show_unused_channels); - } - super.onCreateOptionsMenu(menu, inflater); - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - if (!notificationHideUnusedChannels()) { - return super.onOptionsItemSelected(item); - } - switch (item.getItemId()) { - case SHOW_ALL_CHANNELS: - mShowAll = !mShowAll; - item.setTitle(mShowAll - ? R.string.hide_unused_channels - : R.string.show_unused_channels); - ChannelListPreferenceController list = - use(ChannelListPreferenceController.class); - list.setShowAll(mShowAll); - list.updateState(findPreference(list.getPreferenceKey())); - return true; - default: - return super.onOptionsItemSelected(item); - } - } } diff --git a/src/com/android/settings/notification/app/ChannelListPreferenceController.java b/src/com/android/settings/notification/app/ChannelListPreferenceController.java index 70775926e9b..b8dfb6a7069 100644 --- a/src/com/android/settings/notification/app/ChannelListPreferenceController.java +++ b/src/com/android/settings/notification/app/ChannelListPreferenceController.java @@ -59,8 +59,6 @@ public class ChannelListPreferenceController extends NotificationPreferenceContr private List mChannelGroupList; private PreferenceCategory mPreference; - private boolean mShowAll; - public ChannelListPreferenceController(Context context, NotificationBackend backend) { super(context, backend); } @@ -100,7 +98,7 @@ public class ChannelListPreferenceController extends NotificationPreferenceContr @Override protected Void doInBackground(Void... unused) { if (notificationHideUnusedChannels()) { - if (mShowAll) { + if (mAppRow.showAllChannels) { mChannelGroupList = mBackend.getGroups(mAppRow.pkg, mAppRow.uid).getList(); } else { mChannelGroupList = mBackend.getGroupsWithRecentBlockedFilter(mAppRow.pkg, @@ -123,10 +121,6 @@ public class ChannelListPreferenceController extends NotificationPreferenceContr }.execute(); } - protected void setShowAll(boolean showAll) { - mShowAll = showAll; - } - /** * Update the preferences group to match the * @param groupPrefsList diff --git a/src/com/android/settings/notification/app/DeletedChannelsPreferenceController.java b/src/com/android/settings/notification/app/DeletedChannelsPreferenceController.java index 6a1d4cb1247..07b7fdab01d 100644 --- a/src/com/android/settings/notification/app/DeletedChannelsPreferenceController.java +++ b/src/com/android/settings/notification/app/DeletedChannelsPreferenceController.java @@ -16,6 +16,8 @@ package com.android.settings.notification.app; +import static com.android.server.notification.Flags.notificationHideUnusedChannels; + import android.content.Context; import androidx.preference.Preference; @@ -44,6 +46,9 @@ public class DeletedChannelsPreferenceController extends NotificationPreferenceC if (!super.isAvailable()) { return false; } + if (notificationHideUnusedChannels()) { + return false; + } // only visible on app screen if (mChannel != null || hasValidGroup()) { return false; diff --git a/src/com/android/settings/notification/app/ShowMorePreferenceController.java b/src/com/android/settings/notification/app/ShowMorePreferenceController.java new file mode 100644 index 00000000000..dbc279a6c8b --- /dev/null +++ b/src/com/android/settings/notification/app/ShowMorePreferenceController.java @@ -0,0 +1,75 @@ +/* + * 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 static com.android.server.notification.Flags.notificationHideUnusedChannels; + +import android.content.Context; + +import androidx.annotation.NonNull; +import androidx.preference.Preference; +import androidx.preference.PreferenceScreen; + +import com.android.settings.notification.NotificationBackend; + +import org.jetbrains.annotations.NotNull; + +public class ShowMorePreferenceController extends NotificationPreferenceController { + + private static final String KEY = "more"; + private NotificationSettings.DependentFieldListener mDependentFieldListener; + + public ShowMorePreferenceController(Context context, + NotificationSettings.DependentFieldListener dependentFieldListener, + NotificationBackend backend) { + super(context, backend); + mDependentFieldListener = dependentFieldListener; + } + + @Override + public String getPreferenceKey() { + return KEY; + } + + @Override + public boolean isAvailable() { + if (!notificationHideUnusedChannels()) { + return false; + } + if (mAppRow == null) { + return false; + } + if (mAppRow.banned || mAppRow.showAllChannels) { + return false; + } + return true; + } + + @Override + boolean isIncludedInFilter() { + return false; + } + + @Override + public void updateState(Preference preference) { + preference.setOnPreferenceClickListener(preference1 -> { + mAppRow.showAllChannels = true; + mDependentFieldListener.onFieldValueChanged(); + return true; + }); + } +} diff --git a/tests/robotests/src/com/android/settings/notification/app/DeletedChannelsPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/app/DeletedChannelsPreferenceControllerTest.java index 5c9de7cb30b..267b8d74616 100644 --- a/tests/robotests/src/com/android/settings/notification/app/DeletedChannelsPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/notification/app/DeletedChannelsPreferenceControllerTest.java @@ -31,12 +31,17 @@ import android.app.NotificationChannelGroup; import android.app.NotificationManager; import android.content.Context; import android.os.UserManager; +import android.platform.test.annotations.DisableFlags; +import android.platform.test.annotations.EnableFlags; +import android.platform.test.flag.junit.SetFlagsRule; import androidx.preference.Preference; +import com.android.server.notification.Flags; import com.android.settings.notification.NotificationBackend; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; @@ -60,6 +65,8 @@ public class DeletedChannelsPreferenceControllerTest { private UserManager mUm; private DeletedChannelsPreferenceController mController; + @Rule + public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); @Before public void setUp() { @@ -109,6 +116,16 @@ public class DeletedChannelsPreferenceControllerTest { } @Test + @EnableFlags(Flags.FLAG_NOTIFICATION_HIDE_UNUSED_CHANNELS) + public void isAvailable_notIfFlagEnabled() { + when(mBackend.getDeletedChannelCount(any(), anyInt())).thenReturn(1); + mController.onResume( + new NotificationBackend.AppRow(), null, null, null, null, null, new ArrayList<>()); + assertFalse(mController.isAvailable()); + } + + @Test + @DisableFlags(Flags.FLAG_NOTIFICATION_HIDE_UNUSED_CHANNELS) public void isAvailable_appScreen() { when(mBackend.getDeletedChannelCount(any(), anyInt())).thenReturn(1); mController.onResume( diff --git a/tests/robotests/src/com/android/settings/notification/app/ShowMorePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/app/ShowMorePreferenceControllerTest.java new file mode 100644 index 00000000000..611c80a48f1 --- /dev/null +++ b/tests/robotests/src/com/android/settings/notification/app/ShowMorePreferenceControllerTest.java @@ -0,0 +1,113 @@ +/* + * 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 static com.google.common.truth.Truth.assertThat; + +import static org.junit.Assert.assertFalse; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; + +import android.app.NotificationChannelGroup; +import android.app.NotificationManager; +import android.content.Context; +import android.os.UserManager; +import android.platform.test.annotations.EnableFlags; +import android.platform.test.flag.junit.SetFlagsRule; + +import androidx.preference.Preference; + +import com.android.server.notification.Flags; +import com.android.settings.notification.NotificationBackend; + +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 org.robolectric.shadows.ShadowApplication; + +@RunWith(RobolectricTestRunner.class) +@EnableFlags(Flags.FLAG_NOTIFICATION_HIDE_UNUSED_CHANNELS) +public class ShowMorePreferenceControllerTest { + + private Context mContext; + @Mock + private NotificationBackend mBackend; + @Mock + private NotificationManager mNm; + @Mock + private UserManager mUm; + @Mock + private NotificationSettings.DependentFieldListener mDependentFieldListener; + + private ShowMorePreferenceController mController; + @Rule + public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + ShadowApplication shadowApplication = ShadowApplication.getInstance(); + shadowApplication.setSystemService(Context.NOTIFICATION_SERVICE, mNm); + shadowApplication.setSystemService(Context.USER_SERVICE, mUm); + mContext = RuntimeEnvironment.application; + mController = new ShowMorePreferenceController(mContext, mDependentFieldListener, mBackend); + } + + @Test + public void noCrashIfNoOnResume() { + mController.isAvailable(); + mController.updateState(mock(Preference.class)); + } + + @Test + public void isAvailable_notIfAppBlocked() { + NotificationBackend.AppRow appRow = new NotificationBackend.AppRow(); + appRow.banned = true; + appRow.showAllChannels = false; + mController.onResume(appRow, null, null, null, null, null, null); + assertFalse(mController.isAvailable()); + } + + @Test + public void isAvailable_notIfShowingAll() { + NotificationBackend.AppRow appRow = new NotificationBackend.AppRow(); + mController.onResume(appRow, null, mock(NotificationChannelGroup.class), null, null, null, + null); + assertFalse(mController.isAvailable()); + } + + @Test + public void updateState() { + NotificationBackend.AppRow appRow = new NotificationBackend.AppRow(); + appRow.banned = false; + appRow.showAllChannels = false; + mController.onResume(appRow, null, null, null, null, null, null); + + Preference pref = new Preference(mContext); + mController.updateState(pref); + + pref.performClick(); + + verify(mDependentFieldListener).onFieldValueChanged(); + assertThat(appRow.showAllChannels).isTrue(); + } +}