Settings: An update on Downtime.

- Migrate settings to the new zen mode state model.
 - Remove downtime settings.
 - Add automatic rule management page (add/remove)
 - Bind new automatic schedule rules to detail editor.
 - Clean up a few found miscapitalized string captions.
 - Migrate zen switch to report the shared summary string.

Bug: 20064962
Change-Id: Ia561e7f77c90c962729240b4d51ba1915297f64a
This commit is contained in:
John Spurlock
2015-04-09 12:50:04 -04:00
parent 342d08537f
commit 45fa140b8c
23 changed files with 907 additions and 763 deletions

View File

@@ -709,6 +709,26 @@
android:value="true" /> android:value="true" />
</activity> </activity>
<activity android:name="Settings$ZenModeScheduleRuleSettingsActivity"
android:exported="true"
android:taskAffinity="">
<intent-filter android:priority="1">
<action android:name="android.settings.ZEN_MODE_SCHEDULE_RULE_SETTINGS" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="com.android.settings.SHORTCUT" />
</intent-filter>
<meta-data android:name="com.android.settings.FRAGMENT_CLASS"
android:value="com.android.settings.notification.ZenModeScheduleRuleSettings" />
<meta-data android:name="com.android.settings.TOP_LEVEL_HEADER_ID"
android:resource="@id/notification_settings" />
<meta-data android:name="com.android.settings.PRIMARY_PROFILE_CONTROLLED"
android:value="true" />
</activity>
<activity android:name="Settings$HomeSettingsActivity" <activity android:name="Settings$HomeSettingsActivity"
android:label="@string/home_settings" android:label="@string/home_settings"
android:taskAffinity=""> android:taskAffinity="">

View File

@@ -0,0 +1,25 @@
<!--
Copyright (C) 2015 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.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24.0dp"
android:height="24.0dp"
android:tint="?android:attr/colorControlNormal"
android:viewportWidth="48.0"
android:viewportHeight="48.0">
<path
android:fillColor="@android:color/white"
android:pathData="M12.0,38.0c0.0,2.21 1.79,4.0 4.0,4.0l16.0,0.0c2.21,0.0 4.0,-1.79 4.0,-4.0L36.0,14.0L12.0,14.0l0.0,24.0zM38.0,8.0l-7.0,0.0l-2.0,-2.0L19.0,6.0l-2.0,2.0l-7.0,0.0l0.0,4.0l28.0,0.0L38.0,8.0z"/>
</vector>

32
res/layout/zen_rule_name.xml Executable file
View File

@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2015 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.
-->
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<EditText
android:id="@+id/rule_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:singleLine="true"
android:layout_marginLeft="22dp"
android:layout_marginRight="22dp" >
<requestFocus />
</EditText>
</FrameLayout>

View File

@@ -20,4 +20,4 @@
android:minHeight="?android:attr/listPreferredItemHeightSmall" android:minHeight="?android:attr/listPreferredItemHeightSmall"
android:textAppearance="?android:attr/textAppearanceMedium" android:textAppearance="?android:attr/textAppearanceMedium"
android:gravity="center_vertical" android:gravity="center_vertical"
android:paddingStart="@dimen/zen_downtime_checkbox_padding" /> android:paddingStart="@dimen/zen_schedule_rule_checkbox_padding" />

View File

@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2015 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.
-->
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/add"
android:title="@string/zen_mode_time_add_rule"
android:icon="@drawable/ic_menu_add_white"
android:visible="true"
android:showAsAction="collapseActionView|ifRoom" />
</menu>

View File

@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2015 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.
-->
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/delete"
android:title="@string/zen_mode_delete_rule"
android:icon="@drawable/ic_delete"
android:visible="true"
android:showAsAction="collapseActionView|ifRoom" />
</menu>

View File

@@ -1210,20 +1210,6 @@
<item>3</item> <item>3</item>
</string-array> </string-array>
<!-- Setting display values for zen mode -->
<string-array name="entries_zen_mode">
<item>Off</item>
<item>Limited interruptions</item>
<item>Zero interruptions</item>
</string-array>
<!-- Setting values for zen mode, must match the Settings.Global.ZEN_MODE_ constants -->
<string-array name="entryvalues_zen_mode" translatable="false">
<item>0</item>
<item>1</item>
<item>2</item>
</string-array>
<!-- Battery saver mode: allowable trigger threshold levels. --> <!-- Battery saver mode: allowable trigger threshold levels. -->
<integer-array name="battery_saver_trigger_values" translatable="false" > <integer-array name="battery_saver_trigger_values" translatable="false" >
<item>0</item> <item>0</item>

View File

@@ -90,8 +90,8 @@
<dimen name="notification_app_icon_size">64dp</dimen> <dimen name="notification_app_icon_size">64dp</dimen>
<dimen name="notification_app_icon_badge_size">20dp</dimen> <dimen name="notification_app_icon_badge_size">20dp</dimen>
<dimen name="notification_app_icon_badge_margin">4dp</dimen> <dimen name="notification_app_icon_badge_margin">4dp</dimen>
<dimen name="zen_downtime_checkbox_padding">7dp</dimen> <dimen name="zen_schedule_rule_checkbox_padding">7dp</dimen>
<dimen name="zen_downtime_margin">17dp</dimen> <dimen name="zen_schedule_day_margin">17dp</dimen>
<!-- Default text size for caption preview samples. Uses dp rather than sp because captions are not scaled. --> <!-- Default text size for caption preview samples. Uses dp rather than sp because captions are not scaled. -->
<dimen name="caption_preview_text_size">48dp</dimen> <dimen name="caption_preview_text_size">48dp</dimen>

View File

