Redesign zen visual effects screens

Test: robotests
Bug: 78448988
Change-Id: I3040c1103d76c75601e82e3660a2ace202837ec2
This commit is contained in:
Julia Reynolds
2018-04-23 12:24:21 -04:00
parent 98015e7c93
commit 4aa42fed67
20 changed files with 1507 additions and 60 deletions

View File

@@ -738,23 +738,6 @@
android:value="true" /> android:value="true" />
</activity> </activity>
<activity
android:name="Settings$ZenModeBlockedEffectsSettingsActivity"
android:label="@string/zen_mode_what_to_block_title"
android:icon="@drawable/ic_settings_notifications"
android:exported="true"
android:taskAffinity="com.android.settings"
android:parentActivityName="Settings">
<intent-filter android:priority="1">
<action android:name="android.settings.ZEN_MODE_BLOCKED_EFFECTS_SETTINGS" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
<meta-data android:name="com.android.settings.FRAGMENT_CLASS"
android:value="com.android.settings.notification.ZenModeBlockedEffectsSettings" />
<meta-data android:name="com.android.settings.PRIMARY_PROFILE_CONTROLLED"
android:value="true" />
</activity>
<activity <activity
android:name=".notification.ZenOnboardingActivity" android:name=".notification.ZenOnboardingActivity"
android:label="@string/zen_onboarding_dnd_visual_disturbances_header" android:label="@string/zen_onboarding_dnd_visual_disturbances_header"

View File

@@ -0,0 +1,90 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2018 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.
-->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:settings="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?android:attr/listPreferredItemHeightSmall"
android:gravity="center_vertical"
android:background="@android:color/transparent"
android:clipToPadding="false">
<LinearLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="?android:attr/selectableItemBackground"
android:gravity="start|center_vertical"
android:clipToPadding="false">
<LinearLayout
android:id="@+id/checkbox_frame"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="center"
android:minWidth="56dp"
android:layout_marginEnd="16dp"
android:orientation="vertical">
<RadioButton
android:id="@android:id/checkbox"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:background="@null"
android:focusable="false"
android:clickable="false" />
</LinearLayout>
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:paddingTop="16dp"
android:paddingBottom="16dp">
<TextView
android:id="@android:id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:singleLine="true"
android:textAppearance="?android:attr/textAppearanceListItem"
android:ellipsize="marquee" />
<TextView
android:id="@android:id/summary"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@android:id/title"
android:layout_alignStart="@android:id/title"
android:textAppearance="?android:attr/textAppearanceListItemSecondary"
android:textColor="?android:attr/textColorSecondary"
android:maxLines="10" />
</RelativeLayout>
</LinearLayout>
<include layout="@layout/preference_two_target_divider" />
<LinearLayout
android:id="@android:id/widget_frame"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="center"
android:minWidth="64dp"
android:orientation="vertical" />
</LinearLayout>

View File

@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2018 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.
-->
<!-- Layout used by CheckBoxPreference for the checkbox style. This is inflated
inside android.R.layout.preference. -->
<RadioButton xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@android:id/checkbox"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:background="@null"
android:focusable="false"
android:clickable="false" />

View File

@@ -7215,8 +7215,39 @@
<!-- Do not disturb: Subtitle for the Visual signals option to toggle on/off visual signals/alerts when the screen is on/when screen is off. [CHAR LIMIT=30] --> <!-- Do not disturb: Subtitle for the Visual signals option to toggle on/off visual signals/alerts when the screen is on/when screen is off. [CHAR LIMIT=30] -->
<string name="zen_mode_visual_signals_settings_subtitle">Allow visual signals</string> <string name="zen_mode_visual_signals_settings_subtitle">Allow visual signals</string>
<!-- Do not disturb: restrict notifications title [CHAR LIMIT=60] -->
<string name="zen_mode_restrict_notifications_screen_title">Restrict notifications</string>
<!-- Do not disturb: restrict notifications title [CHAR LIMIT=60] -->
<string name="zen_mode_restrict_notifications_title">Notifications</string>
<!-- Do not disturb: restrict notifications category title [CHAR LIMIT=100] -->
<string name="zen_mode_restrict_notifications_category">When Do Not Disturb is turned on</string>
<!-- Do not disturb: Mute notifications option [CHAR LIMIT=60] -->
<string name="zen_mode_restrict_notifications_mute">Mute notifications</string>
<!-- Do not disturb:Mute notifications summary [CHAR LIMIT=NONE] -->
<string name="zen_mode_restrict_notifications_mute_summary">Show notifications but mute sounds &amp; vibrations</string>
<!-- Do not disturb:Mute notifications footer [CHAR LIMIT=NONE] -->
<string name="zen_mode_restrict_notifications_mute_footer">When new notifications arrive your phone won\u2019t make a sound or vibration</string>
<!-- Do not disturb: Hide notifications option [CHAR LIMIT=60] -->
<string name="zen_mode_restrict_notifications_hide">Hide &amp; mute notifications</string>
<!-- Do not disturb: Hide notifications summary [CHAR LIMIT=NONE] -->
<string name="zen_mode_restrict_notifications_hide_summary">Notifications will not appear at all</string>
<!-- Do not disturb: Hide notifications footer [CHAR LIMIT=NONE] -->
<string name="zen_mode_restrict_notifications_hide_footer">You won\u2019t see new or existing notifications when Do Not Disturb is on. However, notifications needed for basic phone activity and status will still appear.</string>
<!-- Do not disturb: Custom settings option [CHAR LIMIT=60] -->
<string name="zen_mode_restrict_notifications_custom">Custom</string>
<!-- Do not disturb: restrict notifications page, menu option [CHAR LIMIT=60] -->
<string name="zen_mode_restrict_notifications_enable_custom">Enable custom setting</string>
<!-- Do not disturb: restrict notifications page, menu option [CHAR LIMIT=60] -->
<string name="zen_mode_restrict_notifications_disable_custom">Remove custom setting</string>
<!-- Do not disturb: restrict notifications page, menu option [CHAR LIMIT=60] -->
<string name="zen_mode_restrict_notifications_summary_muted">Will appear</string>
<!-- Do not disturb: restrict notifications page, menu option [CHAR LIMIT=60] -->
<string name="zen_mode_restrict_notifications_summary_custom">Partially hidden</string>
<!-- Do not disturb: restrict notifications page, menu option [CHAR LIMIT=60] -->
<string name="zen_mode_restrict_notifications_summary_hidden">Hidden</string>
<!-- Do not disturb: what to block title [CHAR LIMIT = 60] --> <!-- Do not disturb: what to block title [CHAR LIMIT = 60] -->
<string name="zen_mode_what_to_block_title">Block visual disturbances</string> <string name="zen_mode_what_to_block_title">Custom restrictions</string>
<!-- Do not disturb: what to block > effects title [CHAR LIMIT = 60] --> <!-- Do not disturb: what to block > effects title [CHAR LIMIT = 60] -->
<string name="zen_mode_block_effects_screen_on">When the screen is on</string> <string name="zen_mode_block_effects_screen_on">When the screen is on</string>
<!-- Do not disturb: what to block > effects title [CHAR LIMIT = 60] --> <!-- Do not disturb: what to block > effects title [CHAR LIMIT = 60] -->

