Updates to automatic rule pages in Settings

- Re-added metrics for zen behavior preference controllers
- Dialogs in zen mode settings are rotate-friendly
- Automatic rules are refreshed on update state
- User-created (and default) automatic rules are always priority only and user cannot change this
- Automatic rules redesigned to have headers

Test: make ROBOTEST_FILTER=ZenModeAutomaticRulesPreferenceControllerTest RunSettingsRoboTests -j40
Bug: 63077372
Fixes: 68324465
Fixes: 69057696
Change-Id: I163acef2715dd4e60bfc08207f0e22352c4c0e28
This commit is contained in:
Beverly
2017-11-20 17:33:01 -05:00
parent 91fff3093d
commit 323522171d
25 changed files with 829 additions and 405 deletions

View File

@@ -6741,6 +6741,9 @@
<!-- Do not disturb: Title for the zen mode automatic rules page in settings. [CHAR LIMIT=30] -->
<string name="zen_mode_automation_settings_page_title">Automatic rules</string>
<!-- Do not disturb: Title for a specific zen mode automatic rule in settings. [CHAR LIMIT=30] -->
<string name="zen_mode_automatic_rule_settings_page_title">Automatic rule</string>
<!-- Do not disturb: Title for the zen mode automation option Suggestion. [CHAR LIMIT=50] -->
<string name="zen_mode_automation_suggestion_title">Set Do Not Disturb rules</string>

View File

@@ -15,8 +15,18 @@
limitations under the License.
-->
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
android:key="zen_mode_event_rule_settings" >
<PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android"
android:key="zen_mode_event_rule_settings"
android:title="@string/zen_mode_automatic_rule_settings_page_title">
<com.android.settings.applications.LayoutPreference
android:key="pref_app_header"
android:layout="@layout/settings_entity_header" />
<com.android.settings.applications.LayoutPreference
android:key="zen_automatic_rule_switch"
android:layout="@layout/styled_switch_bar" />
<!-- Rule name -->
<Preference
@@ -36,10 +46,4 @@
android:title="@string/zen_mode_event_rule_reply"
android:summary="%s" />
<!-- Zen mode -->
<DropDownPreference
android:key="zen_mode"
android:title="@string/zen_mode_settings_title"
android:summary="%s" />
</PreferenceScreen>

View File

@@ -15,8 +15,18 @@
limitations under the License.
-->
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
android:key="zen_mode_schedule_rule_settings" >
<PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android"
android:key="zen_mode_schedule_rule_settings"
android:title="@string/zen_mode_automatic_rule_settings_page_title">
<com.android.settings.applications.LayoutPreference
android:key="pref_app_header"
android:layout="@layout/settings_entity_header" />
<com.android.settings.applications.LayoutPreference
android:key="zen_automatic_rule_switch"
android:layout="@layout/styled_switch_bar" />
<!-- Rule name -->
<Preference
@@ -39,11 +49,4 @@
android:summary="@string/zen_mode_schedule_alarm_summary"
android:order="99" />
<!-- Zen mode -->
<DropDownPreference
android:key="zen_mode"
android:title="@string/zen_mode_settings_title"
android:order="100"
android:summary="%s" />
</PreferenceScreen>

View File

