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); + } +}