diff --git a/res/drawable/ic_zen_mode_action_change_icon.xml b/res/drawable/ic_zen_mode_action_change_icon.xml
new file mode 100644
index 00000000000..4cf4167314a
--- /dev/null
+++ b/res/drawable/ic_zen_mode_action_change_icon.xml
@@ -0,0 +1,25 @@
+
+
+
+
\ No newline at end of file
diff --git a/res/layout/modes_icon_list.xml b/res/layout/modes_icon_list.xml
new file mode 100644
index 00000000000..87e647eb7a6
--- /dev/null
+++ b/res/layout/modes_icon_list.xml
@@ -0,0 +1,38 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/res/layout/modes_icon_list_item.xml b/res/layout/modes_icon_list_item.xml
new file mode 100644
index 00000000000..aa45de33b72
--- /dev/null
+++ b/res/layout/modes_icon_list_item.xml
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+
+
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index c72c17d79b2..d972e138eec 100755
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -497,4 +497,9 @@
264dp
30dp
+
+
+ 96dp
+ 56dp
+ 32dp
diff --git a/res/values/strings.xml b/res/values/strings.xml
index dea2cc6af23..fd6a084bdd6 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -9312,6 +9312,15 @@
Change to always interrupt
+
+ Rename
+
+
+ Change icon
+
+
+ Change icon
+
Warning
diff --git a/res/xml/modes_icon_picker.xml b/res/xml/modes_icon_picker.xml
new file mode 100644
index 00000000000..cb0ff302672
--- /dev/null
+++ b/res/xml/modes_icon_picker.xml
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/res/xml/modes_rule_settings.xml b/res/xml/modes_rule_settings.xml
index f2822741bc7..cf090be46d3 100644
--- a/res/xml/modes_rule_settings.xml
+++ b/res/xml/modes_rule_settings.xml
@@ -28,6 +28,10 @@
android:selectable="false"
android:layout="@layout/modes_activation_button"/>
+
+
diff --git a/src/com/android/settings/notification/modes/IconUtil.java b/src/com/android/settings/notification/modes/IconUtil.java
new file mode 100644
index 00000000000..c6ecaa0a56d
--- /dev/null
+++ b/src/com/android/settings/notification/modes/IconUtil.java
@@ -0,0 +1,69 @@
+/*
+ * 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 static com.google.common.base.Preconditions.checkNotNull;
+
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.LayerDrawable;
+import android.graphics.drawable.ShapeDrawable;
+import android.graphics.drawable.shapes.OvalShape;
+
+import androidx.annotation.DrawableRes;
+import androidx.annotation.NonNull;
+
+import com.android.settings.R;
+import com.android.settingslib.Utils;
+
+class IconUtil {
+
+ static Drawable applyTint(@NonNull Context context, @NonNull Drawable icon) {
+ icon = icon.mutate();
+ icon.setTintList(
+ Utils.getColorAttr(context, android.R.attr.colorControlNormal));
+ return icon;
+ }
+
+ /**
+ * Returns a variant of the supplied {@code icon} to be used in the icon picker. The inner icon
+ * is 36x36dp and it's contained into a circle of diameter 54dp.
+ */
+ static Drawable makeIconCircle(@NonNull Context context, @NonNull Drawable icon) {
+ ShapeDrawable background = new ShapeDrawable(new OvalShape());
+ background.getPaint().setColor(Utils.getColorAttrDefaultColor(context,
+ com.android.internal.R.attr.materialColorSecondaryContainer));
+ icon.setTint(Utils.getColorAttrDefaultColor(context,
+ com.android.internal.R.attr.materialColorOnSecondaryContainer));
+
+ LayerDrawable layerDrawable = new LayerDrawable(new Drawable[] { background, icon });
+
+ int circleDiameter = context.getResources().getDimensionPixelSize(
+ R.dimen.zen_mode_icon_list_circle_diameter);
+ int iconSize = context.getResources().getDimensionPixelSize(
+ R.dimen.zen_mode_icon_list_icon_size);
+ int iconPadding = (circleDiameter - iconSize) / 2;
+ layerDrawable.setBounds(0, 0, circleDiameter, circleDiameter);
+ layerDrawable.setLayerInset(1, iconPadding, iconPadding, iconPadding, iconPadding);
+
+ return layerDrawable;
+ }
+
+ static Drawable makeIconCircle(@NonNull Context context, @DrawableRes int iconResId) {
+ return makeIconCircle(context, checkNotNull(context.getDrawable(iconResId)));
+ }
+}
diff --git a/src/com/android/settings/notification/modes/ZenMode.java b/src/com/android/settings/notification/modes/ZenMode.java
index 1be7e5fda1e..aca959f0f51 100644
--- a/src/com/android/settings/notification/modes/ZenMode.java
+++ b/src/com/android/settings/notification/modes/ZenMode.java
@@ -204,6 +204,14 @@ class ZenMode {
: new ZenDeviceEffects.Builder().build();
}
+ public boolean canEditName() {
+ return !isManualDnd();
+ }
+
+ public boolean canEditIcon() {
+ return !isManualDnd();
+ }
+
public boolean canBeDeleted() {
return !mIsManualDnd;
}
diff --git a/src/com/android/settings/notification/modes/ZenModeActionsPreferenceController.java b/src/com/android/settings/notification/modes/ZenModeActionsPreferenceController.java
new file mode 100644
index 00000000000..5695fbcbc47
--- /dev/null
+++ b/src/com/android/settings/notification/modes/ZenModeActionsPreferenceController.java
@@ -0,0 +1,64 @@
+/*
+ * 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 static com.android.settings.notification.modes.ZenModeFragmentBase.MODE_ID;
+
+import android.content.Context;
+import android.os.Bundle;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.preference.Preference;
+
+import com.android.settings.R;
+import com.android.settings.core.SubSettingLauncher;
+import com.android.settingslib.widget.ActionButtonsPreference;
+
+class ZenModeActionsPreferenceController extends AbstractZenModePreferenceController {
+
+ private ActionButtonsPreference mPreference;
+
+ ZenModeActionsPreferenceController(@NonNull Context context, @NonNull String key,
+ @Nullable ZenModesBackend backend) {
+ super(context, key, backend);
+ }
+
+ @Override
+ void updateState(Preference preference, @NonNull ZenMode zenMode) {
+ ActionButtonsPreference buttonsPreference = (ActionButtonsPreference) preference;
+
+ // TODO: b/346278854 - Add rename action (with setButton1Enabled(zenMode.canEditName())
+ buttonsPreference.setButton1Text(R.string.zen_mode_action_change_name);
+ buttonsPreference.setButton1Icon(R.drawable.ic_mode_edit);
+ buttonsPreference.setButton1Enabled(false);
+
+ buttonsPreference.setButton2Text(R.string.zen_mode_action_change_icon);
+ buttonsPreference.setButton2Icon(R.drawable.ic_zen_mode_action_change_icon);
+ buttonsPreference.setButton2Enabled(zenMode.canEditIcon());
+ buttonsPreference.setButton2OnClickListener(v -> {
+ Bundle bundle = new Bundle();
+ bundle.putString(MODE_ID, zenMode.getId());
+ new SubSettingLauncher(mContext)
+ .setDestination(ZenModeIconPickerFragment.class.getName())
+ // TODO: b/332937635 - Update metrics category
+ .setSourceMetricsCategory(0)
+ .setArguments(bundle)
+ .launch();
+ });
+ }
+}
diff --git a/src/com/android/settings/notification/modes/ZenModeFragment.java b/src/com/android/settings/notification/modes/ZenModeFragment.java
index 7084f51a922..87165b85d72 100644
--- a/src/com/android/settings/notification/modes/ZenModeFragment.java
+++ b/src/com/android/settings/notification/modes/ZenModeFragment.java
@@ -38,6 +38,7 @@ public class ZenModeFragment extends ZenModeFragmentBase {
List prefControllers = new ArrayList<>();
prefControllers.add(new ZenModeHeaderController(context, "header", this, mBackend));
prefControllers.add(new ZenModeButtonPreferenceController(context, "activate", mBackend));
+ prefControllers.add(new ZenModeActionsPreferenceController(context, "actions", mBackend));
prefControllers.add(new ZenModePeopleLinkPreferenceController(
context, "zen_mode_people", mBackend));
prefControllers.add(new ZenModeAppsLinkPreferenceController(
diff --git a/src/com/android/settings/notification/modes/ZenModeFragmentBase.java b/src/com/android/settings/notification/modes/ZenModeFragmentBase.java
index 5e6cfa5084e..e086524a427 100644
--- a/src/com/android/settings/notification/modes/ZenModeFragmentBase.java
+++ b/src/com/android/settings/notification/modes/ZenModeFragmentBase.java
@@ -51,12 +51,12 @@ abstract class ZenModeFragmentBase extends ZenModesFragmentBase {
if (bundle != null && bundle.containsKey(MODE_ID)) {
String id = bundle.getString(MODE_ID);
if (!reloadMode(id)) {
- Log.d(TAG, "Mode id " + id + " not found");
+ Log.e(TAG, "Mode id " + id + " not found");
toastAndFinish();
return;
}
} else {
- Log.d(TAG, "Mode id required to set mode config settings");
+ Log.e(TAG, "Mode id required to set mode config settings");
toastAndFinish();
return;
}
diff --git a/src/com/android/settings/notification/modes/ZenModeHeaderController.java b/src/com/android/settings/notification/modes/ZenModeHeaderController.java
index ba6e9d9a22e..d8f0a6730fa 100644
--- a/src/com/android/settings/notification/modes/ZenModeHeaderController.java
+++ b/src/com/android/settings/notification/modes/ZenModeHeaderController.java
@@ -63,9 +63,8 @@ class ZenModeHeaderController extends AbstractZenModePreferenceController {
FutureUtil.whenDone(
zenMode.getIcon(mContext, IconLoader.getInstance()),
- icon -> mHeaderController.setIcon(icon)
- .setLabel(zenMode.getRule().getName())
- .done(false /* rebindActions */),
+ icon -> mHeaderController.setIcon(IconUtil.applyTint(mContext, icon))
+ .done(/* rebindActions= */ false),
mContext.getMainExecutor());
}
}
diff --git a/src/com/android/settings/notification/modes/ZenModeIconPickerFragment.java b/src/com/android/settings/notification/modes/ZenModeIconPickerFragment.java
new file mode 100644
index 00000000000..950849e0056
--- /dev/null
+++ b/src/com/android/settings/notification/modes/ZenModeIconPickerFragment.java
@@ -0,0 +1,49 @@
+/*
+ * 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.app.settings.SettingsEnums;
+import android.content.Context;
+
+import com.android.settings.R;
+import com.android.settingslib.core.AbstractPreferenceController;
+
+import com.google.common.collect.ImmutableList;
+
+import java.util.List;
+
+public class ZenModeIconPickerFragment extends ZenModeFragmentBase {
+ @Override
+ protected int getPreferenceScreenResId() {
+ return R.xml.modes_icon_picker;
+ }
+
+ @Override
+ public int getMetricsCategory() {
+ // TODO: b/332937635 - make this the correct metrics category
+ return SettingsEnums.NOTIFICATION_ZEN_MODE_AUTOMATION;
+ }
+
+ @Override
+ protected List createPreferenceControllers(Context context) {
+ return ImmutableList.of(
+ new ZenModeIconPickerIconPreferenceController(context, "current_icon", this,
+ mBackend),
+ new ZenModeIconPickerListPreferenceController(context, "icon_list", this,
+ mBackend));
+ }
+}
diff --git a/src/com/android/settings/notification/modes/ZenModeIconPickerIconPreferenceController.java b/src/com/android/settings/notification/modes/ZenModeIconPickerIconPreferenceController.java
new file mode 100644
index 00000000000..9eaaa973305
--- /dev/null
+++ b/src/com/android/settings/notification/modes/ZenModeIconPickerIconPreferenceController.java
@@ -0,0 +1,59 @@
+/*
+ * 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.annotation.Nullable;
+import androidx.preference.Preference;
+
+import com.android.settings.R;
+import com.android.settings.dashboard.DashboardFragment;
+import com.android.settings.widget.EntityHeaderController;
+import com.android.settingslib.widget.LayoutPreference;
+
+class ZenModeIconPickerIconPreferenceController extends AbstractZenModePreferenceController {
+
+ private final DashboardFragment mFragment;
+ private EntityHeaderController mHeaderController;
+
+ ZenModeIconPickerIconPreferenceController(@NonNull Context context, @NonNull String key,
+ @NonNull DashboardFragment fragment, @Nullable ZenModesBackend backend) {
+ super(context, key, backend);
+ mFragment = fragment;
+ }
+
+ @Override
+ void updateState(Preference preference, @NonNull ZenMode zenMode) {
+ preference.setSelectable(false);
+
+ if (mHeaderController == null) {
+ final LayoutPreference pref = (LayoutPreference) preference;
+ mHeaderController = EntityHeaderController.newInstance(
+ mFragment.getActivity(),
+ mFragment,
+ pref.findViewById(R.id.entity_header));
+ }
+
+ FutureUtil.whenDone(
+ zenMode.getIcon(mContext, IconLoader.getInstance()),
+ icon -> mHeaderController.setIcon(IconUtil.applyTint(mContext, icon))
+ .done(/* rebindActions= */ false),
+ mContext.getMainExecutor());
+ }
+}
diff --git a/src/com/android/settings/notification/modes/ZenModeIconPickerListPreferenceController.java b/src/com/android/settings/notification/modes/ZenModeIconPickerListPreferenceController.java
new file mode 100644
index 00000000000..b07c26f9e18
--- /dev/null
+++ b/src/com/android/settings/notification/modes/ZenModeIconPickerListPreferenceController.java
@@ -0,0 +1,170 @@
+/*
+ * 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 android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+
+import androidx.annotation.DrawableRes;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.VisibleForTesting;
+import androidx.preference.Preference;
+import androidx.preference.PreferenceScreen;
+import androidx.recyclerview.widget.GridLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+
+import com.android.settings.R;
+import com.android.settings.dashboard.DashboardFragment;
+import com.android.settingslib.widget.LayoutPreference;
+
+import com.google.common.collect.ImmutableList;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Objects;
+
+class ZenModeIconPickerListPreferenceController extends AbstractZenModePreferenceController {
+
+ private final DashboardFragment mFragment;
+ private IconAdapter mAdapter;
+
+ ZenModeIconPickerListPreferenceController(@NonNull Context context, @NonNull String key,
+ @NonNull DashboardFragment fragment, @Nullable ZenModesBackend backend) {
+ super(context, key, backend);
+ mFragment = fragment;
+ }
+
+ @Override
+ public void displayPreference(PreferenceScreen screen) {
+ super.displayPreference(screen);
+ LayoutPreference pref = screen.findPreference(getPreferenceKey());
+ if (pref == null) {
+ return;
+ }
+
+ if (mAdapter == null) {
+ // TODO: b/333901673 - This is just an example; replace with correct list.
+ List exampleIcons =
+ Arrays.stream(android.R.drawable.class.getFields())
+ .filter(
+ f -> Modifier.isStatic(f.getModifiers())
+ && f.getName().startsWith("ic_"))
+ .sorted(Comparator.comparing(Field::getName))
+ .limit(20)
+ .map(f -> {
+ try {
+ return new IconInfo(f.getInt(null), f.getName());
+ } catch (IllegalAccessException e) {
+ return null;
+ }
+ })
+ .filter(Objects::nonNull)
+ .toList();
+ mAdapter = new IconAdapter(exampleIcons);
+ }
+ RecyclerView recyclerView = pref.findViewById(R.id.icon_list);
+ recyclerView.setLayoutManager(new AutoFitGridLayoutManager(mContext));
+ recyclerView.setAdapter(mAdapter);
+ recyclerView.setHasFixedSize(true);
+ }
+
+ @VisibleForTesting
+ void onIconSelected(@DrawableRes int resId) {
+ saveMode(mode -> {
+ mode.getRule().setIconResId(resId);
+ return mode;
+ });
+ mFragment.finish();
+ }
+
+ @Override
+ void updateState(Preference preference, @NonNull ZenMode zenMode) {
+ // Nothing to do, the current icon is shown in a different preference.
+ }
+
+ private record IconInfo(@DrawableRes int resId, String description) { }
+
+ private class IconHolder extends RecyclerView.ViewHolder {
+
+ private final ImageView mImageView;
+
+ IconHolder(@NonNull View itemView) {
+ super(itemView);
+ mImageView = itemView.findViewById(R.id.icon_image_view);
+ }
+
+ void bindIcon(IconInfo icon) {
+ mImageView.setImageDrawable(
+ IconUtil.makeIconCircle(itemView.getContext(), icon.resId()));
+ itemView.setContentDescription(icon.description());
+ itemView.setOnClickListener(v -> onIconSelected(icon.resId()));
+ }
+ }
+
+ private class IconAdapter extends RecyclerView.Adapter {
+
+ private final ImmutableList mIconResources;
+
+ private IconAdapter(List iconOptions) {
+ mIconResources = ImmutableList.copyOf(iconOptions);
+ }
+
+ @NonNull
+ @Override
+ public IconHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
+ View itemView = LayoutInflater.from(parent.getContext()).inflate(
+ R.layout.modes_icon_list_item, parent, false);
+ return new IconHolder(itemView);
+ }
+
+ @Override
+ public void onBindViewHolder(@NonNull IconHolder holder, int position) {
+ holder.bindIcon(mIconResources.get(position));
+ }
+
+ @Override
+ public int getItemCount() {
+ return mIconResources.size();
+ }
+ }
+
+ private static class AutoFitGridLayoutManager extends GridLayoutManager {
+ private final float mColumnWidth;
+
+ AutoFitGridLayoutManager(Context context) {
+ super(context, /* spanCount= */ 1);
+ this.mColumnWidth = context
+ .getResources()
+ .getDimensionPixelSize(R.dimen.zen_mode_icon_list_item_size);
+ }
+
+ @Override
+ public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
+ final int totalSpace = getWidth() - getPaddingRight() - getPaddingLeft();
+ final int spanCount = Math.max(1, (int) (totalSpace / mColumnWidth));
+ setSpanCount(spanCount);
+ super.onLayoutChildren(recycler, state);
+ }
+ }
+}
diff --git a/src/com/android/settings/notification/modes/ZenModeListPreference.java b/src/com/android/settings/notification/modes/ZenModeListPreference.java
index a106bddf964..c3daa614343 100644
--- a/src/com/android/settings/notification/modes/ZenModeListPreference.java
+++ b/src/com/android/settings/notification/modes/ZenModeListPreference.java
@@ -23,7 +23,6 @@ import android.os.Bundle;
import com.android.settings.core.SubSettingLauncher;
import com.android.settingslib.RestrictedPreference;
-import com.android.settingslib.Utils;
/**
* Preference representing a single mode item on the modes aggregator page. Clicking on this
@@ -59,11 +58,7 @@ class ZenModeListPreference extends RestrictedPreference {
FutureUtil.whenDone(
mZenMode.getIcon(mContext, IconLoader.getInstance()),
- icon -> {
- icon.setTintList(
- Utils.getColorAttr(mContext, android.R.attr.colorControlNormal));
- setIcon(icon);
- },
+ icon -> setIcon(IconUtil.applyTint(mContext, icon)),
mContext.getMainExecutor());
}
}
diff --git a/tests/robotests/src/com/android/settings/notification/modes/ZenModeIconPickerListPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/modes/ZenModeIconPickerListPreferenceControllerTest.java
new file mode 100644
index 00000000000..c0fbe15a6c2
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/notification/modes/ZenModeIconPickerListPreferenceControllerTest.java
@@ -0,0 +1,91 @@
+/*
+ * 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 static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.AutomaticZenRule;
+import android.content.Context;
+import android.net.Uri;
+
+import androidx.preference.PreferenceScreen;
+import androidx.recyclerview.widget.RecyclerView;
+
+import com.android.settings.R;
+import com.android.settings.dashboard.DashboardFragment;
+import com.android.settingslib.widget.LayoutPreference;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+
+@RunWith(RobolectricTestRunner.class)
+public class ZenModeIconPickerListPreferenceControllerTest {
+
+ private static final ZenMode ZEN_MODE = new ZenMode(
+ "mode_id",
+ new AutomaticZenRule.Builder("mode name", Uri.parse("mode")).build(),
+ /* isActive= */ false);
+
+ private ZenModesBackend mBackend;
+ private ZenModeIconPickerListPreferenceController mController;
+ private PreferenceScreen mPreferenceScreen;
+ private RecyclerView mRecyclerView;
+
+ @Before
+ public void setUp() {
+ Context context = RuntimeEnvironment.getApplication();
+ mBackend = mock(ZenModesBackend.class);
+
+ DashboardFragment fragment = mock(DashboardFragment.class);
+ mController = new ZenModeIconPickerListPreferenceController(
+ RuntimeEnvironment.getApplication(), "icon_list", fragment, mBackend);
+
+ mRecyclerView = new RecyclerView(context);
+ mRecyclerView.setId(R.id.icon_list);
+ LayoutPreference layoutPreference = new LayoutPreference(context, mRecyclerView);
+ mPreferenceScreen = mock(PreferenceScreen.class);
+ when(mPreferenceScreen.findPreference(eq("icon_list"))).thenReturn(layoutPreference);
+ }
+
+ @Test
+ public void displayPreference_loadsIcons() {
+ mController.displayPreference(mPreferenceScreen);
+
+ assertThat(mRecyclerView.getAdapter()).isNotNull();
+ assertThat(mRecyclerView.getAdapter().getItemCount()).isEqualTo(20);
+ }
+
+ @Test
+ public void selectIcon_updatesMode() {
+ mController.setZenMode(ZEN_MODE);
+
+ mController.onIconSelected(R.drawable.ic_android);
+
+ ArgumentCaptor captor = ArgumentCaptor.forClass(ZenMode.class);
+ verify(mBackend).updateMode(captor.capture());
+ assertThat(captor.getValue().getRule().getIconResId()).isEqualTo(R.drawable.ic_android);
+ }
+}