@@ -587,23 +587,11 @@
<!-- Button label for generic cancel action [CHAR LIMIT=20] --> <!-- Button label for generic cancel action [CHAR LIMIT=20] -->
<string name="cancel">Cancel</string> <string name="cancel">Cancel</string>
<!-- Button label for generic cancel action in all caps [CHAR LIMIT=20] -->
<string name="cancel_all_caps">CANCEL</string>
<!-- Button label for generic continue action in all caps [CHAR LIMIT=20] -->
<string name="continue_all_caps">CONTINUE</string>
<!-- Button label for generic OK action [CHAR LIMIT=20] --> <!-- Button label for generic OK action [CHAR LIMIT=20] -->
<string name="okay">OK</string> <string name="okay">OK</string>
<!-- Button label for generic YES action [CHAR LIMIT=20] --> <!-- Button label for generic forget action [CHAR LIMIT=20] -->
<string name="yes_all_caps">YES</string> <string name="forget">Forget</string>
<!-- Button label for generic NO action [CHAR LIMIT=20] -->
<string name="no_all_caps">NO</string>
<!-- Button label for generic FORGET action [CHAR LIMIT=20] -->
<string name="forget">FORGET</string>
<!-- Title of the Settings activity shown within the application itself. --> <!-- Title of the Settings activity shown within the application itself. -->
<string name="settings_label">Settings</string> <string name="settings_label">Settings</string>
@@ -5699,7 +5687,7 @@
<string name="notification_volume_option_title">Notification volume</string> <string name="notification_volume_option_title">Notification volume</string>
<!-- Sound & notification > Sound section: Title for the Interruptions option and associated settings page. [CHAR LIMIT=30] --> <!-- Sound & notification > Sound section: Title for the Interruptions option and associated settings page. [CHAR LIMIT=30] -->
<string name="zen_mode_settings_title">Block interruptions</string> <string name="zen_mode_settings_title">@*android:string/zen_mode_feature_name</string>
<!-- Sound & notification > Sound section: Title for the Priority interruptions option and associated settings page. [CHAR LIMIT=30] --> <!-- Sound & notification > Sound section: Title for the Priority interruptions option and associated settings page. [CHAR LIMIT=30] -->
<string name="zen_mode_priority_settings_title">Priority only allows</string> <string name="zen_mode_priority_settings_title">Priority only allows</string>
@@ -5717,7 +5705,7 @@
<string name="zen_mode_option_no_interruptions">No interruptions</string> <string name="zen_mode_option_no_interruptions">No interruptions</string>
<!-- Sound & notification > Sound section: Zen mode combined summary + condition line [CHAR LIMIT=60] --> <!-- Sound & notification > Sound section: Zen mode combined summary + condition line [CHAR LIMIT=60] -->
<string name="zen_mode_summary_combination"><xliff:g id="mode" example="Priority only">%1$s</xliff:g> <xliff:g id="exit condition" example="until you turn this off">%2$s</xliff:g></string> <string name="zen_mode_summary_combination"><xliff:g id="mode" example="Priority only">%1$s</xliff:g>: <xliff:g id="exit condition" example="Until you turn this off">%2$s</xliff:g></string>
<!-- Sound & notification > Sound section: Title for the option defining the phone ringtone. [CHAR LIMIT=30] --> <!-- Sound & notification > Sound section: Title for the option defining the phone ringtone. [CHAR LIMIT=30] -->
<string name="ringtone_title">Phone ringtone</string> <string name="ringtone_title">Phone ringtone</string>
@@ -5822,32 +5810,6 @@
to dismiss these notifications or touch action buttons within them. to dismiss these notifications or touch action buttons within them.
</string> </string>
<!-- Title of preference to manage condition providers -->
<string name="manage_condition_providers">Condition providers</string>
<!-- Summary of preference to manage condition providers, when none are enabled -->
<string name="manage_condition_providers_summary_zero">No apps provide conditions</string>
<!-- Summary of preference to manage condition providers, when one or more are enabled -->
<plurals name="manage_condition_providers_summary_nonzero">
<item quantity="one">%d app provides conditions</item>
<item quantity="other">%d apps provide conditions</item>
</plurals>
<!-- String to show in the list of condition providers, when none is installed -->
<string name="no_condition_providers">No condition providers are installed.</string>
<!-- Title for a warning message about security implications of enabling a condition
provider, displayed as a dialog message. [CHAR LIMIT=NONE] -->
<string name="condition_provider_security_warning_title">Enable
<xliff:g id="service" example="ConditionProvider">%1$s</xliff:g>?</string>
<!-- Summary for a warning message about security implications of enabling a condition
provider, displayed as a dialog message. [CHAR LIMIT=NONE] -->
<string name="condition_provider_security_warning_summary">
<xliff:g id="condition_provider_name">%1$s</xliff:g> will be able to
add exit conditions to Do not disturb mode.
</string>
<!-- [CHAR LIMIT=NONE] Text when loading app list in notification settings --> <!-- [CHAR LIMIT=NONE] Text when loading app list in notification settings -->
<string name="loading_notification_apps">Loading apps...</string> <string name="loading_notification_apps">Loading apps...</string>
@@ -5887,29 +5849,29 @@
<!-- [CHAR LIMIT=20] Notification settings: App notifications dialog dismiss button caption --> <!-- [CHAR LIMIT=20] Notification settings: App notifications dialog dismiss button caption -->
<string name="app_notifications_dialog_done">Done</string> <string name="app_notifications_dialog_done">Done</string>
<!-- [CHAR LIMIT=60] Zen mode settings: Downtime category text --> <!-- [CHAR LIMIT=40] Zen mode settings: Rule name option and edit dialog title -->
<string name="zen_mode_downtime_category">Downtime</string> <string name="zen_mode_rule_name">Rule name</string>
<!-- [CHAR LIMIT=40] Zen mode settings: Downtime days option title --> <!-- [CHAR LIMIT=40] Zen mode settings: Add rule menu option name -->
<string name="zen_mode_downtime_days">Days</string> <string name="zen_mode_time_add_rule">Add rule</string>
<!-- [CHAR LIMIT=40] Zen mode settings: Delete rule menu option name -->
<string name="zen_mode_delete_rule">Delete rule</string>
<!-- [CHAR LIMIT=40] Zen mode settings: Delete rule dialog confirmation message -->
<string name="zen_mode_delete_rule_confirmation">Delete \"<xliff:g id="rule" example="Weekends">%1$s</xliff:g>\" rule?</string>
<!-- [CHAR LIMIT=40] Zen mode settings: Delete rule dialog button caption -->
<string name="zen_mode_delete_rule_button">Delete</string>
<!-- [CHAR LIMIT=40] Zen mode settings: Text to display if rule isn't found -->
<string name="zen_mode_rule_not_found_text">Rule not found.</string>
<!-- [CHAR LIMIT=40] Zen mode settings: Timebased rule days option title -->
<string name="zen_mode_schedule_rule_days">Days</string>
<!-- [CHAR LIMIT=40] Zen mode settings: Downtime days option value, no days set --> <!-- [CHAR LIMIT=40] Zen mode settings: Downtime days option value, no days set -->
<string name="zen_mode_downtime_days_none">None</string> <string name="zen_mode_schedule_rule_days_none">None</string>
<!-- [CHAR LIMIT=60] Zen mode settings: Downtime mode option title -->
<string name="zen_mode_downtime_mode_title">Interruptions allowed</string>
<!-- [CHAR LIMIT=40] Zen mode settings: Downtime mode option value, priority only -->
<string name="zen_mode_downtime_mode_priority">Priority only</string>
<!-- [CHAR LIMIT=40] Zen mode settings: Downtime mode option value, none -->
<string name="zen_mode_downtime_mode_none">None</string>
<!-- [CHAR LIMIT=40] Zen mode settings: Automation category text -->
<string name="zen_mode_automation_category">Automation</string>
<!-- [CHAR LIMIT=40] Zen mode settings: Entry conditions option: title -->
<string name="zen_mode_entry_conditions_title">Automatically turn on</string>
<!-- [CHAR LIMIT=40] General divider text when concatenating multiple items in a text summary --> <!-- [CHAR LIMIT=40] General divider text when concatenating multiple items in a text summary -->
<string name="summary_divider_text">,\u0020</string> <string name="summary_divider_text">,\u0020</string>
@@ -5962,14 +5924,8 @@
<!-- [CHAR LIMIT=20] Zen mode settings: End time option --> <!-- [CHAR LIMIT=20] Zen mode settings: End time option -->
<string name="zen_mode_end_time">End time</string> <string name="zen_mode_end_time">End time</string>
<!-- [CHAR LIMIT=60] Zen mode settings: End time option: Summary text value format when downtime mode = priority and end time = next day --> <!-- [CHAR LIMIT=60] Zen mode settings: End time option: Summary text value format when end time = next day -->
<string name="zen_mode_end_time_priority_next_day_summary_format"><xliff:g id="formatted_time">%s</xliff:g> next day</string> <string name="zen_mode_end_time_next_day_summary_format"><xliff:g id="formatted_time">%s</xliff:g> next day</string>
<!-- [CHAR LIMIT=60] Zen mode settings: End time option: Summary text value format when downtime mode = none and end time = same day -->
<string name="zen_mode_end_time_none_same_day_summary_format"><xliff:g id="formatted_time">%s</xliff:g> or any alarm before</string>
<!-- [CHAR LIMIT=60] Zen mode settings: End time option: Summary text value format when downtime mode = none and end time = next day -->
<string name="zen_mode_end_time_none_next_day_summary_format"><xliff:g id="formatted_time">%s</xliff:g> next day or any alarm before</string>
<!-- [CHAR LIMIT=20] Notifications settings: Apps section header --> <!-- [CHAR LIMIT=20] Notifications settings: Apps section header -->
<string name="notification_settings_apps_title">App notifications</string> <string name="notification_settings_apps_title">App notifications</string>

View File

@@ -19,43 +19,5 @@
android:key="zen_mode_settings" android:key="zen_mode_settings"
android:title="@string/zen_mode_automation_settings_title" > android:title="@string/zen_mode_automation_settings_title" >
<!-- Downtime --> <!-- Rules added at runtime -->
<PreferenceCategory
android:key="downtime"
android:title="@string/zen_mode_downtime_category" >
<!-- Days -->
<Preference
android:key="days"
android:title="@string/zen_mode_downtime_days"
android:persistent="false" />
<!-- Start time/End time added and removed here! :-) -->
<!-- Interruptions allowed -->
<com.android.settings.DropDownPreference
android:key="downtime_mode"
android:title="@string/zen_mode_downtime_mode_title"
android:order="100"
android:persistent="false" />
</PreferenceCategory>
<PreferenceCategory
android:key="automation"
android:title="@string/zen_mode_automation_category" >
<Preference
android:key="entry"
android:title="@string/zen_mode_entry_conditions_title"
android:persistent="false" />
<Preference
android:key="manage_condition_providers"
android:title="@string/manage_condition_providers"
android:persistent="false"
android:fragment="com.android.settings.notification.ConditionProviderSettings" />
</PreferenceCategory>
</PreferenceScreen> </PreferenceScreen>

View File

@@ -16,7 +16,7 @@
--> -->
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" <PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
android:key="zen_mode_settings" android:key="zen_mode_priority_settings"
android:title="@string/zen_mode_priority_settings_title" > android:title="@string/zen_mode_priority_settings_title" >
<!-- Alarms --> <!-- Alarms -->

View File

@@ -0,0 +1,42 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2015 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_schedule_rule_settings" >
<!-- Rule name -->
<Preference
android:key="rule_name"
android:title="@string/zen_mode_rule_name"
android:persistent="false" />
<!-- Days -->
<Preference
android:key="days"
android:title="@string/zen_mode_schedule_rule_days"
android:persistent="false" />
<!-- Start time/End time added and removed here! :-) -->
<!-- Zen mode -->
<com.android.settings.DropDownPreference
android:key="zen_mode"
android:title="@string/zen_mode_settings_title"
android:order="100"
android:persistent="false" />
</PreferenceScreen>

View File

@@ -96,6 +96,7 @@ public class Settings extends SettingsActivity {
public static class ZenModeSettingsActivity extends SettingsActivity { /* empty */ } public static class ZenModeSettingsActivity extends SettingsActivity { /* empty */ }
public static class ZenModePrioritySettingsActivity extends SettingsActivity { /* empty */ } public static class ZenModePrioritySettingsActivity extends SettingsActivity { /* empty */ }
public static class ZenModeAutomationSettingsActivity extends SettingsActivity { /* empty */ } public static class ZenModeAutomationSettingsActivity extends SettingsActivity { /* empty */ }
public static class ZenModeScheduleRuleSettingsActivity extends SettingsActivity { /* empty */ }
public static class NotificationSettingsActivity extends SettingsActivity { /* empty */ } public static class NotificationSettingsActivity extends SettingsActivity { /* empty */ }
public static class NotificationAppListActivity extends SettingsActivity { /* empty */ } public static class NotificationAppListActivity extends SettingsActivity { /* empty */ }
public static class AppNotificationSettingsActivity extends SettingsActivity { /* empty */ } public static class AppNotificationSettingsActivity extends SettingsActivity { /* empty */ }

View File

@@ -100,6 +100,7 @@ import com.android.settings.notification.NotificationSettings;
import com.android.settings.notification.NotificationStation; import com.android.settings.notification.NotificationStation;
import com.android.settings.notification.OtherSoundSettings; import com.android.settings.notification.OtherSoundSettings;
import com.android.settings.notification.ZenModeSettings; import com.android.settings.notification.ZenModeSettings;
import com.android.settings.notification.ZenModeScheduleRuleSettings;
import com.android.settings.print.PrintJobSettingsFragment; import com.android.settings.print.PrintJobSettingsFragment;
import com.android.settings.print.PrintSettingsFragment; import com.android.settings.print.PrintSettingsFragment;
import com.android.settings.search.DynamicIndexableContentMonitor; import com.android.settings.search.DynamicIndexableContentMonitor;
@@ -332,7 +333,8 @@ public class SettingsActivity extends Activity
AppNotificationSettings.class.getName(), AppNotificationSettings.class.getName(),
OtherSoundSettings.class.getName(), OtherSoundSettings.class.getName(),
ApnSettings.class.getName(), ApnSettings.class.getName(),
WifiCallingSettings.class.getName() WifiCallingSettings.class.getName(),
ZenModeScheduleRuleSettings.class.getName(),
}; };

