Disable all preferences (except toggle) when a mode is disabled

Also set some alpha on the circles so that they look more or less disabled as well.

Fixes: 354867828
Test: atest com.android.settings.notification.modes
Flag: android.app.modes_ui
Change-Id: I53ef5e381d37afa20b0532f3c7ddb3f106b2e85e
diff --git a/src/com/android/settings/notification/modes/CircularIconsPreference.java b/src/com/android/settings/notification/modes/CircularIconsPreference.java
index 1ce3476..e3cd948 100644
--- a/src/com/android/settings/notification/modes/CircularIconsPreference.java
+++ b/src/com/android/settings/notification/modes/CircularIconsPreference.java
@@ -51,6 +51,8 @@
 
 public class CircularIconsPreference extends RestrictedPreference {
 
+    private static final float DISABLED_ITEM_ALPHA = 0.3f;
+
     private Executor mUiExecutor;
     @Nullable private LinearLayout mIconContainer;
 
@@ -98,6 +100,14 @@
         displayIconsIfPending();
     }
 
+    @Override
+    public void setEnabled(boolean enabled) {
+        super.setEnabled(enabled);
+        if (mIconContainer != null) {
+            applyEnabledToIcons(mIconContainer, enabled);
+        }
+    }
+
     private void displayIconsIfPending() {
         CircularIconSet<?> pendingIconSet = mPendingDisplayIconSet;
         if (pendingIconSet != null) {
@@ -211,6 +221,8 @@
             textView.setText(getContext().getString(R.string.zen_mode_plus_n_items, extraItems));
         }
 
+        applyEnabledToIcons(mIconContainer, isEnabled());
+
         // Display icons when all are ready (more consistent than randomly loading).
         mPendingLoadIconsFuture = Futures.allAsList(iconFutures);
         FutureUtil.whenDone(
@@ -224,6 +236,13 @@
                 mUiExecutor);
     }
 