@@ -29,8 +29,9 @@ import android.service.notification.ConditionProviderService;
import android.service.notification.ZenModeConfig;
import android.support.v7.preference.Preference;
import com.android.internal.logging.nano.MetricsProto;
import com.android.settings.core.PreferenceControllerMixin;
import com.android.settingslib.core.AbstractPreferenceController;
import com.android.settingslib.core.lifecycle.Lifecycle;
import java.util.Arrays;
import java.util.Comparator;
@@ -38,19 +39,19 @@ import java.util.Map;
import java.util.Set;
abstract public class AbstractZenModeAutomaticRulePreferenceController extends
AbstractPreferenceController implements PreferenceControllerMixin {
AbstractZenModePreferenceController implements PreferenceControllerMixin {
private static final String TAG = "ZenModeAutomaticRule";
protected ZenModeBackend mBackend;
protected Fragment mParent;
protected Set<Map.Entry<String, AutomaticZenRule>> mRules;
protected PackageManager mPm;
public AbstractZenModeAutomaticRulePreferenceController(Context context, Fragment parent) {
super(context);
public AbstractZenModeAutomaticRulePreferenceController(Context context, String key, Fragment
parent, Lifecycle lifecycle) {
super(context, key, lifecycle);
mBackend = ZenModeBackend.getInstance(context);
mParent = parent;
mPm = mContext.getPackageManager();
mParent = parent;
}
@Override
@@ -65,19 +66,9 @@ abstract public class AbstractZenModeAutomaticRulePreferenceController extends
return ruleMap.entrySet();
}
protected void showNameRuleDialog(final ZenRuleInfo ri) {
new ZenRuleNameDialog(mContext, null, ri.defaultConditionId) {
@Override
public void onOk(String ruleName) {
AutomaticZenRule rule = new AutomaticZenRule(ruleName, ri.serviceComponent,
ri.defaultConditionId, NotificationManager.INTERRUPTION_FILTER_PRIORITY,
true);
String savedRuleId = mBackend.addZenRule(rule);
if (savedRuleId != null) {
mParent.startActivity(getRuleIntent(ri.settingsAction, null, savedRuleId));
}
}
}.show();
protected void showNameRuleDialog(final ZenRuleInfo ri, Fragment parent) {
ZenRuleNameDialog.show(parent, null, ri.defaultConditionId, new
RuleNameChangeListener(ri));
}
protected Map.Entry<String, AutomaticZenRule>[] sortedRules() {
@@ -157,4 +148,26 @@ abstract public class AbstractZenModeAutomaticRulePreferenceController extends
}
return null;
}
public class RuleNameChangeListener implements ZenRuleNameDialog.PositiveClickListener {
ZenRuleInfo mRuleInfo;
public RuleNameChangeListener(ZenRuleInfo ruleInfo) {
mRuleInfo = ruleInfo;
}
@Override
public void onOk(String ruleName, Fragment parent) {
mMetricsFeatureProvider.action(mContext,
MetricsProto.MetricsEvent.ACTION_ZEN_MODE_RULE_NAME_CHANGE_OK);
AutomaticZenRule rule = new AutomaticZenRule(ruleName, mRuleInfo.serviceComponent,
mRuleInfo.defaultConditionId,
NotificationManager.INTERRUPTION_FILTER_PRIORITY, true);
String savedRuleId = mBackend.addZenRule(rule);
if (savedRuleId != null) {
parent.startActivity(getRuleIntent(mRuleInfo.settingsAction, null,
savedRuleId));
}
}
}
}

View File

@@ -35,6 +35,8 @@ import android.util.Slog;
import com.android.internal.annotations.VisibleForTesting;
import com.android.settings.core.PreferenceControllerMixin;
import com.android.settings.core.instrumentation.MetricsFeatureProvider;
import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.core.AbstractPreferenceController;
import com.android.settingslib.core.lifecycle.Lifecycle;
import com.android.settingslib.core.lifecycle.LifecycleObserver;
@@ -51,6 +53,7 @@ abstract public class AbstractZenModePreferenceController extends
private final String KEY;
final private NotificationManager mNotificationManager;
protected static ZenModeConfigWrapper mZenModeConfigWrapper;
protected MetricsFeatureProvider mMetricsFeatureProvider;
public AbstractZenModePreferenceController(Context context, String key,
Lifecycle lifecycle) {
@@ -62,6 +65,9 @@ abstract public class AbstractZenModePreferenceController extends
KEY = key;
mNotificationManager = (NotificationManager) context.getSystemService(
Context.NOTIFICATION_SERVICE);
final FeatureFactory featureFactory = FeatureFactory.getFactory(mContext);
mMetricsFeatureProvider = featureFactory.getMetricsFeatureProvider();
}
@Override

View File

@@ -0,0 +1,104 @@
/*
* Copyright (C) 2017 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.settings.widget.EntityHeaderController.PREF_KEY_APP_HEADER;
import android.app.AutomaticZenRule;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.graphics.drawable.Drawable;
import android.support.v14.preference.PreferenceFragment;
import android.support.v7.preference.Preference;
import android.util.Slog;
import android.view.View;
import com.android.settings.R;
import com.android.settings.applications.LayoutPreference;
import com.android.settings.core.PreferenceControllerMixin;
import com.android.settings.widget.EntityHeaderController;
import com.android.settingslib.core.lifecycle.Lifecycle;
public class ZenAutomaticRuleHeaderPreferenceController extends AbstractZenModePreferenceController
implements PreferenceControllerMixin {
private final String KEY = PREF_KEY_APP_HEADER;
private final PreferenceFragment mFragment;
private AutomaticZenRule mRule;
private EntityHeaderController mController;
public ZenAutomaticRuleHeaderPreferenceController(Context context, PreferenceFragment fragment,
Lifecycle lifecycle) {
super(context, PREF_KEY_APP_HEADER, lifecycle);
mFragment = fragment;
}
@Override
public String getPreferenceKey() {
return KEY;
}
@Override
public boolean isAvailable() {
return mRule != null;
}
public void updateState(Preference preference) {
if (mRule == null) {
return;
}
if (mFragment != null) {
LayoutPreference pref = (LayoutPreference) preference;
if (mController == null) {
mController = EntityHeaderController
.newInstance(mFragment.getActivity(), mFragment,
pref.findViewById(R.id.entity_header));
}
pref = mController.setIcon(getIcon())
.setLabel(mRule.getName())
.setPackageName(mRule.getOwner().getPackageName())
.setUid(mContext.getUserId())
.setHasAppInfoLink(false)
.setButtonActions(EntityHeaderController.ActionType.ACTION_NONE,
EntityHeaderController.ActionType.ACTION_NONE)
.done(mFragment.getActivity(), mContext);
pref.findViewById(R.id.entity_header).setVisibility(View.VISIBLE);
}
}
private Drawable getIcon() {
try {
PackageManager packageManager = mContext.getPackageManager();
ApplicationInfo info = packageManager.getApplicationInfo(
mRule.getOwner().getPackageName(), 0);
return info.loadIcon(packageManager);
} catch (PackageManager.NameNotFoundException e) {
Slog.w(TAG, "Unable to load icon - PackageManager.NameNotFoundException");
}
return null;
}
protected void onResume(AutomaticZenRule rule) {
mRule = rule;
}
}

View File

@@ -0,0 +1,97 @@
/*
* Copyright (C) 2017 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.AutomaticZenRule;
import android.app.Fragment;
import android.content.Context;
import android.support.v7.preference.Preference;
import android.widget.Switch;
import android.widget.Toast;
import com.android.settings.R;
import com.android.settings.applications.LayoutPreference;
import com.android.settings.widget.SwitchBar;
import com.android.settingslib.core.lifecycle.Lifecycle;
public class ZenAutomaticRuleSwitchPreferenceController extends
AbstractZenModeAutomaticRulePreferenceController implements
SwitchBar.OnSwitchChangeListener {
private static final String KEY = "zen_automatic_rule_switch";
private AutomaticZenRule mRule;
private String mId;
private Toast mEnabledToast;
private int mToastTextResource;
public ZenAutomaticRuleSwitchPreferenceController(Context context, Fragment parent,
int toastTextResource, Lifecycle lifecycle) {
super(context, KEY, parent, lifecycle);
mToastTextResource = toastTextResource;
}
@Override
public String getPreferenceKey() {
return KEY;
}
@Override
public boolean isAvailable() {
return mRule != null && mId != null;
}
public void onResume(AutomaticZenRule rule, String id) {
mRule = rule;
mId = id;
}
public void updateState(Preference preference) {
LayoutPreference pref = (LayoutPreference) preference;
SwitchBar bar = pref.findViewById(R.id.switch_bar);
if (mRule != null) {
bar.setChecked(mRule.isEnabled());
}
if (bar != null) {
bar.show();
try {
bar.addOnSwitchChangeListener(this);
} catch (IllegalStateException e) {
// an exception is thrown if you try to add the listener twice
}
}
bar.show();
}
@Override
public void onSwitchChanged(Switch switchView, boolean isChecked) {
final boolean enabled = isChecked;
if (enabled == mRule.isEnabled()) return;
mRule.setEnabled(enabled);
mBackend.setZenRule(mId, mRule);
if (enabled) {
final int toastText = mToastTextResource;
if (toastText != 0) {
mEnabledToast = Toast.makeText(mContext, toastText, Toast.LENGTH_SHORT);
mEnabledToast.show();
}
} else {
if (mEnabledToast != null) {
mEnabledToast.cancel();
}
}
}
}

View File

@@ -0,0 +1,86 @@
/*
* Copyright (c) 2017 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.AlertDialog;
import android.app.Dialog;
import android.app.Fragment;
import android.content.DialogInterface;
import android.os.Bundle;
import android.view.View;
import com.android.internal.logging.nano.MetricsProto;
import com.android.settings.R;
import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
public class ZenDeleteRuleDialog extends InstrumentedDialogFragment {
protected static final String TAG = "ZenDeleteRuleDialog";
private static final String EXTRA_ZEN_RULE_NAME = "zen_rule_name";
private static final String EXTRA_ZEN_RULE_ID = "zen_rule_id";
protected static PositiveClickListener mPositiveClickListener;
/**
* The interface we expect a listener to implement.
*/
public interface PositiveClickListener {
void onOk(String id);
}
public static void show(Fragment parent, String ruleName, String id, PositiveClickListener
listener) {
final Bundle args = new Bundle();
args.putString(EXTRA_ZEN_RULE_NAME, ruleName);
args.putString(EXTRA_ZEN_RULE_ID, id);
mPositiveClickListener = listener;
ZenDeleteRuleDialog dialog = new ZenDeleteRuleDialog();
dialog.setArguments(args);
dialog.setTargetFragment(parent, 0);
dialog.show(parent.getFragmentManager(), TAG);
}
@Override
public int getMetricsCategory() {
return MetricsProto.MetricsEvent.NOTIFICATION_ZEN_MODE_DELETE_RULE_DIALOG;
}
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
Bundle arguments = getArguments();
String ruleName = arguments.getString(EXTRA_ZEN_RULE_NAME);
String id = arguments.getString(EXTRA_ZEN_RULE_ID);
final AlertDialog dialog = new AlertDialog.Builder(getContext())
.setMessage(getString(R.string.zen_mode_delete_rule_confirmation, ruleName))
.setNegativeButton(R.string.cancel, null)
.setPositiveButton(R.string.zen_mode_delete_rule_button,
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
if (arguments != null) {
mPositiveClickListener.onOk(id);
}
}
}).create();
final View messageView = dialog.findViewById(android.R.id.message);
if (messageView != null) {
messageView.setTextDirection(View.TEXT_DIRECTION_LOCALE);
}
return dialog;
}
}

View File