View File

@@ -1,157 +0,0 @@
/*
* Copyright (C) 2014 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.animation.LayoutTransition;
import android.app.INotificationManager;
import android.content.Context;
import android.net.Uri;
import android.os.Handler;
import android.os.Message;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.service.notification.Condition;
import android.service.notification.IConditionListener;
import android.util.ArraySet;
import android.util.Log;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.LinearLayout;
import com.android.settings.R;
public class ZenModeAutomaticConditionSelection extends LinearLayout {
private static final String TAG = "ZenModeAutomaticConditionSelection";
private static final boolean DEBUG = true;
private final INotificationManager mNoMan;
private final H mHandler = new H();
private final Context mContext;
private final ArraySet<Uri> mSelectedConditions = new ArraySet<Uri>();
public ZenModeAutomaticConditionSelection(Context context) {
super(context);
mContext = context;
setOrientation(VERTICAL);
setLayoutTransition(new LayoutTransition());
final int p = mContext.getResources().getDimensionPixelSize(R.dimen.content_margin_left);
setPadding(p, p, p, 0);
mNoMan = INotificationManager.Stub.asInterface(
ServiceManager.getService(Context.NOTIFICATION_SERVICE));
refreshSelectedConditions();
}
private void refreshSelectedConditions() {
try {
final Condition[] automatic = mNoMan.getAutomaticZenModeConditions();
mSelectedConditions.clear();
if (automatic != null) {
for (Condition c : automatic) {
mSelectedConditions.add(c.id);
}
}
} catch (RemoteException e) {
Log.w(TAG, "Error calling getAutomaticZenModeConditions", e);
}
}
private CheckBox newCheckBox(Object tag) {
final CheckBox button = new CheckBox(mContext);
button.setTag(tag);
button.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
setSelectedCondition((Uri)button.getTag(), isChecked);
}
});
addView(button);
return button;
}
private void setSelectedCondition(Uri conditionId, boolean selected) {
if (DEBUG) Log.d(TAG, "setSelectedCondition conditionId=" + conditionId
+ " selected=" + selected);
if (selected) {
mSelectedConditions.add(conditionId);
} else {
mSelectedConditions.remove(conditionId);
}
final Uri[] automatic = new Uri[mSelectedConditions.size()];
for (int i = 0; i < automatic.length; i++) {
automatic[i] = mSelectedConditions.valueAt(i);
}
try {
mNoMan.setAutomaticZenModeConditions(automatic);
} catch (RemoteException e) {
Log.w(TAG, "Error calling setAutomaticZenModeConditions", e);
}
}
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
requestZenModeConditions(Condition.FLAG_RELEVANT_ALWAYS);
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
requestZenModeConditions(0 /*none*/);
}
protected void requestZenModeConditions(int relevance) {
if (DEBUG) Log.d(TAG, "requestZenModeConditions " + Condition.relevanceToString(relevance));
try {
mNoMan.requestZenModeConditions(mListener, relevance);
} catch (RemoteException e) {
Log.w(TAG, "Error calling requestZenModeConditions", e);
}
}
protected void handleConditions(Condition[] conditions) {
for (final Condition c : conditions) {
CheckBox v = (CheckBox) findViewWithTag(c.id);
if (c.state != Condition.STATE_ERROR) {
if (v == null) {
v = newCheckBox(c.id);
}
}
if (v != null) {
v.setText(c.summary);
v.setEnabled(c.state != Condition.STATE_ERROR);
v.setChecked(mSelectedConditions.contains(c.id));
}
}
}
private final IConditionListener mListener = new IConditionListener.Stub() {
@Override
public void onConditionsReceived(Condition[] conditions) {
if (conditions == null || conditions.length == 0) return;
mHandler.obtainMessage(H.CONDITIONS, conditions).sendToTarget();
}
};
private final class H extends Handler {
private static final int CONDITIONS = 1;
@Override
public void handleMessage(Message msg) {
if (msg.what == CONDITIONS) handleConditions((Condition[])msg.obj);
}
}
}

View File