+    private void applyEnabledToIcons(ViewGroup container, boolean enabled) {
+        for (int i = 0; i < container.getChildCount(); i++) {
+            View child = container.getChildAt(i);
+            child.setAlpha(enabled ? 1.0f : DISABLED_ITEM_ALPHA);
+        }
+    }
+
     private static Drawable getPlaceholderImage(Context context) {
         ShapeDrawable placeholder = new ShapeDrawable(new OvalShape());
         placeholder.setTintList(Utils.getColorAttr(context,
@@ -250,6 +269,18 @@
     }
 
     @VisibleForTesting(otherwise = VisibleForTesting.NONE)
+    List<View> getViews() {
+        if (mIconContainer == null) {
+            return List.of();
+        }
+        ArrayList<View> views = new ArrayList<>();
+        for (int i = 0; i < mIconContainer.getChildCount(); i++) {
+            views.add(mIconContainer.getChildAt(i));
+        }
+        return views;
+    }
+
+    @VisibleForTesting(otherwise = VisibleForTesting.NONE)
     List<Drawable> getIcons() {
         if (mIconContainer == null) {
             return List.of();
diff --git a/src/com/android/settings/notification/modes/InterruptionFilterPreferenceController.java b/src/com/android/settings/notification/modes/InterruptionFilterPreferenceController.java
index 8bdeea4..9d4a172 100644
--- a/src/com/android/settings/notification/modes/InterruptionFilterPreferenceController.java
+++ b/src/com/android/settings/notification/modes/InterruptionFilterPreferenceController.java
@@ -44,6 +44,7 @@
 
     @Override
     public void updateState(Preference preference, @NonNull ZenMode zenMode) {
+        preference.setEnabled(zenMode.isEnabled());
         boolean filteringNotifications = zenMode.getRule().getInterruptionFilter()
                 != INTERRUPTION_FILTER_ALL;
         ((TwoStatePreference) preference).setChecked(filteringNotifications);
diff --git a/src/com/android/settings/notification/modes/ZenModeAppsLinkPreferenceController.java b/src/com/android/settings/notification/modes/ZenModeAppsLinkPreferenceController.java
index 962e016..1521a8b 100644
--- a/src/com/android/settings/notification/modes/ZenModeAppsLinkPreferenceController.java
+++ b/src/com/android/settings/notification/modes/ZenModeAppsLinkPreferenceController.java
@@ -34,7 +34,6 @@
 
 import com.android.settings.R;
 import com.android.settings.Utils;
-import com.android.settings.core.SubSettingLauncher;
 import com.android.settingslib.applications.ApplicationsState;
 import com.android.settingslib.applications.ApplicationsState.AppEntry;
 import com.android.settingslib.notification.modes.ZenMode;
@@ -95,11 +94,11 @@
         Bundle bundle = new Bundle();
         bundle.putString(EXTRA_AUTOMATIC_ZEN_RULE_ID, zenMode.getId());
         // TODO(b/332937635): Update metrics category
-        preference.setIntent(new SubSettingLauncher(mContext)
-                .setDestination(ZenModeAppsFragment.class.getName())
-                .setSourceMetricsCategory(0)
-                .setArguments(bundle)
-                .toIntent());
+        preference.setIntent(
+                ZenSubSettingLauncher.forModeFragment(mContext, ZenModeAppsFragment.class,
+                        zenMode.getId(), 0).toIntent());
+        preference.setEnabled(zenMode.isEnabled());
+
         mZenMode = zenMode;
         mPreference = (CircularIconsPreference) preference;
 
diff --git a/src/com/android/settings/notification/modes/ZenModeDisplayLinkPreferenceController.java b/src/com/android/settings/notification/modes/ZenModeDisplayLinkPreferenceController.java
index d3559f1..bba5e34 100644
--- a/src/com/android/settings/notification/modes/ZenModeDisplayLinkPreferenceController.java
+++ b/src/com/android/settings/notification/modes/ZenModeDisplayLinkPreferenceController.java
@@ -24,7 +24,6 @@
 import androidx.annotation.NonNull;
 import androidx.preference.Preference;
 
-import com.android.settings.core.SubSettingLauncher;
 import com.android.settingslib.notification.modes.ZenMode;
 import com.android.settingslib.notification.modes.ZenModesBackend;
 
@@ -43,11 +42,10 @@
         Bundle bundle = new Bundle();
         bundle.putString(EXTRA_AUTOMATIC_ZEN_RULE_ID, zenMode.getId());
         // TODO(b/332937635): Update metrics category
-        preference.setIntent(new SubSettingLauncher(mContext)
-                .setDestination(ZenModeDisplayFragment.class.getName())
-                .setSourceMetricsCategory(0)
-                .setArguments(bundle)
-                .toIntent());
+        preference.setIntent(
+                ZenSubSettingLauncher.forModeFragment(mContext, ZenModeDisplayFragment.class,
+                        zenMode.getId(), 0).toIntent());
+        preference.setEnabled(zenMode.isEnabled());
     }
 
     @Override
diff --git a/src/com/android/settings/notification/modes/ZenModeFragment.java b/src/com/android/settings/notification/modes/ZenModeFragment.java
index 7d7631b..0661284 100644
--- a/src/com/android/settings/notification/modes/ZenModeFragment.java
+++ b/src/com/android/settings/notification/modes/ZenModeFragment.java
@@ -53,12 +53,15 @@
         prefControllers.add(new ZenModeHeaderController(context, "header", this));
         prefControllers.add(
                 new ZenModeButtonPreferenceController(context, "activate", this, mBackend));
+        prefControllers.add(new ZenModePreferenceCategoryController(context, "modes_filters"));
         prefControllers.add(new ZenModePeopleLinkPreferenceController(
                 context, "zen_mode_people", mHelperBackend));
         prefControllers.add(new ZenModeAppsLinkPreferenceController(
                 context, "zen_mode_apps", this, mBackend, mHelperBackend));
         prefControllers.add(new ZenModeOtherLinkPreferenceController(
                 context, "zen_other_settings", mHelperBackend));
+        prefControllers.add(
+                new ZenModePreferenceCategoryController(context, "modes_additional_actions"));
         prefControllers.add(new ZenModeDisplayLinkPreferenceController(
                 context, "mode_display_settings", mBackend, mHelperBackend));
         prefControllers.add(new ZenModeSetTriggerLinkPreferenceController(context,
diff --git a/src/com/android/settings/notification/modes/ZenModeOtherLinkPreferenceController.java b/src/com/android/settings/notification/modes/ZenModeOtherLinkPreferenceController.java
index d7bd517..15e0edc 100644
--- a/src/com/android/settings/notification/modes/ZenModeOtherLinkPreferenceController.java
+++ b/src/com/android/settings/notification/modes/ZenModeOtherLinkPreferenceController.java
@@ -70,6 +70,7 @@
                 ZenSubSettingLauncher.forModeFragment(mContext, ZenModeOtherFragment.class,
                         zenMode.getId(), 0).toIntent());
 
+        preference.setEnabled(zenMode.isEnabled());
         preference.setSummary(mSummaryHelper.getOtherSoundCategoriesSummary(zenMode));
         ((CircularIconsPreference) preference).displayIcons(getSoundIcons(zenMode.getPolicy()));
     }
diff --git a/src/com/android/settings/notification/modes/ZenModePeopleLinkPreferenceController.java b/src/com/android/settings/notification/modes/ZenModePeopleLinkPreferenceController.java
index 762cdd5..b5938c6 100644
--- a/src/com/android/settings/notification/modes/ZenModePeopleLinkPreferenceController.java
+++ b/src/com/android/settings/notification/modes/ZenModePeopleLinkPreferenceController.java
@@ -92,6 +92,7 @@
                 ZenSubSettingLauncher.forModeFragment(mContext, ZenModePeopleFragment.class,
                         zenMode.getId(), 0).toIntent());
 
+        preference.setEnabled(zenMode.isEnabled());
         preference.setSummary(mSummaryHelper.getPeopleSummary(zenMode.getPolicy()));
         ((CircularIconsPreference) preference).displayIcons(getPeopleIcons(zenMode.getPolicy()));
     }
diff --git a/src/com/android/settings/notification/modes/ZenModePreferenceCategoryController.java b/src/com/android/settings/notification/modes/ZenModePreferenceCategoryController.java
new file mode 100644
index 0000000..6ebcb1f
--- /dev/null
+++ b/src/com/android/settings/notification/modes/ZenModePreferenceCategoryController.java
@@ -0,0 +1,39 @@
+/*
+ * 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.modes;
+
+import android.content.Context;
+
+import androidx.annotation.NonNull;
+import androidx.preference.Preference;
+
+import com.android.settingslib.notification.modes.ZenMode;
+
+/**
+ * Simple {@link AbstractZenModePreferenceController} used for all {@code PreferenceCategory}
+ * entries in {@link ZenModeFragment} that should be disabled when the mode is disabled.
+ */
+class ZenModePreferenceCategoryController extends AbstractZenModePreferenceController {
+    ZenModePreferenceCategoryController(@NonNull Context context, @NonNull String key) {
+        super(context, key);
+    }
+
+    @Override
+    void updateState(Preference preference, @NonNull ZenMode zenMode) {
+        preference.setEnabled(zenMode.isEnabled());
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/notification/modes/CircularIconsPreferenceTest.java b/tests/robotests/src/com/android/settings/notification/modes/CircularIconsPreferenceTest.java
index 73754df..ce23fc4 100644
--- a/tests/robotests/src/com/android/settings/notification/modes/CircularIconsPreferenceTest.java
+++ b/tests/robotests/src/com/android/settings/notification/modes/CircularIconsPreferenceTest.java
@@ -226,4 +226,32 @@
         mPreference.displayIcons(one);
         mPreference.displayIcons(same); // if no exception, wasn't called.
     }
+
+    @Test
+    public void setEnabled_afterDisplayIcons_showsEnabledOrDisabledImages() {
+        CircularIconSet<Integer> iconSet = new CircularIconSet<>(ImmutableList.of(1, 2),
+                ColorDrawable::new);
+        bindAndMeasureViewHolder(VIEW_WIDTH);
+        mPreference.displayIcons(iconSet);
+        assertThat(mPreference.getViews()).hasSize(2);
+
+        mPreference.setEnabled(false);
+        assertThat(mPreference.getViews().get(0).getAlpha()).isLessThan(1f);
+
+        mPreference.setEnabled(true);
+        assertThat(mPreference.getViews().get(0).getAlpha()).isEqualTo(1f);
+    }
+
+    @Test
+    public void setEnabled_beforeDisplayIcons_showsEnabledOrDisabledImages() {
+        CircularIconSet<Integer> iconSet = new CircularIconSet<>(ImmutableList.of(1, 2),
+                ColorDrawable::new);
+
+        mPreference.setEnabled(false);
+        bindAndMeasureViewHolder(VIEW_WIDTH);
+        mPreference.displayIcons(iconSet);
+
+        assertThat(mPreference.getViews()).hasSize(2);
+        assertThat(mPreference.getViews().get(0).getAlpha()).isLessThan(1f);
+    }
 }
diff --git a/tests/robotests/src/com/android/settings/notification/modes/InterruptionFilterPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/modes/InterruptionFilterPreferenceControllerTest.java
index 61d3192..0c3f8e1 100644
--- a/tests/robotests/src/com/android/settings/notification/modes/InterruptionFilterPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/modes/InterruptionFilterPreferenceControllerTest.java
@@ -68,6 +68,18 @@
     }
 
     @Test
+    public void testUpdateState_disabled() {
+        TwoStatePreference preference = mock(TwoStatePreference.class);
+        ZenMode zenMode = new TestModeBuilder()
+                .setEnabled(false)
+                .build();
+
+        mController.updateZenMode(preference, zenMode);
+
+        verify(preference).setEnabled(false);
+    }
+
+    @Test
     public void testUpdateState_all() {
         TwoStatePreference preference = mock(TwoStatePreference.class);
         ZenMode zenMode = new TestModeBuilder()
diff --git a/tests/robotests/src/com/android/settings/notification/modes/ZenModeAppsLinkPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/modes/ZenModeAppsLinkPreferenceControllerTest.java
index cc4d306..301ff90 100644
--- a/tests/robotests/src/com/android/settings/notification/modes/ZenModeAppsLinkPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/modes/ZenModeAppsLinkPreferenceControllerTest.java
@@ -142,6 +142,17 @@
     }
 
     @Test
+    public void testUpdateState_disabled() {
+        ZenMode zenMode = new TestModeBuilder()
+                .setEnabled(false)
+                .build();
+
+        mController.updateState(mPreference, zenMode);
+
+        assertThat(mPreference.isEnabled()).isFalse();
+    }
+
+    @Test
     public void testUpdateSetsIntent() {
         // Create a zen mode that allows priority channels to breakthrough.
         ZenMode zenMode = createPriorityChannelsZenMode();
diff --git a/tests/robotests/src/com/android/settings/notification/modes/ZenModeDisplayLinkPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/modes/ZenModeDisplayLinkPreferenceControllerTest.java
index 6c3d74f..29350f6 100644
--- a/tests/robotests/src/com/android/settings/notification/modes/ZenModeDisplayLinkPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/modes/ZenModeDisplayLinkPreferenceControllerTest.java
@@ -28,6 +28,7 @@
 import androidx.preference.Preference;
 
 import com.android.settingslib.notification.modes.TestModeBuilder;
+import com.android.settingslib.notification.modes.ZenMode;
 import com.android.settingslib.notification.modes.ZenModesBackend;
 
 import org.junit.Before;
@@ -62,6 +63,18 @@
     }
 
     @Test
+    public void testUpdateState_disabled() {
+        Preference preference = mock(Preference.class);
+        ZenMode zenMode = new TestModeBuilder()
+                .setEnabled(false)
+                .build();
+
+        mController.updateState(preference, zenMode);
+
+        verify(preference).setEnabled(false);
+    }
+
+    @Test
     @EnableFlags(Flags.FLAG_MODES_UI)
     public void testHasSummary() {
         Preference pref = mock(Preference.class);
diff --git a/tests/robotests/src/com/android/settings/notification/modes/ZenModeOtherLinkPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/modes/ZenModeOtherLinkPreferenceControllerTest.java
index 7fa4f9f..8aa87e6 100644
--- a/tests/robotests/src/com/android/settings/notification/modes/ZenModeOtherLinkPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/modes/ZenModeOtherLinkPreferenceControllerTest.java
@@ -62,6 +62,18 @@
     }
 
     @Test
+    public void updateState_disabled() {
+        CircularIconsPreference pref = mock(CircularIconsPreference.class);
+        ZenMode zenMode = new TestModeBuilder()
+                .setEnabled(false)
+                .build();
+
+        mController.updateZenMode(pref, zenMode);
+
+        verify(pref).setEnabled(false);
+    }
+
+    @Test
     public void updateState_loadsSummary() {
         CircularIconsPreference pref = mock(CircularIconsPreference.class);
         mController.updateZenMode(pref, TestModeBuilder.EXAMPLE);
diff --git a/tests/robotests/src/com/android/settings/notification/modes/ZenModePeopleLinkPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/modes/ZenModePeopleLinkPreferenceControllerTest.java
index 8ec980d..63068fa 100644
--- a/tests/robotests/src/com/android/settings/notification/modes/ZenModePeopleLinkPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/modes/ZenModePeopleLinkPreferenceControllerTest.java
@@ -112,6 +112,17 @@
     }
 
     @Test
+    public void updateState_disabled() {
+        ZenMode zenMode = new TestModeBuilder()
+                .setEnabled(false)
+                .build();
+
+        mController.updateState(mPreference, zenMode);
+
+        assertThat(mPreference.isEnabled()).isFalse();
+    }
+
+    @Test
     public void updateState_setsSummary() {
         mController.updateState(mPreference, TestModeBuilder.EXAMPLE);