@@ -21,6 +21,7 @@ import android.content.Context;
import android.content.Intent;
import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceScreen;
import com.android.settingslib.core.lifecycle.Lifecycle;
import com.android.settings.utils.ZenServiceListing;
@@ -28,19 +29,18 @@ public class ZenModeAddAutomaticRulePreferenceController extends
AbstractZenModeAutomaticRulePreferenceController implements
Preference.OnPreferenceClickListener {
private final String KEY_ADD_RULE;
protected static final String KEY = "zen_mode_add_automatic_rule";
private final ZenServiceListing mZenServiceListing;
public ZenModeAddAutomaticRulePreferenceController(Context context, String key,
Fragment parent, ZenServiceListing serviceListing) {
super(context, parent);
KEY_ADD_RULE = key;
public ZenModeAddAutomaticRulePreferenceController(Context context, Fragment parent,
ZenServiceListing serviceListing, Lifecycle lifecycle) {
super(context, KEY, parent, lifecycle);
mZenServiceListing = serviceListing;
}
@Override
public String getPreferenceKey() {
return KEY_ADD_RULE;
return KEY;
}
@Override
@@ -51,25 +51,30 @@ public class ZenModeAddAutomaticRulePreferenceController extends
@Override
public void displayPreference(PreferenceScreen screen) {
super.displayPreference(screen);
Preference pref = screen.findPreference(KEY_ADD_RULE);
Preference pref = screen.findPreference(KEY);
pref.setPersistent(false);
pref.setOnPreferenceClickListener(this);
}
@Override
public boolean onPreferenceClick(Preference preference) {
new ZenRuleSelectionDialog(mContext, mZenServiceListing) {
@Override
public void onSystemRuleSelected(ZenRuleInfo ri) {
showNameRuleDialog(ri);
}
@Override
public void onExternalRuleSelected(ZenRuleInfo ri) {
Intent intent = new Intent().setComponent(ri.configurationActivity);
mParent.startActivity(intent);
}
}.show();
ZenRuleSelectionDialog.show(mContext, mParent, new RuleSelectionListener(),
mZenServiceListing);
return true;
}
public class RuleSelectionListener implements ZenRuleSelectionDialog.PositiveClickListener {
public RuleSelectionListener() {}
@Override
public void onSystemRuleSelected(ZenRuleInfo ri, Fragment parent) {
showNameRuleDialog(ri, parent);
}
@Override
public void onExternalRuleSelected(ZenRuleInfo ri, Fragment parent) {
Intent intent = new Intent().setComponent(ri.configurationActivity);
parent.startActivity(intent);
}
}
}

View File

@@ -23,6 +23,7 @@ import android.support.v14.preference.SwitchPreference;
import android.support.v7.preference.Preference;
import android.util.Log;
import com.android.internal.logging.nano.MetricsProto;
import com.android.settingslib.core.lifecycle.Lifecycle;
public class ZenModeAlarmsPreferenceController extends
@@ -73,6 +74,9 @@ public class ZenModeAlarmsPreferenceController extends
if (ZenModeSettingsBase.DEBUG) {
Log.d(TAG, "onPrefChange allowAlarms=" + allowAlarms);
}
mMetricsFeatureProvider.action(mContext, MetricsProto.MetricsEvent.ACTION_ZEN_ALLOW_ALARMS,
allowAlarms);
mBackend.saveSoundPolicy(Policy.PRIORITY_CATEGORY_ALARMS, allowAlarms);
return true;
}

View File