@@ -16,248 +16,76 @@
package com.android.settings.notification; package com.android.settings.notification;
import static com.android.settings.notification.ZenModeDowntimeDaysSelection.DAYS; import android.content.Intent;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.DialogFragment;
import android.app.FragmentManager;
import android.app.INotificationManager;
import android.app.TimePickerDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnDismissListener;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.os.Bundle; import android.os.Bundle;
import android.os.ServiceManager;
import android.preference.Preference; import android.preference.Preference;
import android.preference.Preference.OnPreferenceClickListener; import android.preference.Preference.OnPreferenceClickListener;
import android.preference.PreferenceCategory;
import android.preference.PreferenceScreen; import android.preference.PreferenceScreen;
import android.service.notification.Condition; import android.provider.Settings.Global;
import android.service.notification.ZenModeConfig; import android.service.notification.ZenModeConfig;
import android.text.format.DateFormat; import android.service.notification.ZenModeConfig.ScheduleInfo;
import android.service.notification.ZenModeConfig.ZenRule;
import android.util.Log; import android.util.Log;
import android.util.SparseArray; import android.view.Menu;
import android.widget.TimePicker; import android.view.MenuInflater;
import android.view.MenuItem;
import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.MetricsLogger;
import com.android.settings.DropDownPreference;
import com.android.settings.R; import com.android.settings.R;
import com.android.settings.search.BaseSearchIndexProvider;
import com.android.settings.search.Indexable;
import com.android.settings.search.SearchIndexableRaw;
import java.text.SimpleDateFormat; public class ZenModeAutomationSettings extends ZenModeSettingsBase {
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import java.util.Objects;
public class ZenModeAutomationSettings extends ZenModeSettingsBase implements Indexable {
private static final String KEY_DOWNTIME = "downtime";
private static final String KEY_DAYS = "days";
private static final String KEY_START_TIME = "start_time";
private static final String KEY_END_TIME = "end_time";
private static final String KEY_DOWNTIME_MODE = "downtime_mode";
private static final String KEY_AUTOMATION = "automation";
private static final String KEY_ENTRY = "entry";
private static final String KEY_CONDITION_PROVIDERS = "manage_condition_providers";
private static final SimpleDateFormat DAY_FORMAT = new SimpleDateFormat("EEE");
private PackageManager mPM;
private boolean mDisableListeners;
private boolean mDowntimeSupported;
private Preference mDays;
private TimePickerPreference mStart;
private TimePickerPreference mEnd;
private DropDownPreference mDowntimeMode;
private PreferenceCategory mAutomationCategory;
private Preference mEntry;
private Preference mConditionProviders;
@Override @Override
public void onCreate(Bundle icicle) { public void onCreate(Bundle icicle) {
super.onCreate(icicle); super.onCreate(icicle);
mPM = mContext.getPackageManager();
setHasOptionsMenu(true);
addPreferencesFromResource(R.xml.zen_mode_automation_settings); addPreferencesFromResource(R.xml.zen_mode_automation_settings);
final PreferenceScreen root = getPreferenceScreen();
onCreateDowntimeSettings(root);
mAutomationCategory = (PreferenceCategory) findPreference(KEY_AUTOMATION);
mEntry = findPreference(KEY_ENTRY);
mEntry.setOnPreferenceClickListener(new OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(Preference preference) {
new AlertDialog.Builder(mContext)
.setTitle(R.string.zen_mode_entry_conditions_title)
.setView(new ZenModeAutomaticConditionSelection(mContext))
.setOnDismissListener(new OnDismissListener() {
@Override
public void onDismiss(DialogInterface dialog) {
refreshAutomationSection();
}
})
.setPositiveButton(R.string.dlg_ok, null)
.show();
return true;
}
});
mConditionProviders = findPreference(KEY_CONDITION_PROVIDERS);
} }
private void onCreateDowntimeSettings(PreferenceScreen root) { private void showRule(String ruleId, String ruleName) {
mDowntimeSupported = isDowntimeSupported(mContext); if (DEBUG) Log.d(TAG, "showRule " + ruleId + " name=" + ruleName);
if (!mDowntimeSupported) { mContext.startActivity(new Intent(ZenModeScheduleRuleSettings.ACTION)
removePreference(KEY_DOWNTIME); .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
return; .putExtra(ZenModeScheduleRuleSettings.EXTRA_RULE_ID, ruleId));
}
final PreferenceCategory downtime = (PreferenceCategory) findPreference(KEY_DOWNTIME);
mDays = downtime.findPreference(KEY_DAYS);
mDays.setOnPreferenceClickListener(new OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(Preference preference) {
new AlertDialog.Builder(mContext)
.setTitle(R.string.zen_mode_downtime_days)
.setView(new ZenModeDowntimeDaysSelection(mContext, mConfig.sleepMode) {
@Override
protected void onChanged(String mode) {
if (mDisableListeners) return;
if (Objects.equals(mode, mConfig.sleepMode)) return;
if (DEBUG) Log.d(TAG, "days.onChanged sleepMode=" + mode);
final ZenModeConfig newConfig = mConfig.copy();
newConfig.sleepMode = mode;
setZenModeConfig(newConfig);
}
})
.setOnDismissListener(new OnDismissListener() {
@Override
public void onDismiss(DialogInterface dialog) {
updateDays();
}
})
.setPositiveButton(R.string.done_button, null)
.show();
return true;
}
});
final FragmentManager mgr = getFragmentManager();
mStart = new TimePickerPreference(mContext, mgr);
mStart.setKey(KEY_START_TIME);
mStart.setTitle(R.string.zen_mode_start_time);
mStart.setCallback(new TimePickerPreference.Callback() {
@Override
public boolean onSetTime(int hour, int minute) {
if (mDisableListeners) return true;
if (!ZenModeConfig.isValidHour(hour)) return false;
if (!ZenModeConfig.isValidMinute(minute)) return false;
if (hour == mConfig.sleepStartHour && minute == mConfig.sleepStartMinute) {
return true;
}
if (DEBUG) Log.d(TAG, "onPrefChange sleepStart h=" + hour + " m=" + minute);
final ZenModeConfig newConfig = mConfig.copy();
newConfig.sleepStartHour = hour;
newConfig.sleepStartMinute = minute;
return setZenModeConfig(newConfig);
}
});
downtime.addPreference(mStart);
mStart.setDependency(mDays.getKey());
mEnd = new TimePickerPreference(mContext, mgr);
mEnd.setKey(KEY_END_TIME);
mEnd.setTitle(R.string.zen_mode_end_time);
mEnd.setCallback(new TimePickerPreference.Callback() {
@Override
public boolean onSetTime(int hour, int minute) {
if (mDisableListeners) return true;
if (!ZenModeConfig.isValidHour(hour)) return false;
if (!ZenModeConfig.isValidMinute(minute)) return false;
if (hour == mConfig.sleepEndHour && minute == mConfig.sleepEndMinute) {
return true;
}
if (DEBUG) Log.d(TAG, "onPrefChange sleepEnd h=" + hour + " m=" + minute);
final ZenModeConfig newConfig = mConfig.copy();
newConfig.sleepEndHour = hour;
newConfig.sleepEndMinute = minute;
return setZenModeConfig(newConfig);
}
});
downtime.addPreference(mEnd);
mEnd.setDependency(mDays.getKey());
mDowntimeMode = (DropDownPreference) downtime.findPreference(KEY_DOWNTIME_MODE);
mDowntimeMode.addItem(R.string.zen_mode_downtime_mode_priority, false);
mDowntimeMode.addItem(R.string.zen_mode_downtime_mode_none, true);
mDowntimeMode.setCallback(new DropDownPreference.Callback() {
@Override
public boolean onItemSelected(int pos, Object value) {
if (mDisableListeners) return true;
final boolean sleepNone = value instanceof Boolean ? ((Boolean) value) : false;
if (mConfig == null || mConfig.sleepNone == sleepNone) return false;
final ZenModeConfig newConfig = mConfig.copy();
newConfig.sleepNone = sleepNone;
if (DEBUG) Log.d(TAG, "onPrefChange sleepNone=" + sleepNone);
return setZenModeConfig(newConfig);
}
});
mDowntimeMode.setOrder(10); // sort at the bottom of the category
mDowntimeMode.setDependency(mDays.getKey());
} }
private void updateDays() { @Override
// Compute an ordered, delimited list of day names based on the persisted user config. public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
if (mConfig != null) { inflater.inflate(R.menu.zen_mode_automation, menu);
final int[] days = ZenModeConfig.tryParseDays(mConfig.sleepMode);
if (days != null && days.length != 0) {
final StringBuilder sb = new StringBuilder();
final Calendar c = Calendar.getInstance();
for (int i = 0; i < DAYS.length; i++) {
final int day = DAYS[i];
for (int j = 0; j < days.length; j++) {
if (day == days[j]) {
c.set(Calendar.DAY_OF_WEEK, day);
if (sb.length() > 0) {
sb.append(mContext.getString(R.string.summary_divider_text));
}
sb.append(DAY_FORMAT.format(c.getTime()));
break;
}
}
}
if (sb.length() > 0) {
mDays.setSummary(sb);
mDays.notifyDependencyChange(false);
return;
}
}
}
mDays.setSummary(R.string.zen_mode_downtime_days_none);
mDays.notifyDependencyChange(true);
} }
private void updateEndSummary() { @Override
if (!mDowntimeSupported) return; public boolean onOptionsItemSelected(MenuItem item) {
final int startMin = 60 * mConfig.sleepStartHour + mConfig.sleepStartMinute; if (item.getItemId() == R.id.add) {
final int endMin = 60 * mConfig.sleepEndHour + mConfig.sleepEndMinute; showAddRuleDialog();
final boolean nextDay = startMin >= endMin; return true;
final int summaryFormat;
if (mConfig.sleepNone) {
summaryFormat = nextDay ? R.string.zen_mode_end_time_none_next_day_summary_format
: R.string.zen_mode_end_time_none_same_day_summary_format;
} else {
summaryFormat = nextDay ? R.string.zen_mode_end_time_priority_next_day_summary_format
: 0;
} }
mEnd.setSummaryFormat(summaryFormat); return super.onOptionsItemSelected(item);
}
private void showAddRuleDialog() {
new ZenRuleNameDialog(mContext, "", mConfig.getAutomaticRuleNames()) {
@Override
public void onOk(String ruleName) {
final ScheduleInfo schedule = new ScheduleInfo();
schedule.days = ZenModeConfig.ALL_DAYS;
schedule.startHour = 22;
schedule.endHour = 7;
final ZenRule rule = new ZenRule();
rule.name = ruleName;
rule.enabled = true;
rule.zenMode = Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
rule.conditionId = ZenModeConfig.toScheduleConditionId(schedule);
final ZenModeConfig newConfig = mConfig.copy();
final String ruleId = newConfig.newRuleId();
newConfig.automaticRules.put(ruleId, rule);
if (setZenModeConfig(newConfig)) {
showRule(ruleId, rule.name);
}
}
}.show();
} }
@Override @Override
@@ -277,16 +105,27 @@ public class ZenModeAutomationSettings extends ZenModeSettingsBase implements In
} }
private void updateControls() { private void updateControls() {
mDisableListeners = true; final PreferenceScreen root = getPreferenceScreen();
if (mDowntimeSupported) { root.removeAll();
updateDays();
mStart.setTime(mConfig.sleepStartHour, mConfig.sleepStartMinute); if (mConfig == null) return;
mEnd.setTime(mConfig.sleepEndHour, mConfig.sleepEndMinute); for (int i = 0; i < mConfig.automaticRules.size(); i++) {
mDowntimeMode.setSelectedValue(mConfig.sleepNone); final String id = mConfig.automaticRules.keyAt(i);
final ZenRule rule = mConfig.automaticRules.valueAt(i);
if (!ZenModeConfig.isValidScheduleConditionId(rule.conditionId)) continue;
final Preference p = new Preference(mContext);
p.setTitle(rule.name);
p.setSummary(rule.enabled ? R.string.switch_on_text : R.string.switch_off_text);
p.setPersistent(false);
p.setOnPreferenceClickListener(new OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(Preference preference) {
showRule(id, rule.name);
return true;
}
});
root.addPreference(p);
} }
mDisableListeners = false;
refreshAutomationSection();
updateEndSummary();
} }
@Override @Override
@@ -294,171 +133,4 @@ public class ZenModeAutomationSettings extends ZenModeSettingsBase implements In
return MetricsLogger.NOTIFICATION_ZEN_MODE_AUTOMATION; return MetricsLogger.NOTIFICATION_ZEN_MODE_AUTOMATION;
} }
private void refreshAutomationSection() {
if (mConditionProviders != null) {
final int total = ConditionProviderSettings.getProviderCount(mPM);
if (total == 0) {
getPreferenceScreen().removePreference(mAutomationCategory);
} else {
final int n = ConditionProviderSettings.getEnabledProviderCount(mContext);
if (n == 0) {
mConditionProviders.setSummary(getResources().getString(
R.string.manage_condition_providers_summary_zero));
} else {
mConditionProviders.setSummary(String.format(getResources().getQuantityString(
R.plurals.manage_condition_providers_summary_nonzero,
n, n)));
}
final String entrySummary = getEntryConditionSummary();
if (n == 0 || entrySummary == null) {
mEntry.setSummary(R.string.zen_mode_entry_conditions_summary_none);
} else {
mEntry.setSummary(entrySummary);
}
}
}
}
private String getEntryConditionSummary() {
final INotificationManager nm = INotificationManager.Stub.asInterface(
ServiceManager.getService(Context.NOTIFICATION_SERVICE));
try {
final Condition[] automatic = nm.getAutomaticZenModeConditions();
if (automatic == null || automatic.length == 0) {
return null;
}
final String divider = getString(R.string.summary_divider_text);
final StringBuilder sb = new StringBuilder();
for (int i = 0; i < automatic.length; i++) {
if (i > 0) sb.append(divider);
sb.append(automatic[i].summary);
}
return sb.toString();
} catch (Exception e) {
Log.w(TAG, "Error calling getAutomaticZenModeConditions", e);
return null;
}
}
private static SparseArray<String> allKeyTitles(Context context) {
final SparseArray<String> rt = new SparseArray<String>();
rt.put(R.string.zen_mode_downtime_category, KEY_DOWNTIME);
rt.put(R.string.zen_mode_downtime_days, KEY_DAYS);
rt.put(R.string.zen_mode_start_time, KEY_START_TIME);
rt.put(R.string.zen_mode_end_time, KEY_END_TIME);
rt.put(R.string.zen_mode_downtime_mode_title, KEY_DOWNTIME_MODE);
rt.put(R.string.zen_mode_automation_category, KEY_AUTOMATION);
rt.put(R.string.manage_condition_providers, KEY_CONDITION_PROVIDERS);
return rt;
}
// Enable indexing of searchable data
public static final Indexable.SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
new BaseSearchIndexProvider() {
@Override
public List<SearchIndexableRaw> getRawDataToIndex(Context context, boolean enabled) {
final SparseArray<String> keyTitles = allKeyTitles(context);
final int N = keyTitles.size();
final List<SearchIndexableRaw> result = new ArrayList<SearchIndexableRaw>(N);
final Resources res = context.getResources();
for (int i = 0; i < N; i++) {
final SearchIndexableRaw data = new SearchIndexableRaw(context);
data.key = keyTitles.valueAt(i);
data.title = res.getString(keyTitles.keyAt(i));
data.screenTitle = res.getString(R.string.zen_mode_automation_settings_title);
result.add(data);
}
return result;
}
@Override
public List<String> getNonIndexableKeys(Context context) {
final ArrayList<String> rt = new ArrayList<String>();
if (!isDowntimeSupported(context)) {
rt.add(KEY_DOWNTIME);
rt.add(KEY_DAYS);
rt.add(KEY_START_TIME);
rt.add(KEY_END_TIME);
rt.add(KEY_DOWNTIME_MODE);
}
return rt;
}
};
private static class TimePickerPreference extends Preference {
private final Context mContext;
private int mSummaryFormat;
private int mHourOfDay;
private int mMinute;
private Callback mCallback;
public TimePickerPreference(Context context, final FragmentManager mgr) {
super(context);
mContext = context;
setPersistent(false);
setOnPreferenceClickListener(new OnPreferenceClickListener(){
@Override
public boolean onPreferenceClick(Preference preference) {
final TimePickerFragment frag = new TimePickerFragment();
frag.pref = TimePickerPreference.this;
frag.show(mgr, TimePickerPreference.class.getName());
return true;
}
});
}
public void setCallback(Callback callback) {
mCallback = callback;
}
public void setSummaryFormat(int resId) {
mSummaryFormat = resId;
updateSummary();
}
public void setTime(int hourOfDay, int minute) {
if (mCallback != null && !mCallback.onSetTime(hourOfDay, minute)) return;
mHourOfDay = hourOfDay;
mMinute = minute;
updateSummary();
}
private void updateSummary() {
final Calendar c = Calendar.getInstance();
c.set(Calendar.HOUR_OF_DAY, mHourOfDay);
c.set(Calendar.MINUTE, mMinute);
String time = DateFormat.getTimeFormat(mContext).format(c.getTime());
if (mSummaryFormat != 0) {
time = mContext.getResources().getString(mSummaryFormat, time);
}
setSummary(time);
}
public static class TimePickerFragment extends DialogFragment implements
TimePickerDialog.OnTimeSetListener {
public TimePickerPreference pref;
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
final boolean usePref = pref != null && pref.mHourOfDay >= 0 && pref.mMinute >= 0;
final Calendar c = Calendar.getInstance();
final int hour = usePref ? pref.mHourOfDay : c.get(Calendar.HOUR_OF_DAY);
final int minute = usePref ? pref.mMinute : c.get(Calendar.MINUTE);
return new TimePickerDialog(getActivity(), this, hour, minute,
DateFormat.is24HourFormat(getActivity()));
}
public void onTimeSet(TimePicker view, int hourOfDay, int minute) {
if (pref != null) {
pref.setTime(hourOfDay, minute);
}
}
}
public interface Callback {
boolean onSetTime(int hour, int minute);
}
}
} }