View File

@@ -0,0 +1,43 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2018 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.
-->
<PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android"
android:key="zen_mode_restrict_settings_page"
android:title="@string/zen_mode_restrict_notifications_screen_title">
<PreferenceCategory
android:key="restrict_category"
android:title="@string/zen_mode_restrict_notifications_category">
<com.android.settings.notification.ZenCustomRadioButtonPreference
android:key="zen_mute_notifications"
android:title="@string/zen_mode_restrict_notifications_mute"
android:summary="@string/zen_mode_restrict_notifications_mute_summary"/>
<com.android.settings.notification.ZenCustomRadioButtonPreference
android:key="zen_hide_notifications"
android:title="@string/zen_mode_restrict_notifications_hide"
android:summary="@string/zen_mode_restrict_notifications_hide_summary"/>
<com.android.settings.notification.ZenCustomRadioButtonPreference
android:key="zen_custom"
android:title="@string/zen_mode_restrict_notifications_custom" />
</PreferenceCategory>
<com.android.settingslib.widget.FooterPreference />
</PreferenceScreen>

View File

@@ -31,8 +31,8 @@
<!-- What to block (effects) --> <!-- What to block (effects) -->
<Preference <Preference
android:key="zen_mode_block_effects_settings" android:key="zen_mode_block_effects_settings"
android:title="@string/zen_mode_what_to_block_title" android:title="@string/zen_mode_restrict_notifications_title"
android:fragment="com.android.settings.notification.ZenModeBlockedEffectsSettings" /> android:fragment="com.android.settings.notification.ZenModeRestrictNotificationsSettings" />
<!-- Behavior settings (exceptions) --> <!-- Behavior settings (exceptions) -->
<Preference <Preference

View File

@@ -54,6 +54,7 @@ abstract public class AbstractZenModePreferenceController extends
protected static ZenModeConfigWrapper mZenModeConfigWrapper; protected static ZenModeConfigWrapper mZenModeConfigWrapper;
protected MetricsFeatureProvider mMetricsFeatureProvider; protected MetricsFeatureProvider mMetricsFeatureProvider;
protected final ZenModeBackend mBackend; protected final ZenModeBackend mBackend;
protected PreferenceScreen mScreen;
public AbstractZenModePreferenceController(Context context, String key, public AbstractZenModePreferenceController(Context context, String key,
Lifecycle lifecycle) { Lifecycle lifecycle) {
@@ -71,16 +72,26 @@ abstract public class AbstractZenModePreferenceController extends
mBackend = ZenModeBackend.getInstance(context); mBackend = ZenModeBackend.getInstance(context);
} }
@Override
public String getPreferenceKey() {
return KEY;
}
@Override @Override
public void displayPreference(PreferenceScreen screen) { public void displayPreference(PreferenceScreen screen) {
super.displayPreference(screen); super.displayPreference(screen);
mSettingObserver = new SettingObserver(screen.findPreference(KEY)); mScreen = screen;
Preference pref = screen.findPreference(KEY);
if (pref != null) {
mSettingObserver = new SettingObserver(pref);
}
} }
@Override @Override
public void onResume() { public void onResume() {
if (mSettingObserver != null) { if (mSettingObserver != null) {
mSettingObserver.register(mContext.getContentResolver()); mSettingObserver.register(mContext.getContentResolver());
mSettingObserver.onChange(false, null);
} }
} }
@@ -91,14 +102,6 @@ abstract public class AbstractZenModePreferenceController extends
} }
} }
@Override
public void updateState(Preference preference) {
super.updateState(preference);
mBackend.updatePolicy();
mBackend.updateZenMode();
}
protected NotificationManager.Policy getPolicy() { protected NotificationManager.Policy getPolicy() {
return mNotificationManager.getNotificationPolicy(); return mNotificationManager.getNotificationPolicy();
} }
@@ -144,8 +147,13 @@ abstract public class AbstractZenModePreferenceController extends
@Override @Override
public void onChange(boolean selfChange, Uri uri) { public void onChange(boolean selfChange, Uri uri) {
super.onChange(selfChange, uri); super.onChange(selfChange, uri);
if (ZEN_MODE_URI.equals(uri) || ZEN_MODE_CONFIG_ETAG_URI.equals(uri) if (uri == null || ZEN_MODE_URI.equals(uri) || ZEN_MODE_CONFIG_ETAG_URI.equals(uri)
|| ZEN_MODE_DURATION_URI.equals(uri)) { || ZEN_MODE_DURATION_URI.equals(uri)) {
mBackend.updatePolicy();
mBackend.updateZenMode();
if (mScreen != null) {
displayPreference(mScreen);
}
updateState(mPreference); updateState(mPreference);
} }
} }

View File