@@ -19,28 +19,31 @@ package com.android.settings.notification;
import android.app.AutomaticZenRule;
import android.app.Fragment;
import android.content.Context;
import android.support.annotation.VisibleForTesting;
import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceCategory;
import android.support.v7.preference.PreferenceScreen;
import com.android.settingslib.core.lifecycle.Lifecycle;
import java.util.Map;
public class ZenModeAutomaticRulesPreferenceController extends
AbstractZenModeAutomaticRulePreferenceController {
private final String KEY_AUTOMATIC_RULES;
private PreferenceCategory mPreferenceCategory;
Map.Entry<String, AutomaticZenRule>[] mSortedRules;
protected static final String KEY = "zen_mode_automatic_rules";
public ZenModeAutomaticRulesPreferenceController(Context context, String key,
Fragment parent) {
super(context, parent);
KEY_AUTOMATIC_RULES = key;
mSortedRules = sortedRules();
@VisibleForTesting
protected PreferenceCategory mPreferenceCategory;
public ZenModeAutomaticRulesPreferenceController(Context context, Fragment parent, Lifecycle
lifecycle) {
super(context, KEY, parent, lifecycle);
}
@Override
public String getPreferenceKey() {
return KEY_AUTOMATIC_RULES;
return KEY;
}
@Override
@@ -59,40 +62,14 @@ public class ZenModeAutomaticRulesPreferenceController extends
public void updateState(Preference preference) {
super.updateState(preference);
// no need to update AutomaticRule if a rule was deleted
// (on rule deletion, the preference removes itself from its parent)
int oldRuleLength = mSortedRules.length;
mSortedRules = sortedRules();
if (!wasRuleDeleted(oldRuleLength)) {
updateAutomaticRules();
mPreferenceCategory.removeAll();
Map.Entry<String, AutomaticZenRule>[] sortedRules = sortedRules();
for (Map.Entry<String, AutomaticZenRule> sortedRule : sortedRules) {
ZenRulePreference pref = new ZenRulePreference(mPreferenceCategory.getContext(),
sortedRule, mParent, mMetricsFeatureProvider);
mPreferenceCategory.addPreference(pref);
}
}
private boolean wasRuleDeleted(int oldRuleLength) {
int newRuleLength = mSortedRules.length;
int prefCount = mPreferenceCategory.getPreferenceCount();
return (prefCount == oldRuleLength -1) && (prefCount == newRuleLength);
}
private void updateAutomaticRules() {
for (Map.Entry<String, AutomaticZenRule> sortedRule : mSortedRules) {
ZenRulePreference currPref = (ZenRulePreference)
mPreferenceCategory.findPreference(sortedRule.getKey());
if (currPref != null && currPref.appExists) {
// rule already exists in preferences, update it
currPref.setAttributes(sortedRule.getValue());
} else {
// rule doesn't exist in preferences, add it
ZenRulePreference pref = new ZenRulePreference(mPreferenceCategory.getContext(),
sortedRule, mPreferenceCategory);
if (pref.appExists) {
mPreferenceCategory.addPreference(pref);
}
}
}
}
}

View File

@@ -28,29 +28,27 @@ import com.android.settings.search.Indexable;
import com.android.settings.utils.ManagedServiceSettings;
import com.android.settings.utils.ZenServiceListing;
import com.android.settingslib.core.AbstractPreferenceController;
import com.android.settingslib.core.lifecycle.Lifecycle;
import java.util.ArrayList;
import java.util.List;
public class ZenModeAutomationSettings extends ZenModeSettingsBase {
private static final String KEY_ADD_RULE = "zen_mode_add_automatic_rule";
private static final String KEY_AUTOMATIC_RULES = "zen_mode_automatic_rules";
protected static final ManagedServiceSettings.Config CONFIG = getConditionProviderConfig();
protected final ManagedServiceSettings.Config CONFIG = getConditionProviderConfig();
@Override
protected List<AbstractPreferenceController> getPreferenceControllers(Context context) {
ZenServiceListing serviceListing = new ZenServiceListing(getContext(), CONFIG);
serviceListing.reloadApprovedServices();
return buildPreferenceControllers(context, this, serviceListing);
return buildPreferenceControllers(context, this, serviceListing, getLifecycle());
}
private static List<AbstractPreferenceController> buildPreferenceControllers(Context context,
Fragment parent, ZenServiceListing serviceListing) {
Fragment parent, ZenServiceListing serviceListing, Lifecycle lifecycle) {
List<AbstractPreferenceController> controllers = new ArrayList<>();
controllers.add(new ZenModeAddAutomaticRulePreferenceController(context, KEY_ADD_RULE,
parent, serviceListing));
controllers.add(new ZenModeAutomaticRulesPreferenceController(context,
KEY_AUTOMATIC_RULES, parent));
controllers.add(new ZenModeAddAutomaticRulePreferenceController(context, parent,
serviceListing, lifecycle));
controllers.add(new ZenModeAutomaticRulesPreferenceController(context, parent, lifecycle));
return controllers;
}
@@ -94,15 +92,15 @@ public class ZenModeAutomationSettings extends ZenModeSettingsBase {
@Override
public List<String> getNonIndexableKeys(Context context) {
final List<String> keys = super.getNonIndexableKeys(context);
keys.add(KEY_ADD_RULE);
keys.add(KEY_AUTOMATIC_RULES);
keys.add(ZenModeAddAutomaticRulePreferenceController.KEY);
keys.add(ZenModeAutomaticRulesPreferenceController.KEY);
return keys;
}
@Override
public List<AbstractPreferenceController> getPreferenceControllers(
Context context) {
return buildPreferenceControllers(context, null, null);
return buildPreferenceControllers(context, null, null, null);
}
};
}

View File

@@ -22,6 +22,7 @@ import android.support.v7.preference.Preference;
import android.view.View;
import android.widget.Button;
import com.android.internal.logging.nano.MetricsProto;
import com.android.settings.R;
import com.android.settings.applications.LayoutPreference;
import com.android.settings.core.PreferenceControllerMixin;
@@ -57,15 +58,21 @@ public class ZenModeButtonPreferenceController extends AbstractZenModePreference
if (null == mZenButtonOn) {
mZenButtonOn = (Button) ((LayoutPreference) preference)
.findViewById(R.id.zen_mode_settings_turn_on_button);
mZenButtonOn.setOnClickListener(v ->
mBackend.setZenMode(Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS));
mZenButtonOn.setOnClickListener(v -> {
mMetricsFeatureProvider.action(mContext,
MetricsProto.MetricsEvent.ACTION_ZEN_TOGGLE_DND_BUTTON, true);
mBackend.setZenMode(Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS);
});
}
if (null == mZenButtonOff) {
mZenButtonOff = (Button) ((LayoutPreference) preference)
.findViewById(R.id.zen_mode_settings_turn_off_button);
mZenButtonOff.setOnClickListener(v ->
mBackend.setZenMode(Settings.Global.ZEN_MODE_OFF));
mZenButtonOff.setOnClickListener(v -> {
mMetricsFeatureProvider.action(mContext,
MetricsProto.MetricsEvent.ACTION_ZEN_TOGGLE_DND_BUTTON, false);
mBackend.setZenMode(Settings.Global.ZEN_MODE_OFF);
});
}
updateButtons();

View File

@@ -60,16 +60,6 @@ public class ZenModeEventRuleSettings extends ZenModeRuleSettingsBase {
return mEvent != null;
}
@Override
protected String getZenModeDependency() {
return null;
}
@Override
protected int getEnabledToastText() {
return R.string.zen_event_rule_enabled_toast;
}
@Override
public void onResume() {
super.onResume();
@@ -89,7 +79,14 @@ public class ZenModeEventRuleSettings extends ZenModeRuleSettingsBase {
@Override
protected List<AbstractPreferenceController> getPreferenceControllers(Context context) {
return null;
List<AbstractPreferenceController> controllers = new ArrayList<>();
mHeader = new ZenAutomaticRuleHeaderPreferenceController(context, this,
getLifecycle());
mSwitch = new ZenAutomaticRuleSwitchPreferenceController(context, this,
R.string.zen_event_rule_enabled_toast, getLifecycle());
controllers.add(mHeader);
controllers.add(mSwitch);
return controllers;
}
private void reloadCalendar() {

View File

@@ -24,6 +24,7 @@ import android.support.v7.preference.Preference;
import android.util.Log;
import com.android.internal.logging.nano.MetricsProto;
import com.android.settingslib.core.lifecycle.Lifecycle;
public class ZenModeEventsPreferenceController extends AbstractZenModePreferenceController
@@ -71,6 +72,8 @@ public class ZenModeEventsPreferenceController extends AbstractZenModePreference
if (ZenModeSettingsBase.DEBUG) {
Log.d(TAG, "onPrefChange allowEvents=" + allowEvents);
}
mMetricsFeatureProvider.action(mContext, MetricsProto.MetricsEvent.ACTION_ZEN_ALLOW_EVENTS,
allowEvents);
mBackend.saveSoundPolicy(Policy.PRIORITY_CATEGORY_EVENTS, allowEvents);
return true;
}

View File

@@ -23,6 +23,7 @@ import android.support.v14.preference.SwitchPreference;
import android.support.v7.preference.Preference;
import android.util.Log;
import com.android.internal.logging.nano.MetricsProto;
import com.android.settingslib.core.lifecycle.Lifecycle;
public class ZenModeRemindersPreferenceController extends AbstractZenModePreferenceController
@@ -67,7 +68,11 @@ public class ZenModeRemindersPreferenceController extends AbstractZenModePrefere
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
final boolean allowReminders = (Boolean) newValue;
if (ZenModeSettingsBase.DEBUG) Log.d(TAG, "onPrefChange allowReminders=" + allowReminders);
if (ZenModeSettingsBase.DEBUG) {
Log.d(TAG, "onPrefChange allowReminders=" + allowReminders);
}
mMetricsFeatureProvider.action(mContext,
MetricsProto.MetricsEvent.ACTION_ZEN_ALLOW_REMINDERS, allowReminders);
mBackend.saveSoundPolicy(NotificationManager.Policy.PRIORITY_CATEGORY_REMINDERS,
allowReminders);
return true;

View File

@@ -23,6 +23,7 @@ import android.support.v14.preference.SwitchPreference;
import android.support.v7.preference.Preference;
import android.util.Log;
import com.android.internal.logging.nano.MetricsProto;
import com.android.settingslib.core.lifecycle.Lifecycle;
public class ZenModeRepeatCallersPreferenceController extends AbstractZenModePreferenceController
@@ -77,8 +78,11 @@ public class ZenModeRepeatCallersPreferenceController extends AbstractZenModePre
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
final boolean allowRepeatCallers = (Boolean) newValue;
if (ZenModeSettingsBase.DEBUG) Log.d(TAG, "onPrefChange allowRepeatCallers="
+ allowRepeatCallers);
if (ZenModeSettingsBase.DEBUG) {
Log.d(TAG, "onPrefChange allowRepeatCallers=" + allowRepeatCallers);
}
mMetricsFeatureProvider.action(mContext,
MetricsProto.MetricsEvent.ACTION_ZEN_ALLOW_REPEAT_CALLS, allowRepeatCallers);
mBackend.saveSoundPolicy(Policy.PRIORITY_CATEGORY_REPEAT_CALLERS, allowRepeatCallers);
return true;
}

View File

@@ -16,62 +16,43 @@
package com.android.settings.notification;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.AutomaticZenRule;
import android.app.Fragment;
import android.app.NotificationManager;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.service.notification.ConditionProviderService;
import android.support.v7.preference.DropDownPreference;
import android.support.v7.preference.Preference;
import android.support.v7.preference.Preference.OnPreferenceChangeListener;
import android.support.v7.preference.Preference.OnPreferenceClickListener;
import android.support.v7.preference.PreferenceScreen;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.Switch;
import android.widget.Toast;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.logging.nano.MetricsProto;
import com.android.settings.R;
import com.android.settings.SettingsActivity;
import com.android.settings.widget.SwitchBar;
import com.android.settingslib.core.AbstractPreferenceController;
import java.util.List;
public abstract class ZenModeRuleSettingsBase extends ZenModeSettingsBase {
public abstract class ZenModeRuleSettingsBase extends ZenModeSettingsBase
implements SwitchBar.OnSwitchChangeListener {
protected static final String TAG = ZenModeSettingsBase.TAG;
protected static final boolean DEBUG = ZenModeSettingsBase.DEBUG;
private static final String KEY_RULE_NAME = "rule_name";
private static final String KEY_ZEN_MODE = "zen_mode";
protected Context mContext;
protected boolean mDisableListeners;
protected AutomaticZenRule mRule;
protected String mId;
private boolean mDeleting;
private Preference mRuleName;
private SwitchBar mSwitchBar;
private DropDownPreference mZenMode;
private Toast mEnabledToast;
protected ZenAutomaticRuleHeaderPreferenceController mHeader;
protected ZenAutomaticRuleSwitchPreferenceController mSwitch;
abstract protected void onCreateInternal();
abstract protected boolean setRule(AutomaticZenRule rule);
abstract protected String getZenModeDependency();
abstract protected void updateControlsInternal();
abstract protected int getEnabledToastText();
@Override
public void onCreate(Bundle icicle) {
@@ -99,8 +80,6 @@ public abstract class ZenModeRuleSettingsBase extends ZenModeSettingsBase
super.onCreate(icicle);
setHasOptionsMenu(true);
onCreateInternal();
final PreferenceScreen root = getPreferenceScreen();
@@ -112,37 +91,6 @@ public abstract class ZenModeRuleSettingsBase extends ZenModeSettingsBase
return true;
}
});
mZenMode = (DropDownPreference) root.findPreference(KEY_ZEN_MODE);
mZenMode.setEntries(new CharSequence[] {
getString(R.string.zen_mode_option_important_interruptions),
getString(R.string.zen_mode_option_alarms),
getString(R.string.zen_mode_option_no_interruptions),
});
mZenMode.setEntryValues(new CharSequence[] {
Integer.toString(NotificationManager.INTERRUPTION_FILTER_PRIORITY),
Integer.toString(NotificationManager.INTERRUPTION_FILTER_ALARMS),
Integer.toString(NotificationManager.INTERRUPTION_FILTER_NONE),
});
mZenMode.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
if (mDisableListeners) return false;
final int zenMode = Integer.parseInt((String) newValue);
if (zenMode == mRule.getInterruptionFilter()) return false;
if (DEBUG) Log.d(TAG, "onPrefChange zenMode=" + zenMode);
mRule.setInterruptionFilter(zenMode);
mBackend.setZenRule(mId, mRule);
return true;
}
});
mZenMode.setOrder(10); // sort at the bottom of the category
mZenMode.setDependency(getZenModeDependency());
}
@Override
protected List<AbstractPreferenceController> getPreferenceControllers(Context context) {
return null;
}
@Override
@@ -155,43 +103,39 @@ public abstract class ZenModeRuleSettingsBase extends ZenModeSettingsBase
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
final SettingsActivity activity = (SettingsActivity) getActivity();
mSwitchBar = activity.getSwitchBar();
mSwitchBar.addOnSwitchChangeListener(this);
mSwitchBar.show();
public int getHelpResource() {
return R.string.help_uri_interruptions;
}
@Override
public void onDestroyView() {
super.onDestroyView();
mSwitchBar.removeOnSwitchChangeListener(this);
mSwitchBar.hide();
/**
* Update state of header preference managed by PreferenceController.
*/
protected void updateHeader() {
final PreferenceScreen screen = getPreferenceScreen();
mSwitch.onResume(mRule,mId);
mSwitch.displayPreference(screen);
updatePreference(mSwitch);
mHeader.onResume(mRule);
mHeader.displayPreference(screen);
updatePreference(mHeader);
}
@Override
public void onSwitchChanged(Switch switchView, boolean isChecked) {
if (DEBUG) Log.d(TAG, "onSwitchChanged " + isChecked);
if (mDisableListeners) return;
final boolean enabled = isChecked;
if (enabled == mRule.isEnabled()) return;
mMetricsFeatureProvider.action(mContext, MetricsEvent.ACTION_ZEN_ENABLE_RULE, enabled);
if (DEBUG) Log.d(TAG, "onSwitchChanged enabled=" + enabled);
mRule.setEnabled(enabled);
mBackend.setZenRule(mId, mRule);
if (enabled) {
final int toastText = getEnabledToastText();
if (toastText != 0) {
mEnabledToast = Toast.makeText(mContext, toastText, Toast.LENGTH_SHORT);
mEnabledToast.show();
}
} else {
if (mEnabledToast != null) {
mEnabledToast.cancel();
}
private void updatePreference(AbstractPreferenceController controller) {
final PreferenceScreen screen = getPreferenceScreen();
if (!controller.isAvailable()) {
return;
}
final String key = controller.getPreferenceKey();
final Preference preference = screen.findPreference(key);
if (preference == null) {
Log.d(TAG, String.format("Cannot find preference with key %s in Controller %s",
key, controller.getClass().getSimpleName()));
return;
}
controller.updateState(preference);
}
protected void updateRule(Uri newConditionId) {
@@ -207,33 +151,6 @@ public abstract class ZenModeRuleSettingsBase extends ZenModeSettingsBase
}
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
if (DEBUG) Log.d(TAG, "onCreateOptionsMenu");
inflater.inflate(R.menu.zen_mode_rule, menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (DEBUG) Log.d(TAG, "onOptionsItemSelected " + item.getItemId());
if (item.getItemId() == R.id.delete) {
mMetricsFeatureProvider.action(mContext, MetricsEvent.ACTION_ZEN_DELETE_RULE);
showDeleteRuleDialog();
return true;
}
return super.onOptionsItemSelected(item);
}
private void showRuleNameDialog() {
new ZenRuleNameDialog(mContext, mRule.getName(), null) {
@Override
public void onOk(String ruleName) {
mRule.setName(ruleName);
mBackend.setZenRule(mId, mRule);
}
}.show();
}
private boolean refreshRuleOrFinish() {
mRule = getZenRule();
if (DEBUG) Log.d(TAG, "mRule=" + mRule);
@@ -244,42 +161,22 @@ public abstract class ZenModeRuleSettingsBase extends ZenModeSettingsBase
return false;
}
private void showDeleteRuleDialog() {
final AlertDialog dialog = new AlertDialog.Builder(mContext)
.setMessage(getString(R.string.zen_mode_delete_rule_confirmation, mRule.getName()))
.setNegativeButton(R.string.cancel, null)
.setPositiveButton(R.string.zen_mode_delete_rule_button, new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
mMetricsFeatureProvider.action(mContext,
MetricsEvent.ACTION_ZEN_DELETE_RULE_OK);
mDeleting = true;
mBackend.removeZenRule(mId);
}
})
.show();
final View messageView = dialog.findViewById(android.R.id.message);
if (messageView != null) {
messageView.setTextDirection(View.TEXT_DIRECTION_LOCALE);
}
private void showRuleNameDialog() {
ZenRuleNameDialog.show(this, mRule.getName(), null, new RuleNameChangeListener());
}
private void toastAndFinish() {
if (!mDeleting) {
Toast.makeText(mContext, R.string.zen_mode_rule_not_found_text, Toast.LENGTH_SHORT)
Toast.makeText(mContext, R.string.zen_mode_rule_not_found_text, Toast.LENGTH_SHORT)
.show();
}
getActivity().finish();
}
private void updateRuleName() {
Activity activity = getActivity();
if (activity != null) {
activity.setTitle(mRule.getName());
if (mRule != null) {
mRuleName.setSummary(mRule.getName());
} else {
if (DEBUG) Log.d(TAG, "updateRuleName - activity title and mRuleName "
+ "not updated; getActivity() returned null");
if (DEBUG) Log.d(TAG, "updateRuleName - mRuleName "
+ "not updated; mRuleName returned null");
}
}
@@ -291,10 +188,19 @@ public abstract class ZenModeRuleSettingsBase extends ZenModeSettingsBase
mDisableListeners = true;
updateRuleName();
updateControlsInternal();
mZenMode.setValue(Integer.toString(mRule.getInterruptionFilter()));
if (mSwitchBar != null) {
mSwitchBar.setChecked(mRule.isEnabled());
}
updateHeader();
mDisableListeners = false;
}
public class RuleNameChangeListener implements ZenRuleNameDialog.PositiveClickListener {
public RuleNameChangeListener() {}
@Override
public void onOk(String ruleName, Fragment parent) {
mMetricsFeatureProvider.action(mContext,
MetricsProto.MetricsEvent.ACTION_ZEN_MODE_RULE_NAME_CHANGE_OK);
mRule.setName(ruleName);
mBackend.setZenRule(mId, mRule);
}
}
}

View File

@@ -42,6 +42,7 @@ import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
import com.android.settingslib.core.AbstractPreferenceController;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.List;
@@ -76,21 +77,6 @@ public class ZenModeScheduleRuleSettings extends ZenModeRuleSettingsBase {
return R.xml.zen_mode_schedule_rule_settings;
}
@Override
protected List<AbstractPreferenceController> getPreferenceControllers(Context context) {
return null;
}
@Override
protected String getZenModeDependency() {
return mDays.getKey();
}
@Override
protected int getEnabledToastText() {
return R.string.zen_schedule_rule_enabled_toast;
}
@Override
protected void onCreateInternal() {
final PreferenceScreen root = getPreferenceScreen();
@@ -208,6 +194,20 @@ public class ZenModeScheduleRuleSettings extends ZenModeRuleSettingsBase {
updateEndSummary();
}
@Override
protected List<AbstractPreferenceController> getPreferenceControllers(Context context) {
List<AbstractPreferenceController> controllers = new ArrayList<>();
mHeader = new ZenAutomaticRuleHeaderPreferenceController(context, this,
getLifecycle());
mSwitch = new ZenAutomaticRuleSwitchPreferenceController(context, this,
R.string.zen_schedule_rule_enabled_toast, getLifecycle());
controllers.add(mHeader);
controllers.add(mSwitch);
return controllers;
}
@Override
public int getMetricsCategory() {
return MetricsEvent.NOTIFICATION_ZEN_MODE_SCHEDULE_RULE;

View File

@@ -22,6 +22,7 @@ import android.support.v14.preference.SwitchPreference;
import android.support.v7.preference.Preference;
import android.util.Log;
import com.android.internal.logging.nano.MetricsProto;
import com.android.settingslib.core.lifecycle.Lifecycle;
public class ZenModeScreenOffPreferenceController extends
@@ -56,8 +57,11 @@ public class ZenModeScreenOffPreferenceController extends
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
final boolean bypass = (Boolean) newValue;
if (ZenModeSettingsBase.DEBUG) Log.d(TAG, "onPrefChange allowWhenScreenOff="
+ !bypass);
if (ZenModeSettingsBase.DEBUG) {
Log.d(TAG, "onPrefChange allowWhenScreenOff=" + bypass);
}
mMetricsFeatureProvider.action(mContext,
MetricsProto.MetricsEvent.ACTION_ZEN_ALLOW_WHEN_SCREEN_OFF, bypass);
mBackend.saveVisualEffectsPolicy(Policy.SUPPRESSED_EFFECT_SCREEN_OFF, bypass);
return true;
}

View File

@@ -22,6 +22,7 @@ import android.support.v14.preference.SwitchPreference;
import android.support.v7.preference.Preference;
import android.util.Log;
import com.android.internal.logging.nano.MetricsProto;
import com.android.settingslib.core.lifecycle.Lifecycle;
public class ZenModeScreenOnPreferenceController extends
@@ -57,8 +58,9 @@ public class ZenModeScreenOnPreferenceController extends
public boolean onPreferenceChange(Preference preference, Object newValue) {
final boolean bypass = (Boolean) newValue;
if (ZenModeSettingsBase.DEBUG) Log.d(TAG, "onPrefChange allowWhenScreenOn="
+ !bypass);
+ bypass);
mMetricsFeatureProvider.action(mContext,
MetricsProto.MetricsEvent.ACTION_ZEN_ALLOW_WHEN_SCREEN_ON, bypass);
mBackend.saveVisualEffectsPolicy(Policy.SUPPRESSED_EFFECT_SCREEN_ON, bypass);
return true;
}

View File

@@ -17,73 +17,103 @@
package com.android.settings.notification;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.Fragment;
import android.content.Context;
import android.content.DialogInterface;
import android.net.Uri;
import android.os.Bundle;
import android.service.notification.ZenModeConfig;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.EditText;
import com.android.internal.logging.nano.MetricsProto;
import com.android.settings.R;
import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
public abstract class ZenRuleNameDialog {
private static final String TAG = "ZenRuleNameDialog";
private static final boolean DEBUG = ZenModeSettings.DEBUG;
public class ZenRuleNameDialog extends InstrumentedDialogFragment {
protected static final String TAG = "ZenRuleNameDialog";
private static final String EXTRA_ZEN_RULE_NAME = "zen_rule_name";
private static final String EXTRA_CONDITION_ID = "extra_zen_condition_id";
protected static PositiveClickListener mPositiveClickListener;
private final AlertDialog mDialog;
private final EditText mEditText;
private final CharSequence mOriginalRuleName;
private final boolean mIsNew;
@Override
public int getMetricsCategory() {
return MetricsProto.MetricsEvent.NOTIFICATION_ZEN_MODE_RULE_NAME_DIALOG;
}
public ZenRuleNameDialog(Context context, CharSequence ruleName, Uri conditionId) {
mIsNew = ruleName == null;
mOriginalRuleName = ruleName;
/**
* The interface we expect a listener to implement.
*/
public interface PositiveClickListener {
void onOk(String newName, Fragment parent);
}
public static void show(Fragment parent, String ruleName, Uri conditionId, PositiveClickListener
listener) {
final Bundle args = new Bundle();
args.putString(EXTRA_ZEN_RULE_NAME, ruleName);
args.putParcelable(EXTRA_CONDITION_ID, conditionId);
mPositiveClickListener = listener;
ZenRuleNameDialog dialog = new ZenRuleNameDialog();
dialog.setArguments(args);
dialog.setTargetFragment(parent, 0);
dialog.show(parent.getFragmentManager(), TAG);
}
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
Bundle arguments = getArguments();
Uri conditionId = arguments.getParcelable(EXTRA_CONDITION_ID);
String ruleName = arguments.getString(EXTRA_ZEN_RULE_NAME);
boolean isNew = ruleName == null;
CharSequence originalRuleName = ruleName;
Context context = getContext();
final View v = LayoutInflater.from(context).inflate(R.layout.zen_rule_name, null,
false);
mEditText = (EditText) v.findViewById(R.id.zen_mode_rule_name);
if (!mIsNew) {
mEditText.setText(ruleName);
EditText editText = (EditText) v.findViewById(R.id.zen_mode_rule_name);
if (!isNew) {
// set text to current rule name
editText.setText(ruleName);
// move cursor to end of text
editText.setSelection(editText.getText().length());
}
mEditText.setSelectAllOnFocus(true);
mDialog = new AlertDialog.Builder(context)
.setTitle(getTitleResource(conditionId))
editText.setSelectAllOnFocus(true);
return new AlertDialog.Builder(context)
.setTitle(getTitleResource(conditionId, isNew))
.setView(v)
.setPositiveButton(mIsNew ? R.string.zen_mode_add : R.string.okay,
.setPositiveButton(isNew ? R.string.zen_mode_add : R.string.okay,
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
final String newName = trimmedText();
if (TextUtils.isEmpty(newName)) {
return;
}
if (!mIsNew && mOriginalRuleName != null
&& mOriginalRuleName.equals(newName)) {
return; // no change to an existing rule, just dismiss
}
onOk(newName);
}
})
@Override
public void onClick(DialogInterface dialog, int which) {
final String newName = trimmedText(editText);
if (TextUtils.isEmpty(newName)) {
return;
}
if (!isNew && originalRuleName != null
&& originalRuleName.equals(newName)) {
return; // no change to an existing rule, just dismiss
}
mPositiveClickListener.onOk(newName, getTargetFragment());
}
})
.setNegativeButton(R.string.cancel, null)
.create();
}
abstract public void onOk(String ruleName);
public void show() {
mDialog.show();
private String trimmedText(EditText editText) {
return editText.getText() == null ? null : editText.getText().toString().trim();
}
private String trimmedText() {
return mEditText.getText() == null ? null : mEditText.getText().toString().trim();
}
private int getTitleResource(Uri conditionId) {
private int getTitleResource(Uri conditionId, boolean isNew) {
final boolean isEvent = ZenModeConfig.isValidEventConditionId(conditionId);
final boolean isTime = ZenModeConfig.isValidScheduleConditionId(conditionId);
int titleResource = R.string.zen_mode_rule_name;
if (mIsNew) {
if (isNew) {
if (isEvent) {
titleResource = R.string.zen_mode_add_event_rule;
} else if (isTime) {

View File

@@ -16,23 +16,21 @@
package com.android.settings.notification;
import android.app.AlertDialog;
import android.app.AutomaticZenRule;
import android.app.NotificationManager;
import android.app.Fragment;
import android.content.ComponentName;
import android.content.Context;
import android.content.DialogInterface;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.ServiceInfo;
import android.content.res.Resources;
import android.service.notification.ZenModeConfig;
import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceCategory;
import android.support.v7.preference.PreferenceViewHolder;
import android.view.View;
import com.android.internal.logging.nano.MetricsProto;
import com.android.settings.R;
import com.android.settings.core.instrumentation.MetricsFeatureProvider;
import com.android.settings.utils.ManagedServiceSettings;
import com.android.settings.utils.ZenServiceListing;
import com.android.settingslib.TwoTargetPreference;
@@ -45,16 +43,17 @@ public class ZenRulePreference extends TwoTargetPreference {
final CharSequence mName;
final String mId;
boolean appExists;
final PreferenceCategory mParent;
final Fragment mParent;
final Preference mPref;
final Context mContext;
final ZenModeBackend mBackend;
final ZenServiceListing mServiceListing;
final PackageManager mPm;
final MetricsFeatureProvider mMetricsFeatureProvider;
public ZenRulePreference(Context context,
final Map.Entry<String, AutomaticZenRule> ruleEntry,
PreferenceCategory prefCategory) {
Fragment parent, MetricsFeatureProvider metricsProvider) {
super(context);
mBackend = ZenModeBackend.getInstance(context);
@@ -62,11 +61,12 @@ public class ZenRulePreference extends TwoTargetPreference {
final AutomaticZenRule rule = ruleEntry.getValue();
mName = rule.getName();
mId = ruleEntry.getKey();
mParent = prefCategory;
mParent = parent;
mPm = mContext.getPackageManager();
mServiceListing = new ZenServiceListing(mContext, CONFIG);
mServiceListing.reloadApprovedServices();
mPref = this;
mMetricsFeatureProvider = metricsProvider;
setAttributes(rule);
}
@@ -89,25 +89,21 @@ public class ZenRulePreference extends TwoTargetPreference {
private final View.OnClickListener mDeleteListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
showDeleteRuleDialog(mId, mName, mParent, mPref);
showDeleteRuleDialog(mParent, mId, mName.toString());
}
};
private void showDeleteRuleDialog(final String ruleId, final CharSequence ruleName,
PreferenceCategory parent, Preference pref) {
new AlertDialog.Builder(mContext)
.setMessage(mContext.getResources().getString(
R.string.zen_mode_delete_rule_confirmation, ruleName))
.setNegativeButton(R.string.cancel, null)
.setPositiveButton(R.string.zen_mode_delete_rule_button,
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
mBackend.removeZenRule(ruleId);
parent.removePreference(pref);
}
})
.show();
private void showDeleteRuleDialog(final Fragment parent, final String ruleId,
final String ruleName) {
ZenDeleteRuleDialog.show(parent, ruleName, ruleId,
new ZenDeleteRuleDialog.PositiveClickListener() {
@Override
public void onOk(String id) {
mMetricsFeatureProvider.action(mContext,
MetricsProto.MetricsEvent.ACTION_ZEN_DELETE_RULE_OK);
mBackend.removeZenRule(id);
}
});
}
protected void setAttributes(AutomaticZenRule rule) {
@@ -141,26 +137,8 @@ public class ZenRulePreference extends TwoTargetPreference {
private String computeRuleSummary(AutomaticZenRule rule, boolean isSystemRule,
CharSequence providerLabel) {
final String mode = computeZenModeCaption(mContext.getResources(),
rule.getInterruptionFilter());
final String ruleState = (rule == null || !rule.isEnabled())
return (rule == null || !rule.isEnabled())
? mContext.getResources().getString(R.string.switch_off_text)
: mContext.getResources().getString(
R.string.zen_mode_rule_summary_enabled_combination, mode);
return ruleState;
}
private static String computeZenModeCaption(Resources res, int zenMode) {
switch (zenMode) {
case NotificationManager.INTERRUPTION_FILTER_ALARMS:
return res.getString(R.string.zen_mode_option_alarms);
case NotificationManager.INTERRUPTION_FILTER_PRIORITY:
return res.getString(R.string.zen_mode_option_important_interruptions);
case NotificationManager.INTERRUPTION_FILTER_NONE:
return res.getString(R.string.zen_mode_option_no_interruptions);
default:
return null;
}
: mContext.getResources().getString(R.string.switch_on_text);
}
}

View File

@@ -16,16 +16,20 @@
package com.android.settings.notification;
import static com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.Fragment;
import android.app.NotificationManager;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnDismissListener;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.ServiceInfo;
import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
import android.os.Bundle;
import android.service.notification.ZenModeConfig;
import android.util.Log;
import android.view.LayoutInflater;
@@ -35,6 +39,7 @@ import android.widget.LinearLayout;
import android.widget.TextView;
import com.android.settings.R;
import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
import com.android.settings.utils.ZenServiceListing;
import java.lang.ref.WeakReference;
@@ -43,24 +48,48 @@ import java.util.Comparator;
import java.util.Set;
import java.util.TreeSet;
public abstract class ZenRuleSelectionDialog {
public class ZenRuleSelectionDialog extends InstrumentedDialogFragment {
private static final String TAG = "ZenRuleSelectionDialog";
private static final boolean DEBUG = ZenModeSettings.DEBUG;
private final Context mContext;
private final PackageManager mPm;
private NotificationManager mNm;
private final AlertDialog mDialog;
private final LinearLayout mRuleContainer;
private final ZenServiceListing mServiceListing;
private static ZenServiceListing mServiceListing;
protected static PositiveClickListener mPositiveClickListener;
public ZenRuleSelectionDialog(Context context, ZenServiceListing serviceListing) {
private static Context mContext;
private static PackageManager mPm;
private static NotificationManager mNm;
private LinearLayout mRuleContainer;
/**
* The interface we expect a listener to implement.
*/
public interface PositiveClickListener {
void onSystemRuleSelected(ZenRuleInfo ruleInfo, Fragment parent);
void onExternalRuleSelected(ZenRuleInfo ruleInfo, Fragment parent);
}
@Override
public int getMetricsCategory() {
return MetricsEvent.NOTIFICATION_ZEN_MODE_RULE_SELECTION_DIALOG;
}
public static void show(Context context, Fragment parent, PositiveClickListener
listener, ZenServiceListing serviceListing) {
mPositiveClickListener = listener;
mContext = context;
mPm = context.getPackageManager();
mNm = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
mPm = mContext.getPackageManager();
mNm = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
mServiceListing = serviceListing;
final View v =
LayoutInflater.from(context).inflate(R.layout.zen_rule_type_selection, null, false);
ZenRuleSelectionDialog dialog = new ZenRuleSelectionDialog();
dialog.setTargetFragment(parent, 0);
dialog.show(parent.getFragmentManager(), TAG);
}
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
final View v = LayoutInflater.from(getContext()).inflate(R.layout.zen_rule_type_selection,
null, false);
mRuleContainer = (LinearLayout) v.findViewById(R.id.rule_container);
if (mServiceListing != null) {
@@ -69,28 +98,21 @@ public abstract class ZenRuleSelectionDialog {
mServiceListing.addZenCallback(mServiceListingCallback);
mServiceListing.reloadApprovedServices();
}
mDialog = new AlertDialog.Builder(context)
return new AlertDialog.Builder(getContext())
.setTitle(R.string.zen_mode_choose_rule_type)
.setView(v)
.setOnDismissListener(new OnDismissListener() {
@Override
public void onDismiss(DialogInterface dialog) {
if (mServiceListing != null) {
mServiceListing.removeZenCallback(mServiceListingCallback);
}
}
})
.setNegativeButton(R.string.cancel, null)
.create();
}
public void show() {
mDialog.show();
@Override
public void onDismiss(DialogInterface dialog) {
super.onDismiss(dialog);
if (mServiceListing != null) {
mServiceListing.removeZenCallback(mServiceListingCallback);
}
}
abstract public void onSystemRuleSelected(ZenRuleInfo ruleInfo);
abstract public void onExternalRuleSelected(ZenRuleInfo ruleInfo);
private void bindType(final ZenRuleInfo ri) {
try {
ApplicationInfo info = mPm.getApplicationInfo(ri.packageName, 0);
@@ -108,11 +130,11 @@ public abstract class ZenRuleSelectionDialog {
v.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mDialog.dismiss();
dismiss();
if (ri.isSystem) {
onSystemRuleSelected(ri);
mPositiveClickListener.onSystemRuleSelected(ri, getTargetFragment());
} else {
onExternalRuleSelected(ri);
mPositiveClickListener.onExternalRuleSelected(ri, getTargetFragment());
}
}
});

View File

@@ -0,0 +1,166 @@
/*
* Copyright (C) 2017 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 junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertTrue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import android.app.AutomaticZenRule;
import android.app.Fragment;
import android.app.NotificationManager;
import android.content.ContentResolver;
import android.content.Context;
import android.provider.Settings;
import android.support.v7.preference.PreferenceCategory;
import android.support.v7.preference.PreferenceScreen;
import com.android.settings.TestConfig;
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.RuntimeEnvironment;
import org.robolectric.annotation.Config;
import org.robolectric.shadows.ShadowApplication;
import org.robolectric.util.ReflectionHelpers;
import java.util.HashMap;
import java.util.Map;
@RunWith(SettingsRobolectricTestRunner.class)
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
public class ZenModeAutomaticRulesPreferenceControllerTest {
private ZenModeAutomaticRulesPreferenceController mController;
private final String GENERIC_RULE_NAME = "test";
@Mock
private ZenModeBackend mBackend;
@Mock
private NotificationManager mNotificationManager;
@Mock
private PreferenceCategory mockPref;
@Mock
private NotificationManager.Policy mPolicy;
@Mock
private PreferenceScreen mPreferenceScreen;
private Context mContext;
private ContentResolver mContentResolver;
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
ShadowApplication shadowApplication = ShadowApplication.getInstance();
shadowApplication.setSystemService(Context.NOTIFICATION_SERVICE, mNotificationManager);
mContext = shadowApplication.getApplicationContext();
mContentResolver = RuntimeEnvironment.application.getContentResolver();
when(mNotificationManager.getNotificationPolicy()).thenReturn(mPolicy);
mController = new ZenModeAutomaticRulesPreferenceController(mContext, mock(Fragment.class),
mock(Lifecycle.class));
ReflectionHelpers.setField(mController, "mBackend", mBackend);
when(mPreferenceScreen.findPreference(mController.getPreferenceKey())).thenReturn(
mockPref);
mController.displayPreference(mPreferenceScreen);
}
@Test
public void updateState_checkRuleOrderingDescending() {
final int NUM_RULES = 4;
when(mNotificationManager.getAutomaticZenRules()).thenReturn(
mockAutoZenRulesDecreasingCreationTime(NUM_RULES));
Map.Entry<String, AutomaticZenRule>[] rules = mController.sortedRules();
assertEquals(NUM_RULES, rules.length);
// check ordering, most recent should be at the bottom/end (ie higher creation time)
for (int i = 0; i < NUM_RULES; i++) {
assertEquals(rules[i].getKey(), GENERIC_RULE_NAME + (NUM_RULES - 1 - i));
}
}
@Test
public void updateState_checkRuleOrderingAscending() {
final int NUM_RULES = 4;
when(mNotificationManager.getAutomaticZenRules()).thenReturn(
mockAutoZenRulesAscendingCreationTime(NUM_RULES));
Map.Entry<String, AutomaticZenRule>[] rules = mController.sortedRules();
assertEquals(NUM_RULES, rules.length);
// check ordering, most recent should be at the bottom/end (ie higher creation time)
for (int i = 0; i < NUM_RULES; i++) {
assertEquals(rules[i].getKey(), GENERIC_RULE_NAME + i);
}
}
@Test
public void updateState_checkRuleOrderingMix() {
final int NUM_RULES = 4;
// map with creation times: 0, 2, 4, 6
Map<String,AutomaticZenRule> rMap = mockAutoZenRulesAscendingCreationTime(NUM_RULES);
final String insertedRule1 = "insertedRule1";
rMap.put(insertedRule1, new AutomaticZenRule(insertedRule1, null, null,
Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS, true, 5));
final String insertedRule2 = "insertedRule2";
rMap.put(insertedRule2, new AutomaticZenRule(insertedRule2, null, null,
Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS, true, 3));
// rule map with rule creation times, 0, 2, 4, 6, 5, 3
// sort should create ordering based on creation times: 0, 2, 3, 4, 5, 6
when(mNotificationManager.getAutomaticZenRules()).thenReturn(rMap);
Map.Entry<String, AutomaticZenRule>[] rules = mController.sortedRules();
assertEquals(NUM_RULES + 2, rules.length); // inserted 2 rules
// check ordering of inserted rules
assertEquals(rules[4].getKey(), insertedRule1);
assertEquals(rules[2].getKey(), insertedRule2);
}
private Map<String, AutomaticZenRule> mockAutoZenRulesAscendingCreationTime(int numRules) {
Map<String, AutomaticZenRule> ruleMap = new HashMap<>();
for (int i = 0; i < numRules; i++) {
ruleMap.put(GENERIC_RULE_NAME + i, new AutomaticZenRule(GENERIC_RULE_NAME + i, null,
null, Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS, true, i * 2));
}
return ruleMap;
}
private Map<String, AutomaticZenRule> mockAutoZenRulesDecreasingCreationTime(int numRules) {
Map<String, AutomaticZenRule> ruleMap = new HashMap<>();
for (int i = 0; i < numRules; i++) {
ruleMap.put(GENERIC_RULE_NAME + i, new AutomaticZenRule(GENERIC_RULE_NAME + i, null,
null, Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS, true, numRules - i));
}
return ruleMap;
}
}