View File

@@ -45,11 +45,14 @@ public class ZenModeConditionSelection extends RadioGroup {
private final H mHandler = new H(); private final H mHandler = new H();
private final Context mContext; private final Context mContext;
private final List<Condition> mConditions; private final List<Condition> mConditions;
private final int mZenMode;
private Condition mCondition; private Condition mCondition;
public ZenModeConditionSelection(Context context) { public ZenModeConditionSelection(Context context, int zenMode) {
super(context); super(context);
mContext = context; mContext = context;
mZenMode = zenMode;
mConditions = new ArrayList<Condition>(); mConditions = new ArrayList<Condition>();
setLayoutTransition(new LayoutTransition()); setLayoutTransition(new LayoutTransition());
final int p = mContext.getResources().getDimensionPixelSize(R.dimen.content_margin_left); final int p = mContext.getResources().getDimensionPixelSize(R.dimen.content_margin_left);
@@ -130,7 +133,7 @@ public class ZenModeConditionSelection extends RadioGroup {
public void confirmCondition() { public void confirmCondition() {
if (DEBUG) Log.d(TAG, "confirmCondition " + mCondition); if (DEBUG) Log.d(TAG, "confirmCondition " + mCondition);
try { try {
mNoMan.setZenModeCondition(mCondition); mNoMan.setZenMode(mZenMode, mCondition != null ? mCondition.id : null, TAG);
} catch (RemoteException e) { } catch (RemoteException e) {
// noop // noop
} }

View File

@@ -17,37 +17,42 @@
package com.android.settings.notification; package com.android.settings.notification;
import android.content.Context; import android.content.Context;
import android.service.notification.ZenModeConfig;
import android.util.SparseBooleanArray; import android.util.SparseBooleanArray;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.widget.CheckBox; import android.widget.CheckBox;
import android.widget.CompoundButton; import android.widget.CompoundButton;
import android.widget.ScrollView;
import android.widget.CompoundButton.OnCheckedChangeListener; import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.LinearLayout; import android.widget.LinearLayout;
import android.widget.ScrollView;
import com.android.settings.R; import com.android.settings.R;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Calendar; import java.util.Calendar;
public class ZenModeDowntimeDaysSelection extends ScrollView { public class ZenModeScheduleDaysSelection extends ScrollView {
public static final int[] DAYS = { public static final int[] DAYS = {
Calendar.MONDAY, Calendar.TUESDAY, Calendar.WEDNESDAY, Calendar.THURSDAY, Calendar.FRIDAY, Calendar.SUNDAY,
Calendar.SATURDAY, Calendar.SUNDAY Calendar.MONDAY,
Calendar.TUESDAY,
Calendar.WEDNESDAY,
Calendar.THURSDAY,
Calendar.FRIDAY,
Calendar.SATURDAY,
}; };
private static final SimpleDateFormat DAY_FORMAT = new SimpleDateFormat("EEEE"); private static final SimpleDateFormat DAY_FORMAT = new SimpleDateFormat("EEEE");
private final SparseBooleanArray mDays = new SparseBooleanArray(); private final SparseBooleanArray mDays = new SparseBooleanArray();
private final LinearLayout mLayout; private final LinearLayout mLayout;
public ZenModeDowntimeDaysSelection(Context context, String mode) { public ZenModeScheduleDaysSelection(Context context, int[] days) {
super(context); super(context);
mLayout = new LinearLayout(mContext); mLayout = new LinearLayout(mContext);
final int hPad = context.getResources().getDimensionPixelSize(R.dimen.zen_downtime_margin); final int hPad = context.getResources()
.getDimensionPixelSize(R.dimen.zen_schedule_day_margin);
mLayout.setPadding(hPad, 0, hPad, 0); mLayout.setPadding(hPad, 0, hPad, 0);
addView(mLayout); addView(mLayout);
final int[] days = ZenModeConfig.tryParseDays(mode);
if (days != null) { if (days != null) {
for (int i = 0; i < days.length; i++) { for (int i = 0; i < days.length; i++) {
mDays.put(days[i], true); mDays.put(days[i], true);
@@ -58,7 +63,7 @@ public class ZenModeDowntimeDaysSelection extends ScrollView {
final LayoutInflater inflater = LayoutInflater.from(context); final LayoutInflater inflater = LayoutInflater.from(context);
for (int i = 0; i < DAYS.length; i++) { for (int i = 0; i < DAYS.length; i++) {
final int day = DAYS[i]; final int day = DAYS[i];
final CheckBox checkBox = (CheckBox) inflater.inflate(R.layout.zen_downtime_day, final CheckBox checkBox = (CheckBox) inflater.inflate(R.layout.zen_schedule_rule_day,
this, false); this, false);
c.set(Calendar.DAY_OF_WEEK, day); c.set(Calendar.DAY_OF_WEEK, day);
checkBox.setText(DAY_FORMAT.format(c.getTime())); checkBox.setText(DAY_FORMAT.format(c.getTime()));
@@ -67,30 +72,29 @@ public class ZenModeDowntimeDaysSelection extends ScrollView {
@Override @Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
mDays.put(day, isChecked); mDays.put(day, isChecked);
onChanged(getMode()); onChanged(getDays());
} }
}); });
mLayout.addView(checkBox); mLayout.addView(checkBox);
} }
} }
private String getMode() { private int[] getDays() {
final StringBuilder sb = new StringBuilder(ZenModeConfig.SLEEP_MODE_DAYS_PREFIX); final SparseBooleanArray rt = new SparseBooleanArray(mDays.size());
boolean empty = true;
for (int i = 0; i < mDays.size(); i++) { for (int i = 0; i < mDays.size(); i++) {
final int day = mDays.keyAt(i); final int day = mDays.keyAt(i);
if (!mDays.valueAt(i)) continue; if (!mDays.valueAt(i)) continue;
if (empty) { rt.put(day, true);
empty = false;
} else {
sb.append(',');
}
sb.append(day);
} }
return empty ? null : sb.toString(); final int[] rta = new int[rt.size()];
for (int i = 0; i < rta.length; i++) {
rta[i] = rt.keyAt(i);
}
Arrays.sort(rta);
return rta;
} }
protected void onChanged(String mode) { protected void onChanged(int[] days) {
// event hook for subclasses // event hook for subclasses
} }
} }

View File

@@ -0,0 +1,477 @@
/*
* Copyright (C) 2015 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.notification.ZenModeScheduleDaysSelection.DAYS;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.DialogFragment;
import android.app.FragmentManager;
import android.app.TimePickerDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.content.DialogInterface.OnDismissListener;
import android.content.Intent;
import android.os.Bundle;
import android.preference.Preference;
import android.preference.Preference.OnPreferenceClickListener;
import android.preference.PreferenceScreen;
import android.provider.Settings;
import android.provider.Settings.Global;
import android.service.notification.ZenModeConfig;
import android.service.notification.ZenModeConfig.ScheduleInfo;
import android.service.notification.ZenModeConfig.ZenRule;
import android.text.format.DateFormat;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.widget.Switch;
import android.widget.TimePicker;
import android.widget.Toast;
import com.android.internal.logging.MetricsLogger;
import com.android.settings.DropDownPreference;
import com.android.settings.R;
import com.android.settings.SettingsActivity;
import com.android.settings.widget.SwitchBar;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Calendar;
public class ZenModeScheduleRuleSettings extends ZenModeSettingsBase
implements SwitchBar.OnSwitchChangeListener {
private static final String TAG = ZenModeSettingsBase.TAG;
private static final boolean DEBUG = ZenModeSettingsBase.DEBUG;
private static final String KEY_RULE_NAME = "rule_name";
private static final String KEY_DAYS = "days";
private static final String KEY_START_TIME = "start_time";
private static final String KEY_END_TIME = "end_time";
private static final String KEY_ZEN_MODE = "zen_mode";
private static final SimpleDateFormat DAY_FORMAT = new SimpleDateFormat("EEE");
public static final String ACTION = Settings.ACTION_ZEN_MODE_SCHEDULE_RULE_SETTINGS;
public static final String EXTRA_RULE_ID = "rule_id";
private Context mContext;
private boolean mDisableListeners;
private SwitchBar mSwitchBar;
private Preference mRuleName;
private Preference mDays;
private TimePickerPreference mStart;
private TimePickerPreference mEnd;
private DropDownPreference mZenMode;
private String mRuleId;
private ZenRule mRule;
private ScheduleInfo mSchedule;
private boolean mDeleting;
@Override
protected void onZenModeChanged() {
// noop
}
@Override
protected void onZenModeConfigChanged() {
if (!refreshRuleOrFinish()) {
updateControls();
}
}
private boolean refreshRuleOrFinish() {
mRule = mConfig.automaticRules.get(mRuleId);
if (DEBUG) Log.d(TAG, "mRule=" + mRule);
mSchedule = mRule != null ? ZenModeConfig.tryParseScheduleConditionId(mRule.conditionId)
: null;
if (mSchedule == null) {
toastAndFinish();
return true;
}
return false;
}
@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) {
showDeleteRuleDialog();
return true;
}
return super.onOptionsItemSelected(item);
}
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
mContext = getActivity();
final Intent intent = getActivity().getIntent();
if (DEBUG) Log.d(TAG, "onCreate getIntent()=" + intent);
if (intent == null) {
Log.w(TAG, "No intent");
toastAndFinish();
return;
}
mRuleId = intent.getStringExtra(EXTRA_RULE_ID);
if (DEBUG) Log.d(TAG, "mRuleId=" + mRuleId);
if (refreshRuleOrFinish()) {
return;
}
addPreferencesFromResource(R.xml.zen_mode_schedule_rule_settings);
final PreferenceScreen root = getPreferenceScreen();
setHasOptionsMenu(true);
mRuleName = root.findPreference(KEY_RULE_NAME);
mRuleName.setOnPreferenceClickListener(new OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(Preference preference) {
showRuleNameDialog();
return true;
}
});
mDays = root.findPreference(KEY_DAYS);
mDays.setOnPreferenceClickListener(new OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(Preference preference) {
showDaysDialog();
return true;
}
});
final FragmentManager mgr = getFragmentManager();
mStart = new TimePickerPreference(mContext, mgr);
mStart.setKey(KEY_START_TIME);
mStart.setTitle(R.string.zen_mode_start_time);
mStart.setCallback(new TimePickerPreference.Callback() {
@Override
public boolean onSetTime(final int hour, final int minute) {
if (mDisableListeners) return true;
if (!ZenModeConfig.isValidHour(hour)) return false;
if (!ZenModeConfig.isValidMinute(minute)) return false;
if (hour == mSchedule.startHour && minute == mSchedule.startMinute) {
return true;
}
if (DEBUG) Log.d(TAG, "onPrefChange start h=" + hour + " m=" + minute);
mSchedule.startHour = hour;
mSchedule.startMinute = minute;
mRule.conditionId = ZenModeConfig.toScheduleConditionId(mSchedule);
mRule.condition = null;
mRule.snoozing = false;
setZenModeConfig(mConfig);
return true;
}
});
root.addPreference(mStart);
mStart.setDependency(mDays.getKey());
mEnd = new TimePickerPreference(mContext, mgr);
mEnd.setKey(KEY_END_TIME);
mEnd.setTitle(R.string.zen_mode_end_time);
mEnd.setCallback(new TimePickerPreference.Callback() {
@Override
public boolean onSetTime(final int hour, final int minute) {
if (mDisableListeners) return true;
if (!ZenModeConfig.isValidHour(hour)) return false;
if (!ZenModeConfig.isValidMinute(minute)) return false;
if (hour == mSchedule.endHour && minute == mSchedule.endMinute) {
return true;
}
if (DEBUG) Log.d(TAG, "onPrefChange end h=" + hour + " m=" + minute);
mSchedule.startHour = hour;
mSchedule.startMinute = minute;
mRule.conditionId = ZenModeConfig.toScheduleConditionId(mSchedule);
mRule.condition = null;
mRule.snoozing = false;
setZenModeConfig(mConfig);
return true;
}
});
root.addPreference(mEnd);
mEnd.setDependency(mDays.getKey());
mZenMode = (DropDownPreference) root.findPreference(KEY_ZEN_MODE);
mZenMode.addItem(R.string.zen_mode_option_important_interruptions, Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS);
mZenMode.addItem(R.string.zen_mode_option_alarms, Global.ZEN_MODE_ALARMS);
mZenMode.addItem(R.string.zen_mode_option_no_interruptions, Global.ZEN_MODE_NO_INTERRUPTIONS);
mZenMode.setCallback(new DropDownPreference.Callback() {
@Override
public boolean onItemSelected(int pos, Object value) {
if (mDisableListeners) return true;
final int zenMode = (Integer) value;
if (zenMode == mRule.zenMode) return true;
if (DEBUG) Log.d(TAG, "onPrefChange zenMode=" + zenMode);
mRule.zenMode = zenMode;
setZenModeConfig(mConfig);
return true;
}
});
mZenMode.setOrder(10); // sort at the bottom of the category
mZenMode.setDependency(mDays.getKey());
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
final SettingsActivity activity = (SettingsActivity) getActivity();
mSwitchBar = activity.getSwitchBar();
mSwitchBar.addOnSwitchChangeListener(this);
mSwitchBar.show();
}
@Override
public void onDestroyView() {
super.onDestroyView();
mSwitchBar.removeOnSwitchChangeListener(this);
mSwitchBar.hide();
}
@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.enabled) return;
if (DEBUG) Log.d(TAG, "onSwitchChanged enabled=" + enabled);
mRule.enabled = enabled;
mRule.snoozing = false;
setZenModeConfig(mConfig);
}
private void updateDays() {
// Compute an ordered, delimited list of day names based on the persisted user config.
final int[] days = mSchedule.days;
if (days != null && days.length > 0) {
final StringBuilder sb = new StringBuilder();
final Calendar c = Calendar.getInstance();
for (int i = 0; i < DAYS.length; i++) {
final int day = DAYS[i];
for (int j = 0; j < days.length; j++) {
if (day == days[j]) {
c.set(Calendar.DAY_OF_WEEK, day);
if (sb.length() > 0) {
sb.append(mContext.getString(R.string.summary_divider_text));
}
sb.append(DAY_FORMAT.format(c.getTime()));
break;
}
}
}
if (sb.length() > 0) {
mDays.setSummary(sb);
mDays.notifyDependencyChange(false);
return;
}
}
mDays.setSummary(R.string.zen_mode_schedule_rule_days_none);
mDays.notifyDependencyChange(true);
}
private void updateEndSummary() {
final int startMin = 60 * mSchedule.startHour + mSchedule.startMinute;
final int endMin = 60 * mSchedule.endHour + mSchedule.endMinute;
final boolean nextDay = startMin >= endMin;
final int summaryFormat = nextDay ? R.string.zen_mode_end_time_next_day_summary_format : 0;
mEnd.setSummaryFormat(summaryFormat);
}
@Override
public void onResume() {
super.onResume();
updateControls();
}
private void updateRuleName() {
getActivity().setTitle(mRule.name);
mRuleName.setSummary(mRule.name);
}
private void updateControls() {
mDisableListeners = true;
updateRuleName();
updateDays();
mStart.setTime(mSchedule.startHour, mSchedule.startMinute);
mEnd.setTime(mSchedule.endHour, mSchedule.endMinute);
mZenMode.setSelectedValue(mRule.zenMode);
mDisableListeners = false;
updateEndSummary();
if (mSwitchBar != null) {
mSwitchBar.setChecked(mRule.enabled);
}
}
@Override
protected int getMetricsCategory() {
return MetricsLogger.NOTIFICATION_ZEN_MODE_SCHEDULE_RULE;
}
private void showDeleteRuleDialog() {
new AlertDialog.Builder(mContext)
.setMessage(getString(R.string.zen_mode_delete_rule_confirmation, mRule.name))
.setNegativeButton(R.string.cancel, null)
.setPositiveButton(R.string.zen_mode_delete_rule_button, new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
mDeleting = true;
mConfig.automaticRules.remove(mRuleId);
setZenModeConfig(mConfig);
}
})
.show();
}
private void showRuleNameDialog() {
new ZenRuleNameDialog(mContext, mRule.name, mConfig.getAutomaticRuleNames()) {
@Override
public void onOk(String ruleName) {
final ZenModeConfig newConfig = mConfig.copy();
final ZenRule rule = newConfig.automaticRules.get(mRuleId);
if (rule == null) return;
rule.name = ruleName;
setZenModeConfig(newConfig);
}
}.show();
}
private void showDaysDialog() {
new AlertDialog.Builder(mContext)
.setTitle(R.string.zen_mode_schedule_rule_days)
.setView(new ZenModeScheduleDaysSelection(mContext, mSchedule.days) {
@Override
protected void onChanged(final int[] days) {
if (mDisableListeners) return;
if (Arrays.equals(days, mSchedule.days)) return;
if (DEBUG) Log.d(TAG, "days.onChanged days=" + Arrays.asList(days));
mSchedule.days = days;
mRule.conditionId = ZenModeConfig.toScheduleConditionId(mSchedule);
mRule.condition = null;
mRule.snoozing = false;
setZenModeConfig(mConfig);
}
})
.setOnDismissListener(new OnDismissListener() {
@Override
public void onDismiss(DialogInterface dialog) {
updateDays();
}
})
.setPositiveButton(R.string.done_button, null)
.show();
}
private void toastAndFinish() {
if (!mDeleting) {
Toast.makeText(mContext, R.string.zen_mode_rule_not_found_text, Toast.LENGTH_SHORT)
.show();
}
getActivity().finish();
}
private static class TimePickerPreference extends Preference {
private final Context mContext;
private int mSummaryFormat;
private int mHourOfDay;
private int mMinute;
private Callback mCallback;
public TimePickerPreference(Context context, final FragmentManager mgr) {
super(context);
mContext = context;
setPersistent(false);
setOnPreferenceClickListener(new OnPreferenceClickListener(){
@Override
public boolean onPreferenceClick(Preference preference) {
final TimePickerFragment frag = new TimePickerFragment();
frag.pref = TimePickerPreference.this;
frag.show(mgr, TimePickerPreference.class.getName());
return true;
}
});
}
public void setCallback(Callback callback) {
mCallback = callback;
}
public void setSummaryFormat(int resId) {
mSummaryFormat = resId;
updateSummary();
}
public void setTime(int hourOfDay, int minute) {
if (mCallback != null && !mCallback.onSetTime(hourOfDay, minute)) return;
mHourOfDay = hourOfDay;
mMinute = minute;
updateSummary();
}
private void updateSummary() {
final Calendar c = Calendar.getInstance();
c.set(Calendar.HOUR_OF_DAY, mHourOfDay);
c.set(Calendar.MINUTE, mMinute);
String time = DateFormat.getTimeFormat(mContext).format(c.getTime());
if (mSummaryFormat != 0) {
time = mContext.getResources().getString(mSummaryFormat, time);
}
setSummary(time);
}
public static class TimePickerFragment extends DialogFragment implements
TimePickerDialog.OnTimeSetListener {
public TimePickerPreference pref;
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
final boolean usePref = pref != null && pref.mHourOfDay >= 0 && pref.mMinute >= 0;
final Calendar c = Calendar.getInstance();
final int hour = usePref ? pref.mHourOfDay : c.get(Calendar.HOUR_OF_DAY);
final int minute = usePref ? pref.mMinute : c.get(Calendar.MINUTE);
return new TimePickerDialog(getActivity(), this, hour, minute,
DateFormat.is24HourFormat(getActivity()));
}
public void onTimeSet(TimePicker view, int hourOfDay, int minute) {
if (pref != null) {
pref.setTime(hourOfDay, minute);
}
}
}
public interface Callback {
boolean onSetTime(int hour, int minute);
}
}
}

View File

@@ -21,10 +21,12 @@ import android.content.Context;
import android.content.DialogInterface; import android.content.DialogInterface;
import android.content.res.Resources; import android.content.res.Resources;
import android.os.Bundle; import android.os.Bundle;
import android.os.UserHandle;
import android.preference.Preference; import android.preference.Preference;
import android.preference.PreferenceScreen; import android.preference.PreferenceScreen;
import android.provider.Settings.Global; import android.provider.Settings.Global;
import android.service.notification.Condition; import android.service.notification.Condition;
import android.service.notification.ZenModeConfig;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.Log; import android.util.Log;
import android.util.SparseArray; import android.util.SparseArray;
@@ -51,6 +53,7 @@ public class ZenModeSettings extends ZenModeSettingsBase
private AlertDialog mDialog; private AlertDialog mDialog;
private SwitchBar mSwitchBar; private SwitchBar mSwitchBar;
private boolean mShowing; private boolean mShowing;
private boolean mUpdatingControls;
@Override @Override
public void onCreate(Bundle savedInstanceState) { public void onCreate(Bundle savedInstanceState) {
@@ -60,7 +63,7 @@ public class ZenModeSettings extends ZenModeSettingsBase
final PreferenceScreen root = getPreferenceScreen(); final PreferenceScreen root = getPreferenceScreen();
mPrioritySettings = root.findPreference(KEY_PRIORITY_SETTINGS); mPrioritySettings = root.findPreference(KEY_PRIORITY_SETTINGS);
if (!isDowntimeSupported(mContext)) { if (!isScheduleSupported(mContext)) {
removePreference(KEY_AUTOMATION_SETTINGS); removePreference(KEY_AUTOMATION_SETTINGS);
} }
} }
@@ -97,13 +100,14 @@ public class ZenModeSettings extends ZenModeSettingsBase
@Override @Override
public void onSwitchChanged(Switch switchView, boolean isChecked) { public void onSwitchChanged(Switch switchView, boolean isChecked) {
if (DEBUG) Log.d(TAG, "onSwitchChanged " + isChecked + " mShowing=" + mShowing); if (DEBUG) Log.d(TAG, "onSwitchChanged " + isChecked + " mShowing=" + mShowing
if (!mShowing) return; // not from the user + " mUpdatingControls=" + mUpdatingControls);
if (!mShowing || mUpdatingControls) return; // not from the user
if (isChecked) { if (isChecked) {
setZenMode(Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS); setZenMode(Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS, null);
showConditionSelection(Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS); showConditionSelection(Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS);
} else { } else {
setZenMode(Global.ZEN_MODE_OFF); setZenMode(Global.ZEN_MODE_OFF, null);
} }
} }
@@ -135,29 +139,20 @@ public class ZenModeSettings extends ZenModeSettingsBase
} }
} }
private String computeExitConditionText() {
return mConfig == null || mConfig.exitCondition == null
? getString(com.android.internal.R.string.zen_mode_forever)
: computeConditionText(mConfig.exitCondition);
}
public static String computeConditionText(Condition c) {
return !TextUtils.isEmpty(c.line1) ? c.line1
: !TextUtils.isEmpty(c.summary) ? c.summary
: "";
}
private String computeZenModeSummaryLine() { private String computeZenModeSummaryLine() {
final String caption = computeZenModeCaption(mZenMode); final String caption = computeZenModeCaption(mZenMode);
if (caption == null) return null; if (caption == null) return null; // zen mode off
final String conditionText = computeExitConditionText().toLowerCase(); final String conditionText = ZenModeConfig.getConditionLine1(mContext, mConfig,
UserHandle.myUserId());
return getString(R.string.zen_mode_summary_combination, caption, conditionText); return getString(R.string.zen_mode_summary_combination, caption, conditionText);
} }
private void updateControls() { private void updateControls() {
if (mSwitchBar != null) { if (mSwitchBar != null) {
final String summaryLine = computeZenModeSummaryLine(); final String summaryLine = computeZenModeSummaryLine();
mUpdatingControls = true;
mSwitchBar.setChecked(summaryLine != null); mSwitchBar.setChecked(summaryLine != null);
mUpdatingControls = false;
mSwitchBar.setSummary(summaryLine); mSwitchBar.setSummary(summaryLine);
} }
updatePrioritySettingsSummary(); updatePrioritySettingsSummary();
@@ -184,7 +179,7 @@ public class ZenModeSettings extends ZenModeSettingsBase
if (mDialog != null) return; if (mDialog != null) return;
final ZenModeConditionSelection zenModeConditionSelection = final ZenModeConditionSelection zenModeConditionSelection =
new ZenModeConditionSelection(mContext); new ZenModeConditionSelection(mContext, zenMode);
DialogInterface.OnClickListener positiveListener = new DialogInterface.OnClickListener() { DialogInterface.OnClickListener positiveListener = new DialogInterface.OnClickListener() {
@Override @Override
public void onClick(DialogInterface dialog, int which) { public void onClick(DialogInterface dialog, int which) {
@@ -198,7 +193,7 @@ public class ZenModeSettings extends ZenModeSettingsBase
.setTitle(computeZenModeCaption(zenMode)) .setTitle(computeZenModeCaption(zenMode))
.setView(scrollView) .setView(scrollView)
.setPositiveButton(R.string.okay, positiveListener) .setPositiveButton(R.string.okay, positiveListener)
.setNegativeButton(R.string.cancel_all_caps, new DialogInterface.OnClickListener() { .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
@Override @Override
public void onClick(DialogInterface dialog, int which) { public void onClick(DialogInterface dialog, int which) {
cancelDialog(); cancelDialog();
@@ -216,10 +211,16 @@ public class ZenModeSettings extends ZenModeSettingsBase
private void cancelDialog() { private void cancelDialog() {
if (DEBUG) Log.d(TAG, "cancelDialog"); if (DEBUG) Log.d(TAG, "cancelDialog");
// If not making a decision, reset zen to off. // If not making a decision, reset zen to off.
setZenMode(Global.ZEN_MODE_OFF); setZenMode(Global.ZEN_MODE_OFF, null);
mDialog = null; mDialog = null;
} }
public static String computeConditionText(Condition c) {
return !TextUtils.isEmpty(c.line1) ? c.line1
: !TextUtils.isEmpty(c.summary) ? c.summary
: "";
}
private static SparseArray<String> allKeyTitles(Context context) { private static SparseArray<String> allKeyTitles(Context context) {
final SparseArray<String> rt = new SparseArray<String>(); final SparseArray<String> rt = new SparseArray<String>();
rt.put(R.string.zen_mode_priority_settings_title, KEY_PRIORITY_SETTINGS); rt.put(R.string.zen_mode_priority_settings_title, KEY_PRIORITY_SETTINGS);
@@ -250,7 +251,7 @@ public class ZenModeSettings extends ZenModeSettingsBase
@Override @Override
public List<String> getNonIndexableKeys(Context context) { public List<String> getNonIndexableKeys(Context context) {
final ArrayList<String> rt = new ArrayList<String>(); final ArrayList<String> rt = new ArrayList<String>();
if (!isDowntimeSupported(context)) { if (!isScheduleSupported(context)) {
rt.add(KEY_AUTOMATION_SETTINGS); rt.add(KEY_AUTOMATION_SETTINGS);
} }
return rt; return rt;

View File

@@ -16,14 +16,12 @@
package com.android.settings.notification; package com.android.settings.notification;
import android.app.INotificationManager;
import android.app.NotificationManager; import android.app.NotificationManager;
import android.content.Context; import android.content.Context;
import android.database.ContentObserver; import android.database.ContentObserver;
import android.net.Uri; import android.net.Uri;
import android.os.Bundle; import android.os.Bundle;
import android.os.Handler; import android.os.Handler;
import android.os.ServiceManager;
import android.provider.Settings; import android.provider.Settings;
import android.provider.Settings.Global; import android.provider.Settings.Global;
import android.service.notification.ZenModeConfig; import android.service.notification.ZenModeConfig;
@@ -91,40 +89,27 @@ abstract public class ZenModeSettingsBase extends SettingsPreferenceFragment {
} }
protected boolean setZenModeConfig(ZenModeConfig config) { protected boolean setZenModeConfig(ZenModeConfig config) {
final INotificationManager nm = INotificationManager.Stub.asInterface( final String reason = getClass().getSimpleName();
ServiceManager.getService(Context.NOTIFICATION_SERVICE)); final boolean success = NotificationManager.from(mContext).setZenModeConfig(config, reason);
try { if (success) {
final boolean success = nm.setZenModeConfig(config); mConfig = config;
if (success) { if (DEBUG) Log.d(TAG, "Saved mConfig=" + mConfig);
mConfig = config; onZenModeConfigChanged();
if (DEBUG) Log.d(TAG, "Saved mConfig=" + mConfig);
onZenModeConfigChanged();
}
return success;
} catch (Exception e) {
Log.w(TAG, "Error calling NoMan", e);
return false;
} }
return success;
} }
protected void setZenMode(int zenMode) { protected void setZenMode(int zenMode, Uri conditionId) {
Global.putInt(getContentResolver(), Global.ZEN_MODE, zenMode); NotificationManager.from(mContext).setZenMode(zenMode, conditionId, TAG);
} }
protected static boolean isDowntimeSupported(Context context) { protected static boolean isScheduleSupported(Context context) {
return NotificationManager.from(context) return NotificationManager.from(context)
.isSystemConditionProviderEnabled(ZenModeConfig.DOWNTIME_PATH); .isSystemConditionProviderEnabled(ZenModeConfig.SCHEDULE_PATH);
} }
private ZenModeConfig getZenModeConfig() { private ZenModeConfig getZenModeConfig() {
final INotificationManager nm = INotificationManager.Stub.asInterface( return NotificationManager.from(mContext).getZenModeConfig();
ServiceManager.getService(Context.NOTIFICATION_SERVICE));
try {
return nm.getZenModeConfig();
} catch (Exception e) {
Log.w(TAG, "Error calling NoMan", e);
return new ZenModeConfig();
}
} }
private final class SettingsObserver extends ContentObserver { private final class SettingsObserver extends ContentObserver {

View File

@@ -0,0 +1,93 @@
/*
* Copyright (C) 2015 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.content.Context;
import android.content.DialogInterface;
import android.text.Editable;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.util.ArraySet;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.EditText;
import com.android.settings.R;
public abstract class ZenRuleNameDialog {
private final AlertDialog mDialog;
private final EditText mEditText;
private final ArraySet<String> mExistingNames;
public ZenRuleNameDialog(Context context, String ruleName, ArraySet<String> existingNames) {
final View v = LayoutInflater.from(context).inflate(R.layout.zen_rule_name, null, false);
mEditText = (EditText) v.findViewById(R.id.rule_name);
mEditText.setText(ruleName);
mEditText.setSelectAllOnFocus(true);
mDialog = new AlertDialog.Builder(context)
.setTitle(R.string.zen_mode_rule_name)
.setView(v)
.setPositiveButton(R.string.okay, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
onOk(trimmedText());
}
})
.setNegativeButton(R.string.cancel, null)
.create();
mEditText.addTextChangedListener(new TextWatcher() {
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
// noop
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
// noop
}
@Override
public void afterTextChanged(Editable s) {
updatePositiveButton();
}
});
mExistingNames = new ArraySet<String>(existingNames.size());
for (String existingName : existingNames) {
mExistingNames.add(existingName.toLowerCase());
}
}
abstract public void onOk(String ruleName);
private String trimmedText() {
return mEditText.getText() == null ? null : mEditText.getText().toString().trim();
}
public void show() {
mDialog.show();
updatePositiveButton();
}
private void updatePositiveButton() {
final String name = trimmedText();
final boolean validName = !TextUtils.isEmpty(name)
&& !mExistingNames.contains(name.toLowerCase());
mDialog.getButton(DialogInterface.BUTTON_POSITIVE).setEnabled(validName);
}
}

View File

@@ -24,11 +24,12 @@ import com.android.settings.DevelopmentSettings;
import com.android.settings.DeviceInfoSettings; import com.android.settings.DeviceInfoSettings;
import com.android.settings.DisplaySettings; import com.android.settings.DisplaySettings;
import com.android.settings.HomeSettings; import com.android.settings.HomeSettings;
import com.android.settings.ScreenPinningSettings;
import com.android.settings.PrivacySettings; import com.android.settings.PrivacySettings;
import com.android.settings.R; import com.android.settings.R;
import com.android.settings.ScreenPinningSettings;
import com.android.settings.SecuritySettings; import com.android.settings.SecuritySettings;
import com.android.settings.WallpaperTypeSettings; import com.android.settings.WallpaperTypeSettings;
import com.android.settings.WifiCallingSettings;
import com.android.settings.WirelessSettings; import com.android.settings.WirelessSettings;
import com.android.settings.accessibility.AccessibilitySettings; import com.android.settings.accessibility.AccessibilitySettings;
import com.android.settings.applications.AdvancedAppSettings; import com.android.settings.applications.AdvancedAppSettings;
@@ -43,7 +44,6 @@ import com.android.settings.location.ScanningSettings;
import com.android.settings.net.DataUsageMeteredSettings; import com.android.settings.net.DataUsageMeteredSettings;
import com.android.settings.notification.NotificationSettings; import com.android.settings.notification.NotificationSettings;
import com.android.settings.notification.OtherSoundSettings; import com.android.settings.notification.OtherSoundSettings;
import com.android.settings.notification.ZenModeAutomationSettings;
import com.android.settings.notification.ZenModePrioritySettings; import com.android.settings.notification.ZenModePrioritySettings;
import com.android.settings.notification.ZenModeSettings; import com.android.settings.notification.ZenModeSettings;
import com.android.settings.print.PrintSettingsFragment; import com.android.settings.print.PrintSettingsFragment;
@@ -53,7 +53,6 @@ import com.android.settings.voice.VoiceInputSettings;
import com.android.settings.wifi.AdvancedWifiSettings; import com.android.settings.wifi.AdvancedWifiSettings;
import com.android.settings.wifi.SavedAccessPointsWifiSettings; import com.android.settings.wifi.SavedAccessPointsWifiSettings;
import com.android.settings.wifi.WifiSettings; import com.android.settings.wifi.WifiSettings;
import com.android.settings.WifiCallingSettings;
import java.util.Collection; import java.util.Collection;
import java.util.HashMap; import java.util.HashMap;
@@ -171,13 +170,6 @@ public final class SearchIndexableResources {
ZenModePrioritySettings.class.getName(), ZenModePrioritySettings.class.getName(),
R.drawable.ic_settings_notifications)); R.drawable.ic_settings_notifications));
sResMap.put(ZenModeAutomationSettings.class.getName(),
new SearchIndexableResource(
Ranking.getRankForClassName(ZenModeAutomationSettings.class.getName()),
NO_DATA_RES_ID,
ZenModeAutomationSettings.class.getName(),
R.drawable.ic_settings_notifications));
sResMap.put(Memory.class.getName(), sResMap.put(Memory.class.getName(),
new SearchIndexableResource( new SearchIndexableResource(
Ranking.getRankForClassName(Memory.class.getName()), Ranking.getRankForClassName(Memory.class.getName()),