@@ -0,0 +1,140 @@
/*
* Copyright (C) 2018 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;
import android.content.Context;
import androidx.preference.PreferenceViewHolder;
import android.util.AttributeSet;
import android.view.View;
import android.widget.RadioButton;
import com.android.settings.R;
import com.android.settingslib.TwoTargetPreference;
/**
* A radio button preference with a divider and a settings icon that links to another screen.
*/
public class ZenCustomRadioButtonPreference extends TwoTargetPreference
implements View.OnClickListener {
private RadioButton mButton;
private boolean mChecked;
private OnGearClickListener mOnGearClickListener;
private OnRadioButtonClickListener mOnRadioButtonClickListener;
public ZenCustomRadioButtonPreference(Context context, AttributeSet attrs,
int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
setLayoutResource(R.layout.preference_two_target_radio);
}
public ZenCustomRadioButtonPreference(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
setLayoutResource(R.layout.preference_two_target_radio);
}
public ZenCustomRadioButtonPreference(Context context, AttributeSet attrs) {
super(context, attrs);
setLayoutResource(R.layout.preference_two_target_radio);
}
public ZenCustomRadioButtonPreference(Context context) {
super(context);
setLayoutResource(R.layout.preference_two_target_radio);
}
@Override
protected int getSecondTargetResId() {
return R.layout.preference_widget_gear;
}
public void setOnGearClickListener(OnGearClickListener l) {
mOnGearClickListener = l;
notifyChanged();
}
public void setOnRadioButtonClickListener(OnRadioButtonClickListener l) {
mOnRadioButtonClickListener = l;
notifyChanged();
}
@Override
public void onBindViewHolder(PreferenceViewHolder holder) {
super.onBindViewHolder(holder);
View buttonFrame = holder.findViewById(R.id.checkbox_frame);
if (buttonFrame != null) {
buttonFrame.setOnClickListener(this);
}
mButton = (RadioButton) holder.findViewById(android.R.id.checkbox);
if (mButton != null) {
mButton.setChecked(mChecked);
}
final View gear = holder.findViewById(android.R.id.widget_frame);
if (mOnGearClickListener != null) {
gear.setVisibility(View.VISIBLE);
gear.setOnClickListener(this);
} else {
gear.setVisibility(View.GONE);
gear.setOnClickListener(null);
}
}
public boolean isChecked() {
return mButton != null && mChecked;
}
public void setChecked(boolean checked) {
mChecked = checked;
if (mButton != null) {
mButton.setChecked(checked);
}
}
public RadioButton getRadioButton() {
return mButton;
}
@Override
public void onClick() {
if (mOnRadioButtonClickListener != null) {
mOnRadioButtonClickListener.onRadioButtonClick(this);
}
}
@Override
public void onClick(View v) {
if (v.getId() == android.R.id.widget_frame) {
if (mOnGearClickListener != null) {
mOnGearClickListener.onGearClick(this);
}
} else if (v.getId() == R.id.checkbox_frame) {
if (mOnRadioButtonClickListener != null) {
mOnRadioButtonClickListener.onRadioButtonClick(this);
}
}
}
public interface OnGearClickListener {
void onGearClick(ZenCustomRadioButtonPreference p);
}
public interface OnRadioButtonClickListener {
void onRadioButtonClick(ZenCustomRadioButtonPreference p);
}
}

View File

@@ -0,0 +1,56 @@
/*
* Copyright (C) 2018 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;
import android.app.NotificationManager.Policy;
import android.content.Context;
import androidx.preference.Preference;
import androidx.preference.PreferenceScreen;
import com.android.settings.R;
import com.android.settingslib.core.lifecycle.Lifecycle;
public class ZenFooterPreferenceController extends AbstractZenModePreferenceController {
public ZenFooterPreferenceController(Context context, Lifecycle lifecycle,
String key) {
super(context, key, lifecycle);
}
@Override
public boolean isAvailable() {
return mBackend.mPolicy.suppressedVisualEffects == 0
|| Policy.areAllVisualEffectsSuppressed(mBackend.mPolicy.suppressedVisualEffects);
}
@Override
public void updateState(Preference preference) {
super.updateState(preference);
if (mBackend.mPolicy.suppressedVisualEffects == 0) {
preference.setTitle(R.string.zen_mode_restrict_notifications_mute_footer);
} else if (Policy.areAllVisualEffectsSuppressed(mBackend.mPolicy.suppressedVisualEffects)) {
preference.setTitle(R.string.zen_mode_restrict_notifications_hide_footer);
} else {
preference.setTitle(null);
}
}
protected void hide(PreferenceScreen screen) {
setVisible(screen, getPreferenceKey(), false /* visible */);
}
}

View File

@@ -0,0 +1,151 @@
/*
* Copyright (C) 2018 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;
import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.ACTION_ZEN_SHOW_CUSTOM;
import android.content.Context;
import android.os.Bundle;
import android.provider.SearchIndexableResource;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settings.R;
import com.android.settings.overlay.FeatureFactory;
import com.android.settings.search.BaseSearchIndexProvider;
import com.android.settings.search.Indexable;
import com.android.settingslib.core.AbstractPreferenceController;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
import com.android.settingslib.core.lifecycle.Lifecycle;
import com.android.settingslib.search.SearchIndexable;
import com.android.settingslib.widget.FooterPreference;
import java.util.ArrayList;
import java.util.List;
@SearchIndexable(forTarget = SearchIndexable.ALL & ~SearchIndexable.ARC)
public class ZenModeRestrictNotificationsSettings extends ZenModeSettingsBase implements Indexable {
protected static final int APP_MENU_SHOW_CUSTOM = 1;
protected boolean mShowMenuSelected;
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
menu.add(0, APP_MENU_SHOW_CUSTOM, 0, R.string.zen_mode_restrict_notifications_enable_custom)
.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
}
@Override
public boolean onOptionsItemSelected(MenuItem menuItem) {
if (menuItem.getItemId() == APP_MENU_SHOW_CUSTOM) {
final FeatureFactory featureFactory = FeatureFactory.getFactory(mContext);
MetricsFeatureProvider metrics = featureFactory.getMetricsFeatureProvider();
mShowMenuSelected = !mShowMenuSelected;
ZenModeVisEffectsCustomPreferenceController custom =
use(ZenModeVisEffectsCustomPreferenceController.class);
custom.setShownByMenu(mShowMenuSelected);
if (mShowMenuSelected) {
custom.select();
metrics.action(mContext, ACTION_ZEN_SHOW_CUSTOM, true);
} else {
metrics.action(mContext, ACTION_ZEN_SHOW_CUSTOM, false);
}
return true;
}
return false;
}
@Override
public void onPrepareOptionsMenu(Menu menu) {
if (mShowMenuSelected && !use(ZenModeVisEffectsCustomPreferenceController.class)
.areCustomOptionsSelected()) {
menu.findItem(APP_MENU_SHOW_CUSTOM)
.setTitle(R.string.zen_mode_restrict_notifications_disable_custom);
} else {
menu.findItem(APP_MENU_SHOW_CUSTOM)
.setTitle(R.string.zen_mode_restrict_notifications_enable_custom);
}
}
@Override
protected List<AbstractPreferenceController> createPreferenceControllers(Context context) {
return buildPreferenceControllers(context, getLifecycle());
}
private static List<AbstractPreferenceController> buildPreferenceControllers(Context context,
Lifecycle lifecycle) {
List<AbstractPreferenceController> controllers = new ArrayList<>();
controllers.add(new ZenModeVisEffectsNonePreferenceController(
context, lifecycle, "zen_mute_notifications"));
controllers.add(new ZenModeVisEffectsAllPreferenceController(
context, lifecycle, "zen_hide_notifications"));
controllers.add(new ZenModeVisEffectsCustomPreferenceController(
context, lifecycle, "zen_custom"));
controllers.add(new ZenFooterPreferenceController(context, lifecycle,
FooterPreference.KEY_FOOTER));
return controllers;
}
@Override
protected int getPreferenceScreenResId() {
return R.xml.zen_mode_restrict_notifications_settings;
}
@Override
public int getMetricsCategory() {
return MetricsEvent.SETTINGS_ZEN_NOTIFICATIONS;
}
/**
* For Search.
*/
public static final SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
new BaseSearchIndexProvider() {
@Override
public List<SearchIndexableResource> getXmlResourcesToIndex(Context context,
boolean enabled) {
final ArrayList<SearchIndexableResource> result = new ArrayList<>();
final SearchIndexableResource sir = new SearchIndexableResource(context);
sir.xmlResId = R.xml.zen_mode_restrict_notifications_settings;
result.add(sir);
return result;
}
@Override
public List<String> getNonIndexableKeys(Context context) {
final List<String> keys = super.getNonIndexableKeys(context);
return keys;
}
@Override
public List<AbstractPreferenceController> createPreferenceControllers(Context context) {
return buildPreferenceControllers(context, null);
}
};
}

View File

@@ -160,24 +160,15 @@ public class ZenModeSettings extends ZenModeSettingsBase {
} }
String getBlockedEffectsSummary(Policy policy) { String getBlockedEffectsSummary(Policy policy) {
List<String> blockedStrings = new ArrayList<>(); if (policy.suppressedVisualEffects == 0) {
if (Policy.areAnyScreenOffEffectsSuppressed(policy.suppressedVisualEffects)) {
blockedStrings.add(mContext.getResources().getString(
R.string.zen_mode_block_effect_summary_screen_off));
}
if (Policy.areAnyScreenOnEffectsSuppressed(policy.suppressedVisualEffects)) {
blockedStrings.add(mContext.getResources().getString(
R.string.zen_mode_block_effect_summary_screen_on));
}
if (blockedStrings.size() == 0) {
return mContext.getResources().getString( return mContext.getResources().getString(
R.string.zen_mode_block_effect_summary_none); R.string.zen_mode_restrict_notifications_summary_muted);
} else if (blockedStrings.size() == 1) { } else if (Policy.areAllVisualEffectsSuppressed(policy.suppressedVisualEffects)) {
return blockedStrings.get(0); return mContext.getResources().getString(
R.string.zen_mode_restrict_notifications_summary_hidden);
} else { } else {
return mContext.getResources().getString(R.string.join_two_unrelated_items, return mContext.getResources().getString(
blockedStrings.get(0), blockedStrings.get(1)); R.string.zen_mode_restrict_notifications_summary_custom);
} }
} }

View File

@@ -0,0 +1,76 @@
/*
* Copyright (C) 2018 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;
import android.app.NotificationManager.Policy;
import android.content.Context;
import androidx.preference.Preference;
import androidx.preference.PreferenceScreen;
import com.android.internal.logging.nano.MetricsProto;
import com.android.settingslib.core.lifecycle.Lifecycle;
public class ZenModeVisEffectsAllPreferenceController
extends AbstractZenModePreferenceController
implements ZenCustomRadioButtonPreference.OnRadioButtonClickListener {
protected static final int EFFECTS = Policy.SUPPRESSED_EFFECT_SCREEN_OFF
| Policy.SUPPRESSED_EFFECT_SCREEN_ON
| Policy.SUPPRESSED_EFFECT_FULL_SCREEN_INTENT
| Policy.SUPPRESSED_EFFECT_LIGHTS
| Policy.SUPPRESSED_EFFECT_PEEK
| Policy.SUPPRESSED_EFFECT_STATUS_BAR
| Policy.SUPPRESSED_EFFECT_BADGE
| Policy.SUPPRESSED_EFFECT_AMBIENT
| Policy.SUPPRESSED_EFFECT_NOTIFICATION_LIST;
public ZenModeVisEffectsAllPreferenceController(Context context, Lifecycle lifecycle,
String key) {
super(context, key, lifecycle);
}
@Override
public boolean isAvailable() {
return true;
}
@Override
public void updateState(Preference preference) {
super.updateState(preference);
boolean everythingBlocked = Policy.areAllVisualEffectsSuppressed(
mBackend.mPolicy.suppressedVisualEffects);
ZenCustomRadioButtonPreference pref = (ZenCustomRadioButtonPreference) preference;
pref.setOnRadioButtonClickListener(this);
pref.setChecked(everythingBlocked);
}
protected void deselect(PreferenceScreen screen) {
ZenCustomRadioButtonPreference preference =
(ZenCustomRadioButtonPreference) screen.findPreference(getPreferenceKey());
if (preference != null) {
preference.setChecked(false);
}
}
@Override
public void onRadioButtonClick(ZenCustomRadioButtonPreference p) {
mMetricsFeatureProvider.action(mContext,
MetricsProto.MetricsEvent.ACTION_ZEN_SOUND_AND_VIS_EFFECTS, true);
mBackend.saveVisualEffectsPolicy(EFFECTS, true);
}
}

View File

@@ -0,0 +1,92 @@
/*
* Copyright (C) 2018 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;
import android.app.NotificationManager.Policy;
import android.content.Context;
import androidx.preference.Preference;
import androidx.preference.PreferenceScreen;
import com.android.internal.logging.nano.MetricsProto;
import com.android.settings.R;
import com.android.settings.core.SubSettingLauncher;
import com.android.settingslib.core.lifecycle.Lifecycle;
public class ZenModeVisEffectsCustomPreferenceController
extends AbstractZenModePreferenceController {
protected boolean mShowMenuSelected;
protected static final int INTERRUPTIVE_EFFECTS = Policy.SUPPRESSED_EFFECT_AMBIENT
| Policy.SUPPRESSED_EFFECT_PEEK
| Policy.SUPPRESSED_EFFECT_LIGHTS
| Policy.SUPPRESSED_EFFECT_FULL_SCREEN_INTENT;
public ZenModeVisEffectsCustomPreferenceController(Context context, Lifecycle lifecycle,
String key) {
super(context, key, lifecycle);
}
@Override
public boolean isAvailable() {
if (mShowMenuSelected) {
return true;
}
return areCustomOptionsSelected();
}
@Override
public void updateState(Preference preference) {
super.updateState(preference);
ZenCustomRadioButtonPreference pref = (ZenCustomRadioButtonPreference) preference;
pref.setChecked(areCustomOptionsSelected());
pref.setOnGearClickListener(p -> {
new SubSettingLauncher(mContext)
.setDestination(ZenModeBlockedEffectsSettings.class.getName())
.setTitle(R.string.zen_mode_what_to_block_title)
.setSourceMetricsCategory(MetricsProto.MetricsEvent.SETTINGS_ZEN_NOTIFICATIONS)
.launch();
});
pref.setOnRadioButtonClickListener(p -> {
select();
});
}
protected void setShownByMenu(boolean shown) {
mShowMenuSelected = shown;
}
protected boolean areCustomOptionsSelected() {
boolean allEffectsSuppressed =
Policy.areAllVisualEffectsSuppressed(mBackend.mPolicy.suppressedVisualEffects);
boolean noEffectsSuppressed = mBackend.mPolicy.suppressedVisualEffects == 0;
return !(allEffectsSuppressed || noEffectsSuppressed);
}
protected void select() {
mMetricsFeatureProvider.action(mContext,
MetricsProto.MetricsEvent.ACTION_ZEN_CUSTOM, true);
mBackend.savePolicy(mBackend.mPolicy.priorityCategories,
mBackend.mPolicy.priorityCallSenders,
mBackend.mPolicy.priorityMessageSenders,
INTERRUPTIVE_EFFECTS);
}
}

View File

@@ -0,0 +1,75 @@
/*
* Copyright (C) 2018 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;
import android.app.NotificationManager.Policy;
import android.content.Context;
import androidx.preference.Preference;
import androidx.preference.PreferenceScreen;
import com.android.internal.logging.nano.MetricsProto;
import com.android.settingslib.core.lifecycle.Lifecycle;
public class ZenModeVisEffectsNonePreferenceController
extends AbstractZenModePreferenceController
implements ZenCustomRadioButtonPreference.OnRadioButtonClickListener {
protected static final int EFFECTS = Policy.SUPPRESSED_EFFECT_SCREEN_OFF
| Policy.SUPPRESSED_EFFECT_SCREEN_ON
| Policy.SUPPRESSED_EFFECT_FULL_SCREEN_INTENT
| Policy.SUPPRESSED_EFFECT_LIGHTS
| Policy.SUPPRESSED_EFFECT_PEEK
| Policy.SUPPRESSED_EFFECT_STATUS_BAR
| Policy.SUPPRESSED_EFFECT_BADGE
| Policy.SUPPRESSED_EFFECT_AMBIENT
| Policy.SUPPRESSED_EFFECT_NOTIFICATION_LIST;
public ZenModeVisEffectsNonePreferenceController(Context context, Lifecycle lifecycle,
String key) {
super(context, key, lifecycle);
}
@Override
public boolean isAvailable() {
return true;
}
@Override
public void updateState(Preference preference) {
super.updateState(preference);
boolean nothingBlocked = mBackend.mPolicy.suppressedVisualEffects == 0;
ZenCustomRadioButtonPreference pref = (ZenCustomRadioButtonPreference) preference;
pref.setOnRadioButtonClickListener(this);
pref.setChecked(nothingBlocked);
}
@Override
public void onRadioButtonClick(ZenCustomRadioButtonPreference preference) {
mMetricsFeatureProvider.action(mContext,
MetricsProto.MetricsEvent.ACTION_ZEN_SOUND_ONLY, true);
mBackend.saveVisualEffectsPolicy(EFFECTS, false);
}
protected void deselect(PreferenceScreen screen) {
ZenCustomRadioButtonPreference preference =
(ZenCustomRadioButtonPreference) screen.findPreference(getPreferenceKey());
if (preference != null) {
preference.setChecked(false);
}
}
}

View File

@@ -0,0 +1,113 @@
/*
* Copyright (C) 2018 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;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import android.content.Context;
import androidx.preference.Preference.OnPreferenceChangeListener;
import androidx.preference.PreferenceViewHolder;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.RadioButton;
import android.widget.Switch;
import com.android.settings.R;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settings.widget.MasterSwitchPreference;
import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RuntimeEnvironment;
@RunWith(SettingsRobolectricTestRunner.class)
public class ZenCustomRadioButtonPreferenceTest {
private Context mContext;
@Before
public void setUp() {
mContext = RuntimeEnvironment.application;
}
@Test
public void createNewPreference_shouldSetLayout() {
final ZenCustomRadioButtonPreference preference
= new ZenCustomRadioButtonPreference(mContext);
assertThat(preference.getLayoutResource()).isEqualTo(R.layout.preference_two_target_radio);
assertThat(preference.getWidgetLayoutResource())
.isEqualTo(R.layout.preference_widget_gear);
}
@Test
public void setChecked_shouldUpdateButtonCheckedState() {
final ZenCustomRadioButtonPreference preference =
new ZenCustomRadioButtonPreference(mContext);
final PreferenceViewHolder holder = PreferenceViewHolder.createInstanceForTests(
LayoutInflater.from(mContext).inflate(
R.layout.preference_two_target_radio, null));
final RadioButton toggle = (RadioButton) holder.findViewById(android.R.id.checkbox);
preference.onBindViewHolder(holder);
preference.setChecked(true);
assertThat(toggle.isChecked()).isTrue();
preference.setChecked(false);
assertThat(toggle.isChecked()).isFalse();
}
@Test
public void clickRadioButton_shouldNotifyRadioButtonClicked() {
final ZenCustomRadioButtonPreference preference
= new ZenCustomRadioButtonPreference(mContext);
final PreferenceViewHolder holder = PreferenceViewHolder.createInstanceForTests(
LayoutInflater.from(mContext).inflate(R.layout.preference_two_target_radio, null));
final View toggle = holder.findViewById(R.id.checkbox_frame);
ZenCustomRadioButtonPreference.OnRadioButtonClickListener l = mock(
ZenCustomRadioButtonPreference.OnRadioButtonClickListener.class);
preference.setOnRadioButtonClickListener(l);
preference.onBindViewHolder(holder);
toggle.performClick();
verify(l).onRadioButtonClick(preference);
}
@Test
public void clickWidgetView_shouldNotifyWidgetClicked() {
final ZenCustomRadioButtonPreference preference =
new ZenCustomRadioButtonPreference(mContext);
final PreferenceViewHolder holder = PreferenceViewHolder.createInstanceForTests(
LayoutInflater.from(mContext).inflate(R.layout.preference_two_target_radio, null));
final View widgetView = holder.findViewById(android.R.id.widget_frame);
ZenCustomRadioButtonPreference.OnGearClickListener l = mock(
ZenCustomRadioButtonPreference.OnGearClickListener.class);
preference.setOnGearClickListener(l);
preference.onBindViewHolder(holder);
widgetView.performClick();
verify(l).onGearClick(preference);
}
}

View File

@@ -0,0 +1,138 @@
/*
* Copyright (C) 2018 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;
import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_AMBIENT;
import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_BADGE;
import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_FULL_SCREEN_INTENT;
import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_LIGHTS;
import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_NOTIFICATION_LIST;
import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK;
import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_OFF;
import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_ON;
import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_STATUS_BAR;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.NotificationManager;
import android.content.Context;
import androidx.preference.PreferenceScreen;
import com.android.settings.R;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settingslib.core.lifecycle.Lifecycle;
import com.android.settingslib.widget.FooterPreference;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.shadows.ShadowApplication;
import org.robolectric.util.ReflectionHelpers;
@RunWith(SettingsRobolectricTestRunner.class)
public class ZenFooterPreferenceControllerTest {
private ZenFooterPreferenceController mController;
@Mock
private ZenModeBackend mBackend;
@Mock
private FooterPreference mockPref;
private Context mContext;
@Mock
private PreferenceScreen mScreen;
@Mock NotificationManager mNotificationManager;
private static final String PREF_KEY = "main_pref";
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
ShadowApplication shadowApplication = ShadowApplication.getInstance();
mContext = shadowApplication.getApplicationContext();
shadowApplication.setSystemService(Context.NOTIFICATION_SERVICE, mNotificationManager);
when(mNotificationManager.getNotificationPolicy()).thenReturn(
mock(NotificationManager.Policy.class));
mController = new ZenFooterPreferenceController(
mContext, mock(Lifecycle.class), PREF_KEY);
ReflectionHelpers.setField(mController, "mBackend", mBackend);
when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(mockPref);
}
@Test
public void isAvailable_noVisEffects() {
mBackend.mPolicy = new NotificationManager.Policy(0, 0, 0, 0);
assertThat(mController.isAvailable()).isTrue();
}
@Test
public void isAvailable_someVisEffects() {
mBackend.mPolicy = new NotificationManager.Policy(0, 0, 0, 2);
assertThat(mController.isAvailable()).isFalse();
}
@Test
public void isAvailable_allVisEffects() {
int allSuppressed = SUPPRESSED_EFFECT_SCREEN_OFF
| SUPPRESSED_EFFECT_SCREEN_ON
| SUPPRESSED_EFFECT_FULL_SCREEN_INTENT
| SUPPRESSED_EFFECT_AMBIENT
| SUPPRESSED_EFFECT_STATUS_BAR
| SUPPRESSED_EFFECT_BADGE
| SUPPRESSED_EFFECT_LIGHTS
| SUPPRESSED_EFFECT_PEEK
| SUPPRESSED_EFFECT_NOTIFICATION_LIST;
mBackend.mPolicy = new NotificationManager.Policy(0, 0, 0, allSuppressed);
assertThat(mController.isAvailable()).isTrue();
}
@Test
public void updateSummary_noVisEffects() {
mBackend.mPolicy = new NotificationManager.Policy(0, 0, 0, 0);
mController.updateState(mockPref);
verify(mockPref).setTitle(R.string.zen_mode_restrict_notifications_mute_footer);
}
@Test
public void getSummary_someVisEffects() {
mBackend.mPolicy = new NotificationManager.Policy(0, 0, 0, 2);
mController.updateState(mockPref);
verify(mockPref).setTitle(null);
}
@Test
public void getSummary_allVisEffects() {
int allSuppressed = SUPPRESSED_EFFECT_SCREEN_OFF
| SUPPRESSED_EFFECT_SCREEN_ON
| SUPPRESSED_EFFECT_FULL_SCREEN_INTENT
| SUPPRESSED_EFFECT_AMBIENT
| SUPPRESSED_EFFECT_STATUS_BAR
| SUPPRESSED_EFFECT_BADGE
| SUPPRESSED_EFFECT_LIGHTS
| SUPPRESSED_EFFECT_PEEK
| SUPPRESSED_EFFECT_NOTIFICATION_LIST;
mBackend.mPolicy = new NotificationManager.Policy(0, 0, 0, allSuppressed);
mController.updateState(mockPref);
verify(mockPref).setTitle(R.string.zen_mode_restrict_notifications_hide_footer);
}
}

View File

@@ -74,29 +74,23 @@ public class ZenModeSettingsTest {
@Test @Test
public void testBlockedEffectsSummary_none() { public void testBlockedEffectsSummary_none() {
NotificationManager.Policy policy = new NotificationManager.Policy(0, 0, 0, 0); NotificationManager.Policy policy = new NotificationManager.Policy(0, 0, 0, 0);
assertEquals("Never", mBuilder.getBlockedEffectsSummary(policy)); assertEquals(mContext.getString(R.string.zen_mode_restrict_notifications_summary_muted),
mBuilder.getBlockedEffectsSummary(policy));
} }
@Test @Test
public void testBlockedEffectsSummary_screen_on() { public void testBlockedEffectsSummary_some() {
NotificationManager.Policy policy = new NotificationManager.Policy( NotificationManager.Policy policy = new NotificationManager.Policy(
0, 0, 0, NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK); 0, 0, 0, NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK);
assertEquals("When screen is on", mBuilder.getBlockedEffectsSummary(policy)); assertEquals(mContext.getString(R.string.zen_mode_restrict_notifications_summary_custom),
mBuilder.getBlockedEffectsSummary(policy));
} }
@Test @Test
public void testBlockedEffectsSummary_screen_off() { public void testBlockedEffectsSummary_all() {
NotificationManager.Policy policy = new NotificationManager.Policy( NotificationManager.Policy policy = new NotificationManager.Policy(
0, 0, 0, NotificationManager.Policy.SUPPRESSED_EFFECT_AMBIENT); 0, 0, 0, 511);
assertEquals("When screen is off", mBuilder.getBlockedEffectsSummary(policy)); assertEquals(mContext.getString(R.string.zen_mode_restrict_notifications_summary_hidden),
}
@Test
public void testBlockedEffectsSummary_both() {
NotificationManager.Policy policy = new NotificationManager.Policy(0, 0, 0,
NotificationManager.Policy.SUPPRESSED_EFFECT_NOTIFICATION_LIST
| NotificationManager.Policy.SUPPRESSED_EFFECT_LIGHTS);
assertEquals("When screen is off, When screen is on",
mBuilder.getBlockedEffectsSummary(policy)); mBuilder.getBlockedEffectsSummary(policy));
} }

View File

@@ -0,0 +1,141 @@
/*
* Copyright (C) 2018 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;
import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_AMBIENT;
import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_BADGE;
import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_FULL_SCREEN_INTENT;
import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_LIGHTS;
import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_NOTIFICATION_LIST;
import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK;
import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_OFF;
import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_ON;
import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_STATUS_BAR;
import static com.android.internal.logging.nano.MetricsProto.MetricsEvent
.ACTION_ZEN_SOUND_AND_VIS_EFFECTS;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.nullable;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.NotificationManager;
import android.content.Context;
import androidx.preference.PreferenceScreen;
import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settings.widget.DisabledCheckBoxPreference;
import com.android.settings.widget.RadioButtonPreference;
import com.android.settingslib.core.lifecycle.Lifecycle;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.shadows.ShadowApplication;
import org.robolectric.util.ReflectionHelpers;
@RunWith(SettingsRobolectricTestRunner.class)
public class ZenModeVisEffectsAllPreferenceControllerTest {
private ZenModeVisEffectsAllPreferenceController mController;
@Mock
private ZenModeBackend mBackend;
@Mock
private ZenCustomRadioButtonPreference mockPref;
private Context mContext;
private FakeFeatureFactory mFeatureFactory;
@Mock
private PreferenceScreen mScreen;
@Mock NotificationManager mNotificationManager;
private static final String PREF_KEY = "main_pref";
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
ShadowApplication shadowApplication = ShadowApplication.getInstance();
mContext = shadowApplication.getApplicationContext();
mFeatureFactory = FakeFeatureFactory.setupForTest();
shadowApplication.setSystemService(Context.NOTIFICATION_SERVICE, mNotificationManager);
when(mNotificationManager.getNotificationPolicy()).thenReturn(
mock(NotificationManager.Policy.class));
mController = new ZenModeVisEffectsAllPreferenceController(
mContext, mock(Lifecycle.class), PREF_KEY);
ReflectionHelpers.setField(mController, "mBackend", mBackend);
when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(mockPref);
mController.displayPreference(mScreen);
}
@Test
public void isAvailable() {
assertTrue(mController.isAvailable());
}
@Test
public void updateState_notChecked() {
mBackend.mPolicy = new NotificationManager.Policy(0, 0, 0, 1);
mController.updateState(mockPref);
verify(mockPref).setChecked(false);
}
@Test
public void updateState_checked() {
int allSuppressed = SUPPRESSED_EFFECT_SCREEN_OFF
| SUPPRESSED_EFFECT_SCREEN_ON
| SUPPRESSED_EFFECT_FULL_SCREEN_INTENT
| SUPPRESSED_EFFECT_AMBIENT
| SUPPRESSED_EFFECT_STATUS_BAR
| SUPPRESSED_EFFECT_BADGE
| SUPPRESSED_EFFECT_LIGHTS
| SUPPRESSED_EFFECT_PEEK
| SUPPRESSED_EFFECT_NOTIFICATION_LIST;
mBackend.mPolicy = new NotificationManager.Policy(0, 0, 0, allSuppressed);
mController.updateState(mockPref);
verify(mockPref).setChecked(true);
}
@Test
public void onPreferenceChanged_checkedTrue() {
int allSuppressed = SUPPRESSED_EFFECT_SCREEN_OFF
| SUPPRESSED_EFFECT_SCREEN_ON
| SUPPRESSED_EFFECT_FULL_SCREEN_INTENT
| SUPPRESSED_EFFECT_AMBIENT
| SUPPRESSED_EFFECT_STATUS_BAR
| SUPPRESSED_EFFECT_BADGE
| SUPPRESSED_EFFECT_LIGHTS
| SUPPRESSED_EFFECT_PEEK
| SUPPRESSED_EFFECT_NOTIFICATION_LIST;
mBackend.mPolicy = new NotificationManager.Policy(0, 0, 0, 1);
mController.onRadioButtonClick(mockPref);
verify(mBackend).saveVisualEffectsPolicy(allSuppressed, true);
verify(mFeatureFactory.metricsFeatureProvider).action(eq(mContext),
eq(ACTION_ZEN_SOUND_AND_VIS_EFFECTS),
eq(true));
}
}

View File

@@ -0,0 +1,167 @@
/*
* Copyright (C) 2018 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;
import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_AMBIENT;
import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_BADGE;
import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_FULL_SCREEN_INTENT;
import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_LIGHTS;
import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_NOTIFICATION_LIST;
import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK;
import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_OFF;
import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_ON;
import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_STATUS_BAR;
import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.ACTION_ZEN_CUSTOM;
import static com.android.internal.logging.nano.MetricsProto.MetricsEvent
.ACTION_ZEN_SOUND_AND_VIS_EFFECTS;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
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.NotificationManager;
import android.content.Context;
import androidx.preference.PreferenceScreen;
import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settingslib.core.lifecycle.Lifecycle;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.shadows.ShadowApplication;
import org.robolectric.util.ReflectionHelpers;
@RunWith(SettingsRobolectricTestRunner.class)
public class ZenModeVisEffectsCustomPreferenceControllerTest {
private ZenModeVisEffectsCustomPreferenceController mController;
@Mock
private ZenModeBackend mBackend;
@Mock
private ZenCustomRadioButtonPreference mockPref;
private Context mContext;
private FakeFeatureFactory mFeatureFactory;
@Mock
private PreferenceScreen mScreen;
@Mock NotificationManager mNotificationManager;
private static final String PREF_KEY = "main_pref";
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
ShadowApplication shadowApplication = ShadowApplication.getInstance();
mContext = shadowApplication.getApplicationContext();
mFeatureFactory = FakeFeatureFactory.setupForTest();
shadowApplication.setSystemService(Context.NOTIFICATION_SERVICE, mNotificationManager);
when(mNotificationManager.getNotificationPolicy()).thenReturn(
mock(NotificationManager.Policy.class));
mController = new ZenModeVisEffectsCustomPreferenceController(
mContext, mock(Lifecycle.class), PREF_KEY);
ReflectionHelpers.setField(mController, "mBackend", mBackend);
when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(mockPref);
}
@Test
public void isAvailable_menuOff_noVisEffects() {
mBackend.mPolicy = new NotificationManager.Policy(0, 0, 0, 0);
mController.mShowMenuSelected = false;
assertThat(mController.isAvailable()).isFalse();
}
@Test
public void isAvailable_menuOn_noVisEffects() {
mBackend.mPolicy = new NotificationManager.Policy(0, 0, 0, 0);
mController.mShowMenuSelected = true;
assertThat(mController.isAvailable()).isTrue();
}
@Test
public void isAvailable_menuOn_visEffects() {
mBackend.mPolicy = new NotificationManager.Policy(0, 0, 0, 1);
mController.mShowMenuSelected = false;
assertThat(mController.isAvailable()).isTrue();
}
@Test
public void updateState_notChecked_noVisEffects() {
mBackend.mPolicy = new NotificationManager.Policy(0, 0, 0, 0);
mController.updateState(mockPref);
verify(mockPref).setChecked(false);
}
@Test
public void updateState_notChecked_allVisEffects() {
int allSuppressed = SUPPRESSED_EFFECT_SCREEN_OFF
| SUPPRESSED_EFFECT_SCREEN_ON
| SUPPRESSED_EFFECT_FULL_SCREEN_INTENT
| SUPPRESSED_EFFECT_AMBIENT
| SUPPRESSED_EFFECT_STATUS_BAR
| SUPPRESSED_EFFECT_BADGE
| SUPPRESSED_EFFECT_LIGHTS
| SUPPRESSED_EFFECT_PEEK
| SUPPRESSED_EFFECT_NOTIFICATION_LIST;
mBackend.mPolicy = new NotificationManager.Policy(0, 0, 0, allSuppressed);
mController.updateState(mockPref);
verify(mockPref).setChecked(false);
}
@Test
public void updateState_checked() {
mBackend.mPolicy = new NotificationManager.Policy(0, 0, 0, 2);
mController.updateState(mockPref);
verify(mockPref).setChecked(true);
}
@Test
public void updateState_listeners() {
mBackend.mPolicy = new NotificationManager.Policy(0, 0, 0, 2);
mController.updateState(mockPref);
verify(mockPref).setOnGearClickListener(any());
verify(mockPref).setOnRadioButtonClickListener(any());
}
@Test
public void select() {
int interruptiveSuppressed = SUPPRESSED_EFFECT_FULL_SCREEN_INTENT
| SUPPRESSED_EFFECT_AMBIENT
| SUPPRESSED_EFFECT_LIGHTS
| SUPPRESSED_EFFECT_PEEK;
mBackend.mPolicy = new NotificationManager.Policy(0, 0, 0, 1);
mController.select();
verify(mBackend).savePolicy(anyInt(), anyInt(), anyInt(), eq(interruptiveSuppressed));
verify(mFeatureFactory.metricsFeatureProvider).action(eq(mContext),
eq(ACTION_ZEN_CUSTOM),
eq(true));
}
}

View File

@@ -0,0 +1,132 @@
/*
* Copyright (C) 2018 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;
import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_AMBIENT;
import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_BADGE;
import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_FULL_SCREEN_INTENT;
import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_LIGHTS;
import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_NOTIFICATION_LIST;
import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK;
import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_OFF;
import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_ON;
import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_STATUS_BAR;
import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.ACTION_ZEN_SOUND_ONLY;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.nullable;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.NotificationManager;
import android.content.Context;
import androidx.preference.PreferenceScreen;
import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settings.widget.DisabledCheckBoxPreference;
import com.android.settings.widget.RadioButtonPreference;
import com.android.settingslib.core.lifecycle.Lifecycle;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.shadows.ShadowApplication;
import org.robolectric.util.ReflectionHelpers;
@RunWith(SettingsRobolectricTestRunner.class)
public class ZenModeVisEffectsNonePreferenceControllerTest {
private ZenModeVisEffectsNonePreferenceController mController;
@Mock
private ZenModeBackend mBackend;
@Mock
private ZenCustomRadioButtonPreference mockPref;
private Context mContext;
private FakeFeatureFactory mFeatureFactory;
@Mock
private PreferenceScreen mScreen;
@Mock NotificationManager mNotificationManager;
private static final String PREF_KEY = "main_pref";
private static final int PREF_METRICS = 1;
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
ShadowApplication shadowApplication = ShadowApplication.getInstance();
mContext = shadowApplication.getApplicationContext();
mFeatureFactory = FakeFeatureFactory.setupForTest();
shadowApplication.setSystemService(Context.NOTIFICATION_SERVICE, mNotificationManager);
when(mNotificationManager.getNotificationPolicy()).thenReturn(
mock(NotificationManager.Policy.class));
mController = new ZenModeVisEffectsNonePreferenceController(
mContext, mock(Lifecycle.class), PREF_KEY);
ReflectionHelpers.setField(mController, "mBackend", mBackend);
when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(mockPref);
mController.displayPreference(mScreen);
}
@Test
public void isAvailable() {
assertTrue(mController.isAvailable());
}
@Test
public void updateState_notChecked() {
mBackend.mPolicy = new NotificationManager.Policy(0, 0, 0, 1);
mController.updateState(mockPref);
verify(mockPref).setChecked(false);
}
@Test
public void updateState_checked() {
mBackend.mPolicy = new NotificationManager.Policy(0, 0, 0, 0);
mController.updateState(mockPref);
verify(mockPref).setChecked(true);
}
@Test
public void onRadioButtonClick() {
int allSuppressed = SUPPRESSED_EFFECT_SCREEN_OFF
| SUPPRESSED_EFFECT_SCREEN_ON
| SUPPRESSED_EFFECT_FULL_SCREEN_INTENT
| SUPPRESSED_EFFECT_AMBIENT
| SUPPRESSED_EFFECT_STATUS_BAR
| SUPPRESSED_EFFECT_BADGE
| SUPPRESSED_EFFECT_LIGHTS
| SUPPRESSED_EFFECT_PEEK
| SUPPRESSED_EFFECT_NOTIFICATION_LIST;
mBackend.mPolicy = new NotificationManager.Policy(0, 0, 0, 1);
mController.onRadioButtonClick(mockPref);
verify(mBackend).saveVisualEffectsPolicy(allSuppressed, false);
verify(mFeatureFactory.metricsFeatureProvider).action(nullable(Context.class),
eq(ACTION_ZEN_SOUND_ONLY),
eq(true));
}
}