diff options
| author | 2014-07-07 23:27:07 +0000 | |
|---|---|---|
| committer | 2014-07-02 20:00:08 +0000 | |
| commit | 5a19b1c75390881a13dc06e942cf5c9992650c1f (patch) | |
| tree | 5ff2dde4bdd00fb98e74ac5a9956364e87a8c456 | |
| parent | 032fb0a2a221c7912ab7f425da7819b1767d50c8 (diff) | |
| parent | ae641c9ccd3f81214cee54a5f13804f1765187ad (diff) | |
Merge "Implement new volume UI design."
40 files changed, 822 insertions, 648 deletions
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 01e1f8a9c00f..206b75d88e9c 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -6190,18 +6190,21 @@ public final class Settings { "lock_screen_show_notifications"; /** - * Defines global zen mode. ZEN_MODE_OFF or ZEN_MODE_ON. + * Defines global zen mode. ZEN_MODE_OFF, ZEN_MODE_IMPORTANT_INTERRUPTIONS, + * or ZEN_MODE_NO_INTERRUPTIONS. * * @hide */ public static final String ZEN_MODE = "zen_mode"; /** @hide */ public static final int ZEN_MODE_OFF = 0; - /** @hide */ public static final int ZEN_MODE_ON = 1; + /** @hide */ public static final int ZEN_MODE_IMPORTANT_INTERRUPTIONS = 1; + /** @hide */ public static final int ZEN_MODE_NO_INTERRUPTIONS = 2; /** @hide */ public static String zenModeToString(int mode) { - if (mode == ZEN_MODE_OFF) return "ZEN_MODE_OFF"; - return "ZEN_MODE_ON"; + if (mode == ZEN_MODE_IMPORTANT_INTERRUPTIONS) return "ZEN_MODE_IMPORTANT_INTERRUPTIONS"; + if (mode == ZEN_MODE_NO_INTERRUPTIONS) return "ZEN_MODE_NO_INTERRUPTIONS"; + return "ZEN_MODE_OFF"; } /** diff --git a/core/java/android/service/notification/ZenModeConfig.java b/core/java/android/service/notification/ZenModeConfig.java index 68a3d30b7e91..8fc3c5a28203 100644 --- a/core/java/android/service/notification/ZenModeConfig.java +++ b/core/java/android/service/notification/ZenModeConfig.java @@ -30,6 +30,7 @@ import org.xmlpull.v1.XmlSerializer; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; +import java.util.Calendar; import java.util.Objects; /** @@ -42,12 +43,18 @@ public class ZenModeConfig implements Parcelable { public static final String SLEEP_MODE_NIGHTS = "nights"; public static final String SLEEP_MODE_WEEKNIGHTS = "weeknights"; + public static final String SLEEP_MODE_DAYS_PREFIX = "days:"; public static final int SOURCE_ANYONE = 0; public static final int SOURCE_CONTACT = 1; public static final int SOURCE_STAR = 2; public static final int MAX_SOURCE = SOURCE_STAR; + public static final int[] ALL_DAYS = { Calendar.SUNDAY, Calendar.MONDAY, Calendar.TUESDAY, + Calendar.WEDNESDAY, Calendar.THURSDAY, Calendar.FRIDAY, Calendar.SATURDAY }; + public static final int[] WEEKNIGHT_DAYS = { Calendar.SUNDAY, Calendar.MONDAY, Calendar.TUESDAY, + Calendar.WEDNESDAY, Calendar.THURSDAY }; + private static final int XML_VERSION = 1; private static final String ZEN_TAG = "zen"; private static final String ZEN_ATT_VERSION = "version"; @@ -198,8 +205,39 @@ public class ZenModeConfig implements Parcelable { public boolean isValid() { return isValidHour(sleepStartHour) && isValidMinute(sleepStartMinute) && isValidHour(sleepEndHour) && isValidMinute(sleepEndMinute) - && (sleepMode == null || sleepMode.equals(SLEEP_MODE_NIGHTS) - || sleepMode.equals(SLEEP_MODE_WEEKNIGHTS)); + && isValidSleepMode(sleepMode); + } + + public static boolean isValidSleepMode(String sleepMode) { + return sleepMode == null || sleepMode.equals(SLEEP_MODE_NIGHTS) + || sleepMode.equals(SLEEP_MODE_WEEKNIGHTS) || tryParseDays(sleepMode) != null; + } + + public static int[] tryParseDays(String sleepMode) { + if (sleepMode == null) return null; + sleepMode = sleepMode.trim(); + if (SLEEP_MODE_NIGHTS.equals(sleepMode)) return ALL_DAYS; + if (SLEEP_MODE_WEEKNIGHTS.equals(sleepMode)) return WEEKNIGHT_DAYS; + if (!sleepMode.startsWith(SLEEP_MODE_DAYS_PREFIX)) return null; + if (sleepMode.equals(SLEEP_MODE_DAYS_PREFIX)) return null; + final String[] tokens = sleepMode.substring(SLEEP_MODE_DAYS_PREFIX.length()).split(","); + if (tokens.length == 0) return null; + final int[] rt = new int[tokens.length]; + for (int i = 0; i < tokens.length; i++) { + final int day = tryParseInt(tokens[i], -1); + if (day == -1) return null; + rt[i] = day; + } + return rt; + } + + private static int tryParseInt(String value, int defValue) { + if (TextUtils.isEmpty(value)) return defValue; + try { + return Integer.valueOf(value); + } catch (NumberFormatException e) { + return defValue; + } } public static ZenModeConfig readXml(XmlPullParser parser) @@ -209,7 +247,7 @@ public class ZenModeConfig implements Parcelable { String tag = parser.getName(); if (!ZEN_TAG.equals(tag)) return null; final ZenModeConfig rt = new ZenModeConfig(); - final int version = Integer.parseInt(parser.getAttributeValue(null, ZEN_ATT_VERSION)); + final int version = safeInt(parser, ZEN_ATT_VERSION, XML_VERSION); final ArrayList<ComponentName> conditionComponents = new ArrayList<ComponentName>(); final ArrayList<Uri> conditionIds = new ArrayList<Uri>(); while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) { @@ -232,8 +270,7 @@ public class ZenModeConfig implements Parcelable { } } else if (SLEEP_TAG.equals(tag)) { final String mode = parser.getAttributeValue(null, SLEEP_ATT_MODE); - rt.sleepMode = (SLEEP_MODE_NIGHTS.equals(mode) - || SLEEP_MODE_WEEKNIGHTS.equals(mode)) ? mode : null; + rt.sleepMode = isValidSleepMode(mode)? mode : null; final int startHour = safeInt(parser, SLEEP_ATT_START_HR, 0); final int startMinute = safeInt(parser, SLEEP_ATT_START_MIN, 0); final int endHour = safeInt(parser, SLEEP_ATT_END_HR, 0); @@ -312,8 +349,7 @@ public class ZenModeConfig implements Parcelable { private static int safeInt(XmlPullParser parser, String att, int defValue) { final String val = parser.getAttributeValue(null, att); - if (TextUtils.isEmpty(val)) return defValue; - return Integer.valueOf(val); + return tryParseInt(val, defValue); } private static ComponentName safeComponentName(XmlPullParser parser, String att) { diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java index 153ee31a0c93..f262390ae3e8 100644 --- a/media/java/android/media/AudioService.java +++ b/media/java/android/media/AudioService.java @@ -109,12 +109,12 @@ public class AudioService extends IAudioService.Stub { private static final String TAG = "AudioService"; /** Debug remote control client/display feature */ - protected static final boolean DEBUG_RC = false; + protected static final boolean DEBUG_RC = Log.isLoggable(TAG + ".RC", Log.DEBUG); /** Debug volumes */ - protected static final boolean DEBUG_VOL = false; + protected static final boolean DEBUG_VOL = Log.isLoggable(TAG + ".VOL", Log.DEBUG); /** debug calls to media session apis */ - private static final boolean DEBUG_SESSIONS = true; + private static final boolean DEBUG_SESSIONS = Log.isLoggable(TAG + ".SESSIONS", Log.DEBUG); /** Allow volume changes to set ringer mode to silent? */ private static final boolean VOLUME_SETS_RINGER_MODE_SILENT = false; @@ -841,7 +841,8 @@ public class AudioService extends IAudioService.Stub { /** @see AudioManager#adjustVolume(int, int) */ public void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags, String callingPackage) { - if (DEBUG_VOL) Log.d(TAG, "adjustSuggestedStreamVolume() stream="+suggestedStreamType); + if (DEBUG_VOL) Log.d(TAG, "adjustSuggestedStreamVolume() stream="+suggestedStreamType + + ", flags=" + flags); int streamType; if (mVolumeControlStream != -1) { streamType = mVolumeControlStream; @@ -871,7 +872,8 @@ public class AudioService extends IAudioService.Stub { if (mUseFixedVolume) { return; } - if (DEBUG_VOL) Log.d(TAG, "adjustStreamVolume() stream="+streamType+", dir="+direction); + if (DEBUG_VOL) Log.d(TAG, "adjustStreamVolume() stream="+streamType+", dir="+direction + + ", flags="+flags); ensureValidDirection(direction); ensureValidStreamType(streamType); diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardViewBase.java b/packages/Keyguard/src/com/android/keyguard/KeyguardViewBase.java index 737e49bde123..276f79590c19 100644 --- a/packages/Keyguard/src/com/android/keyguard/KeyguardViewBase.java +++ b/packages/Keyguard/src/com/android/keyguard/KeyguardViewBase.java @@ -67,7 +67,7 @@ public abstract class KeyguardViewBase extends FrameLayout implements SecurityCa // Whether the volume keys should be handled by keyguard. If true, then // they will be handled here for specific media types such as music, otherwise // the audio service will bring up the volume dialog. - private static final boolean KEYGUARD_MANAGES_VOLUME = true; + private static final boolean KEYGUARD_MANAGES_VOLUME = false; public static final boolean DEBUG = KeyguardConstants.DEBUG; private static final String TAG = "KeyguardViewBase"; diff --git a/packages/SystemUI/res/color/segmented_button_text_selector.xml b/packages/SystemUI/res/color/segmented_button_text_selector.xml new file mode 100644 index 000000000000..13c616990afc --- /dev/null +++ b/packages/SystemUI/res/color/segmented_button_text_selector.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + 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. ?android:attr/colorControlHighlight" +--> + +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + + <item android:state_selected="true" android:color="@android:color/white"/> + <item android:color="@color/segmented_button_text_inactive"/> + +</selector>
\ No newline at end of file diff --git a/packages/SystemUI/res/drawable/ic_qs_minus.xml b/packages/SystemUI/res/drawable/ic_qs_minus.xml index 376cc28b4148..7b76e0f4d56e 100644 --- a/packages/SystemUI/res/drawable/ic_qs_minus.xml +++ b/packages/SystemUI/res/drawable/ic_qs_minus.xml @@ -15,14 +15,14 @@ Copyright (C) 2014 The Android Open Source Project --> <vector xmlns:android="http://schemas.android.com/apk/res/android" > <size - android:width="64dp" - android:height="64dp"/> + android:width="24dp" + android:height="24dp"/> <viewport - android:viewportWidth="24.0" - android:viewportHeight="24.0"/> + android:viewportWidth="48.0" + android:viewportHeight="48.0"/> <path android:fill="#FFFFFFFF" - android:pathData="M7.0,11.0l0.0,2.0l10.0,0.0l0.0,-2.0L7.0,11.0zM12.0,2.0C6.5,2.0 2.0,6.5 2.0,12.0s4.5,10.0 10.0,10.0c5.5,0.0 10.0,-4.5 10.0,-10.0S17.5,2.0 12.0,2.0zM12.0,20.0c-4.4,0.0 -8.0,-3.6 -8.0,-8.0s3.6,-8.0 8.0,-8.0c4.4,0.0 8.0,3.6 8.0,8.0S16.4,20.0 12.0,20.0z"/> + android:pathData="M24.0,4.0C13.0,4.0 4.0,13.0 4.0,24.0s9.0,20.0 20.0,20.0c11.0,0.0 20.0,-9.0 20.0,-20.0S35.0,4.0 24.0,4.0zM34.0,26.0L14.0,26.0l0.0,-4.0l20.0,0.0L34.0,26.0z"/> </vector> diff --git a/packages/SystemUI/res/drawable/ic_qs_plus.xml b/packages/SystemUI/res/drawable/ic_qs_plus.xml index a315f7f5ff2f..4b9f5062a993 100644 --- a/packages/SystemUI/res/drawable/ic_qs_plus.xml +++ b/packages/SystemUI/res/drawable/ic_qs_plus.xml @@ -15,14 +15,14 @@ Copyright (C) 2014 The Android Open Source Project --> <vector xmlns:android="http://schemas.android.com/apk/res/android" > <size - android:width="64dp" - android:height="64dp"/> + android:width="24dp" + android:height="24dp"/> <viewport - android:viewportWidth="24.0" - android:viewportHeight="24.0"/> + android:viewportWidth="48.0" + android:viewportHeight="48.0"/> <path android:fill="#FFFFFFFF" - android:pathData="M13.0,7.0l-2.0,0.0l0.0,4.0L7.0,11.0l0.0,2.0l4.0,0.0l0.0,4.0l2.0,0.0l0.0,-4.0l4.0,0.0l0.0,-2.0l-4.0,0.0L13.0,7.0zM12.0,2.0C6.5,2.0 2.0,6.5 2.0,12.0s4.5,10.0 10.0,10.0c5.5,0.0 10.0,-4.5 10.0,-10.0S17.5,2.0 12.0,2.0zM12.0,20.0c-4.4,0.0 -8.0,-3.6 -8.0,-8.0s3.6,-8.0 8.0,-8.0c4.4,0.0 8.0,3.6 8.0,8.0S16.4,20.0 12.0,20.0z"/> + android:pathData="M24.0,4.0C13.0,4.0 4.0,13.0 4.0,24.0s9.0,20.0 20.0,20.0c11.0,0.0 20.0,-9.0 20.0,-20.0S35.0,4.0 24.0,4.0zM34.0,26.0l-8.0,0.0l0.0,8.0l-4.0,0.0l0.0,-8.0l-8.0,0.0l0.0,-4.0l8.0,0.0l0.0,-8.0l4.0,0.0l0.0,8.0l8.0,0.0L34.0,26.0z"/> </vector> diff --git a/packages/SystemUI/res/drawable/ic_ringer_silent.xml b/packages/SystemUI/res/drawable/ic_ringer_silent.xml index b5837f65cecf..46b94e844e4d 100644 --- a/packages/SystemUI/res/drawable/ic_ringer_silent.xml +++ b/packages/SystemUI/res/drawable/ic_ringer_silent.xml @@ -23,6 +23,6 @@ Copyright (C) 2014 The Android Open Source Project android:viewportHeight="24.0"/> <path - android:fill="#FFFFFFFF" + android:fill="@color/qs_subhead" android:pathData="M11.5,22.0c1.1,0.0 2.0,-0.9 2.0,-2.0l-4.0,0.0C9.5,21.1 10.4,22.0 11.5,22.0zM18.0,10.5c0.0,-3.1 -2.1,-5.6 -5.0,-6.3L13.0,3.5C13.0,2.7 12.3,2.0 11.5,2.0C10.7,2.0 10.0,2.7 10.0,3.5l0.0,0.7C9.5,4.3 9.0,4.5 8.6,4.7l9.4,9.4L18.0,10.5zM17.7,19.0l2.0,2.0l1.3,-1.3L4.3,3.0L3.0,4.3l2.9,2.9C5.3,8.2 5.0,9.3 5.0,10.5L5.0,16.0l-2.0,2.0l0.0,1.0L17.7,19.0z" /> </vector> diff --git a/packages/SystemUI/res/drawable/ic_vol_zen_off.xml b/packages/SystemUI/res/drawable/ic_vol_zen_off.xml deleted file mode 100644 index 477c36b67a9d..000000000000 --- a/packages/SystemUI/res/drawable/ic_vol_zen_off.xml +++ /dev/null @@ -1,28 +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. ---> -<vector xmlns:android="http://schemas.android.com/apk/res/android" > - <size - android:width="32dp" - android:height="32dp"/> - - <viewport - android:viewportWidth="48.0" - android:viewportHeight="48.0"/> - - <path - android:fill="#4DFFFFFF" - android:pathData="M4.0,24.0c0.0,11.0 9.0,20.0 20.0,20.0s20.0,-9.0 20.0,-20.0S35.0,4.0 24.0,4.0S4.0,13.0 4.0,24.0zM36.6,33.8L14.2,11.4C16.9,9.3 20.3,8.0 24.0,8.0c8.8,0.0 16.0,7.2 16.0,16.0C40.0,27.7 38.7,31.1 36.6,33.8zM8.0,24.0c0.0,-3.7 1.3,-7.1 3.4,-9.8L33.8,36.6C31.1,38.7 27.7,40.0 24.0,40.0C15.2,40.0 8.0,32.8 8.0,24.0z"/> -</vector> diff --git a/packages/SystemUI/res/drawable/ic_qs_zen_on.xml b/packages/SystemUI/res/drawable/qs_subhead_caret.xml index 4887b3211ee6..f140bd0adda4 100644 --- a/packages/SystemUI/res/drawable/ic_qs_zen_on.xml +++ b/packages/SystemUI/res/drawable/qs_subhead_caret.xml @@ -15,14 +15,14 @@ Copyright (C) 2014 The Android Open Source Project --> <vector xmlns:android="http://schemas.android.com/apk/res/android" > <size - android:width="64dp" - android:height="64dp"/> + android:width="24.0dp" + android:height="24.0dp"/> <viewport android:viewportWidth="48.0" android:viewportHeight="48.0"/> <path - android:fill="#FFFFFFFF" - android:pathData="M4.0,24.0c0.0,11.0 9.0,20.0 20.0,20.0s20.0,-9.0 20.0,-20.0S35.0,4.0 24.0,4.0S4.0,13.0 4.0,24.0zM36.6,33.8L14.2,11.4C16.9,9.3 20.3,8.0 24.0,8.0c8.8,0.0 16.0,7.2 16.0,16.0C40.0,27.7 38.7,31.1 36.6,33.8zM8.0,24.0c0.0,-3.7 1.3,-7.1 3.4,-9.8L33.8,36.6C31.1,38.7 27.7,40.0 24.0,40.0C15.2,40.0 8.0,32.8 8.0,24.0z"/> + android:fill="@color/qs_subhead" + android:pathData="M14.0,20.0l10.0,10.0 10.0,-10.0z"/> </vector> diff --git a/packages/SystemUI/res/drawable/segmented_button.xml b/packages/SystemUI/res/drawable/segmented_button.xml new file mode 100644 index 000000000000..966998518cc6 --- /dev/null +++ b/packages/SystemUI/res/drawable/segmented_button.xml @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + 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. +--> +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:state_selected="true"> + <shape android:shape="rectangle"> + <solid android:color="@color/segmented_button_selected" /> + <corners android:radius="@dimen/segmented_button_radius" /> + </shape> + </item> + <item> + <ripple android:color="@color/segmented_button_selected" /> + </item> +</selector>
\ No newline at end of file diff --git a/packages/SystemUI/res/drawable/segmented_buttons.xml b/packages/SystemUI/res/drawable/segmented_buttons.xml new file mode 100644 index 000000000000..bfbac971b8da --- /dev/null +++ b/packages/SystemUI/res/drawable/segmented_buttons.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + 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. +--> +<shape xmlns:android="http://schemas.android.com/apk/res/android" + android:shape="rectangle" > + <solid android:color="@color/segmented_button_background" /> + <corners android:radius="@dimen/segmented_button_radius" /> +</shape>
\ No newline at end of file diff --git a/packages/SystemUI/res/drawable/stat_sys_ringer_zen.xml b/packages/SystemUI/res/drawable/stat_sys_ringer_zen.xml deleted file mode 100644 index 59924709016c..000000000000 --- a/packages/SystemUI/res/drawable/stat_sys_ringer_zen.xml +++ /dev/null @@ -1,28 +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. ---> -<vector xmlns:android="http://schemas.android.com/apk/res/android" > - <size - android:width="18dp" - android:height="18dp"/> - - <viewport - android:viewportWidth="48.0" - android:viewportHeight="48.0"/> - - <path - android:fill="#FFFFFFFF" - android:pathData="M4.0,24.0c0.0,11.0 9.0,20.0 20.0,20.0s20.0,-9.0 20.0,-20.0S35.0,4.0 24.0,4.0S4.0,13.0 4.0,24.0zM36.6,33.8L14.2,11.4C16.9,9.3 20.3,8.0 24.0,8.0c8.8,0.0 16.0,7.2 16.0,16.0C40.0,27.7 38.7,31.1 36.6,33.8zM8.0,24.0c0.0,-3.7 1.3,-7.1 3.4,-9.8L33.8,36.6C31.1,38.7 27.7,40.0 24.0,40.0C15.2,40.0 8.0,32.8 8.0,24.0z"/> -</vector> diff --git a/packages/SystemUI/res/drawable/ic_vol_zen_on.xml b/packages/SystemUI/res/drawable/stat_sys_zen_important.xml index 0a43a7b2f341..54a9b1b61a36 100644 --- a/packages/SystemUI/res/drawable/ic_vol_zen_on.xml +++ b/packages/SystemUI/res/drawable/stat_sys_zen_important.xml @@ -15,14 +15,14 @@ Copyright (C) 2014 The Android Open Source Project --> <vector xmlns:android="http://schemas.android.com/apk/res/android" > <size - android:width="32dp" - android:height="32dp"/> + android:width="20dp" + android:height="20dp"/> <viewport - android:viewportWidth="48.0" - android:viewportHeight="48.0"/> + android:viewportWidth="24.0" + android:viewportHeight="24.0"/> <path android:fill="#FFFFFFFF" - android:pathData="M4.0,24.0c0.0,11.0 9.0,20.0 20.0,20.0s20.0,-9.0 20.0,-20.0S35.0,4.0 24.0,4.0S4.0,13.0 4.0,24.0zM36.6,33.8L14.2,11.4C16.9,9.3 20.3,8.0 24.0,8.0c8.8,0.0 16.0,7.2 16.0,16.0C40.0,27.7 38.7,31.1 36.6,33.8zM8.0,24.0c0.0,-3.7 1.3,-7.1 3.4,-9.8L33.8,36.6C31.1,38.7 27.7,40.0 24.0,40.0C15.2,40.0 8.0,32.8 8.0,24.0z"/> + android:pathData="M12.0,17.273l6.1800003,3.7269993 -1.6350002,-7.0290003 5.455,-4.7269993 -7.191,-0.6170006 -2.809,-6.627 -2.809,6.627 -7.191,0.6170006 5.455,4.7269993 -1.6349998,7.0290003z"/> </vector> diff --git a/packages/SystemUI/res/layout/segmented_button.xml b/packages/SystemUI/res/layout/segmented_button.xml new file mode 100644 index 000000000000..ef782209fd8b --- /dev/null +++ b/packages/SystemUI/res/layout/segmented_button.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + 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. +--> +<Button xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_marginStart="@dimen/segmented_button_spacing" + android:layout_weight="1" + android:textColor="@color/segmented_button_text_selector" + android:background="@drawable/segmented_button" + android:textAppearance="@style/TextAppearance.QS.SegmentedButton" + android:minHeight="0dp" + android:padding="12dp" /> diff --git a/packages/SystemUI/res/layout/volume_dialog.xml b/packages/SystemUI/res/layout/volume_dialog.xml index 5afa96713a2b..7bd0aea6c312 100644 --- a/packages/SystemUI/res/layout/volume_dialog.xml +++ b/packages/SystemUI/res/layout/volume_dialog.xml @@ -15,11 +15,11 @@ limitations under the License. --> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="match_parent" + android:layout_width="@dimen/volume_panel_width" android:layout_height="wrap_content" android:background="@drawable/qs_panel_background" android:translationZ="@dimen/volume_panel_z" - android:layout_margin="@dimen/volume_panel_z"> + android:layout_marginBottom="@dimen/volume_panel_z"> <include layout="@layout/volume_panel" /> diff --git a/packages/SystemUI/res/layout/volume_panel.xml b/packages/SystemUI/res/layout/volume_panel.xml index 046862f985ee..b377a066d2a3 100644 --- a/packages/SystemUI/res/layout/volume_panel.xml +++ b/packages/SystemUI/res/layout/volume_panel.xml @@ -14,55 +14,23 @@ See the License for the specific language governing permissions and limitations under the License. --> -<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/visible_panel" android:layout_width="match_parent" android:layout_height="wrap_content" - android:orientation="horizontal" > + android:orientation="vertical" > <FrameLayout android:id="@+id/slider_panel" android:layout_width="match_parent" android:layout_height="wrap_content" - android:minHeight="64dip" - android:layout_toLeftOf="@+id/expand_button_divider" /> + android:clipChildren="false" /> - <ImageView - android:id="@+id/expand_button_divider" - android:layout_width="wrap_content" - android:layout_height="32dip" - android:layout_gravity="top" - android:layout_marginBottom="16dip" - android:layout_marginTop="16dip" - android:layout_toLeftOf="@+id/expand_button" - android:scaleType="fitXY" - android:src="?android:attr/dividerVertical" /> - - <ImageView - android:id="@+id/expand_button" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_alignParentRight="true" - android:layout_gravity="top" - style="@style/BorderlessButton.Tiny" - android:padding="16dip" /> - - <ImageView - android:id="@+id/zen_panel_divider" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_below="@+id/slider_panel" - android:layout_marginLeft="16dip" - android:layout_marginRight="16dip" - android:scaleType="fitXY" - android:src="?android:attr/dividerHorizontal" /> - - <ViewStub + <ViewStub android:id="@+id/zen_panel_stub" - android:layout_below="@+id/zen_panel_divider" - android:inflatedId="@+id/zen_panel" android:layout_width="match_parent" android:layout_height="wrap_content" + android:inflatedId="@+id/zen_panel" android:layout="@layout/zen_mode_panel" /> -</RelativeLayout> +</LinearLayout>
\ No newline at end of file diff --git a/packages/SystemUI/res/layout/volume_panel_item.xml b/packages/SystemUI/res/layout/volume_panel_item.xml index 6e5ab47849e7..d91e2abe2b5e 100644 --- a/packages/SystemUI/res/layout/volume_panel_item.xml +++ b/packages/SystemUI/res/layout/volume_panel_item.xml @@ -1,5 +1,6 @@ <?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2011 The Android Open Source Project +<!-- + Copyright (C) 2011 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. @@ -15,33 +16,29 @@ --> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="match_parent" - android:layout_height="80dip" - android:orientation="horizontal" - android:layout_marginTop="8dip" - android:layout_marginBottom="8dip" - android:gravity="start|center_vertical"> + android:layout_width="match_parent" + android:clipChildren="false" + android:gravity="start|center_vertical" + android:orientation="horizontal" > <ImageView - android:id="@+id/stream_icon" - style="@style/BorderlessButton.Tiny" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:padding="16dip" - android:contentDescription="@null" /> - <FrameLayout - android:id="@+id/seekbar_container" - android:layout_width="0dp" - android:layout_height="wrap_content" - android:layout_weight="1"> - <SeekBar - android:id="@+id/seekbar" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:paddingTop="16dip" - android:paddingBottom="16dip" - android:paddingStart="11dip" - android:paddingEnd="11dip" - android:layout_marginEnd="16dip" /> - </FrameLayout> -</LinearLayout> + android:id="@+id/stream_icon" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:contentDescription="@null" + android:paddingBottom="12dip" + android:paddingLeft="16dip" + android:paddingRight="16dip" + android:paddingTop="12dip" /> + + <SeekBar + android:id="@+id/seekbar" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_weight="1" + android:paddingBottom="0dip" + android:paddingEnd="17dip" + android:paddingStart="0dip" + android:paddingTop="0dip" /> + +</LinearLayout>
\ No newline at end of file diff --git a/packages/SystemUI/res/layout/zen_mode_condition.xml b/packages/SystemUI/res/layout/zen_mode_condition.xml index 6ab8cf3f4666..852a8217ee1b 100644 --- a/packages/SystemUI/res/layout/zen_mode_condition.xml +++ b/packages/SystemUI/res/layout/zen_mode_condition.xml @@ -16,22 +16,23 @@ --> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" - android:layout_height="wrap_content" + android:layout_height="@dimen/qs_detail_item_height" android:layout_marginLeft="@dimen/zen_mode_condition_detail_button_padding" - android:layout_marginRight="@dimen/zen_mode_condition_detail_button_padding" > + android:layout_marginRight="@dimen/qs_panel_padding" > <RadioButton android:id="@android:id/checkbox" android:layout_width="40dp" android:layout_marginStart="2dp" - android:layout_height="@dimen/zen_mode_condition_height" + android:layout_marginEnd="1dp" + android:layout_height="match_parent" android:layout_alignParentStart="true" android:gravity="center" /> <TextView android:id="@android:id/title" android:layout_width="match_parent" - android:layout_height="@dimen/zen_mode_condition_height" + android:layout_height="match_parent" android:layout_toEndOf="@android:id/checkbox" android:layout_toStartOf="@android:id/button1" android:ellipsize="end" @@ -42,24 +43,24 @@ <ImageView android:id="@android:id/button1" style="@style/QSBorderlessButton" - android:layout_width="@dimen/zen_mode_condition_height" - android:layout_height="@dimen/zen_mode_condition_height" - android:layout_alignParentEnd="true" + android:layout_width="32dp" + android:layout_height="32dp" android:layout_centerVertical="true" - android:layout_marginEnd="@dimen/zen_mode_condition_height" + android:layout_marginEnd="@dimen/qs_panel_padding" + android:scaleType="center" + android:layout_toStartOf="@android:id/button2" android:contentDescription="@string/accessibility_quick_settings_less_time" - android:padding="@dimen/zen_mode_condition_detail_button_padding" android:src="@drawable/ic_qs_minus" /> <ImageView android:id="@android:id/button2" style="@style/QSBorderlessButton" - android:layout_width="@dimen/zen_mode_condition_height" - android:layout_height="@dimen/zen_mode_condition_height" + android:layout_width="32dp" + android:layout_height="32dp" android:layout_alignParentEnd="true" + android:scaleType="center" android:layout_centerVertical="true" android:contentDescription="@string/accessibility_quick_settings_more_time" - android:padding="@dimen/zen_mode_condition_detail_button_padding" android:src="@drawable/ic_qs_plus" /> </RelativeLayout>
\ No newline at end of file diff --git a/packages/SystemUI/res/layout/zen_mode_panel.xml b/packages/SystemUI/res/layout/zen_mode_panel.xml index 0420cbc2b81b..9d959fa15e7b 100644 --- a/packages/SystemUI/res/layout/zen_mode_panel.xml +++ b/packages/SystemUI/res/layout/zen_mode_panel.xml @@ -19,36 +19,75 @@ android:id="@+id/zen_mode_panel" android:layout_width="match_parent" android:layout_height="wrap_content" - android:background="@color/system_primary_color" + android:background="@drawable/qs_panel_background" + android:clipChildren="false" android:orientation="vertical" - android:paddingTop="@dimen/qs_panel_padding" > + android:paddingBottom="@dimen/qs_panel_padding" > - <TextView - android:id="@android:id/title" - android:layout_width="wrap_content" + <com.android.systemui.volume.SegmentedButtons + android:id="@+id/zen_buttons" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginLeft="@dimen/qs_panel_padding" + android:layout_marginRight="@dimen/qs_panel_padding" + android:layout_marginTop="8dp" + android:background="@drawable/segmented_buttons" + android:clipChildren="false" /> + + <FrameLayout + android:id="@+id/zen_subhead" + android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_alignParentStart="true" - android:layout_marginBottom="8dp" - android:layout_marginStart="@dimen/qs_panel_padding" - android:layout_marginEnd="@dimen/qs_panel_padding" - android:text="@string/zen_mode_title" - android:textAppearance="@style/TextAppearance.QS.DetailItemPrimary" /> + android:paddingLeft="@dimen/qs_panel_padding" + android:paddingRight="@dimen/qs_panel_padding" + android:paddingTop="@dimen/qs_panel_padding" > + + <TextView + android:id="@+id/zen_subhead_collapsed" + android:layout_width="wrap_content" + android:layout_height="32dp" + android:background="@drawable/btn_borderless_rect" + android:clickable="true" + android:drawableEnd="@drawable/qs_subhead_caret" + android:gravity="center_vertical" + android:textAppearance="@style/TextAppearance.QS.Subhead" /> + + <TextView + android:id="@+id/zen_subhead_expanded" + android:layout_width="wrap_content" + android:layout_height="32dp" + android:clickable="true" + android:gravity="center_vertical" + android:textAppearance="@style/TextAppearance.QS.Subhead" /> + + <ImageView + android:id="@+id/zen_more_settings" + android:layout_width="32dp" + android:layout_height="32dp" + android:layout_gravity="end" + android:background="@drawable/btn_borderless_rect" + android:clickable="true" + android:contentDescription="@null" + android:scaleType="center" + android:src="@drawable/ic_settings_24dp" /> + </FrameLayout> <LinearLayout - android:id="@android:id/content" + android:id="@+id/zen_conditions" android:layout_width="match_parent" android:layout_height="wrap_content" - android:orientation="vertical" /> + android:orientation="vertical" + android:paddingTop="3dp" /> <TextView - android:id="@android:id/button2" - style="@style/QSBorderlessButton" - android:layout_width="wrap_content" + android:id="@+id/zen_alarm_warning" + android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_alignParentEnd="true" - android:layout_marginEnd="4dp" - android:layout_gravity="end" - android:text="@string/quick_settings_more_settings" - android:textAppearance="@style/TextAppearance.QS.DetailButton" /> + android:paddingBottom="8dp" + android:paddingLeft="@dimen/qs_panel_padding" + android:paddingRight="@dimen/qs_panel_padding" + android:paddingTop="8dp" + android:text="@string/zen_alarm_warning" + android:textAppearance="@style/TextAppearance.QS.Warning" /> </com.android.systemui.volume.ZenModePanel>
\ No newline at end of file diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml index a93768b86a08..a3a6a55463f3 100644 --- a/packages/SystemUI/res/values/colors.xml +++ b/packages/SystemUI/res/values/colors.xml @@ -40,6 +40,7 @@ <color name="system_error_color">#fff0592b</color> <color name="qs_tile_divider">#29ffffff</color><!-- 16% white --> <color name="qs_tile_text">#B3FFFFFF</color><!-- 70% white --> + <color name="qs_subhead">#66FFFFFF</color><!-- 40% white --> <color name="status_bar_clock_color">#FFFFFFFF</color> <!-- Tint color for the content on the notification overflow card. --> @@ -85,4 +86,8 @@ <color name="primary_color">#ff7fcac3</color> <color name="background_color_1">#ff384248</color> <color name="background_color_1_press">#ff54656e</color> + + <color name="segmented_button_selected">#ff3d4549</color><!-- #33afbdc4 = 20% #afbdc4 = #ff3d4549 composite --> + <color name="segmented_button_background">#ff21272b</color> + <color name="segmented_button_text_inactive">#b3afbdc4</color><!-- 70% --> </resources> diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml index 2737f7e57f26..5c7dc9083121 100644 --- a/packages/SystemUI/res/values/config.xml +++ b/packages/SystemUI/res/values/config.xml @@ -147,9 +147,6 @@ be 'platform' or 'noisy' (i.e. for noisy touch screens). --> <string name="velocity_tracker_impl" translatable="false">platform</string> - <!-- Wait on the touch feedback this long before performing an action. --> - <integer name="feedback_start_delay">300</integer> - <!-- Set to true to enable the classic notification ticker that scrolls Notification.tickerText across the status bar for what seems like an eternity. --> diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index dfb891ddfcd7..e3c0f5fbccff 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -169,14 +169,16 @@ <dimen name="qs_tile_spacing">4dp</dimen> <dimen name="qs_panel_padding_bottom">8dp</dimen> <dimen name="qs_detail_item_height">48dp</dimen> - <dimen name="qs_detail_item_height_connected">72dp</dimen> + <dimen name="qs_detail_item_height_twoline">72dp</dimen> + <dimen name="segmented_button_spacing">4dp</dimen> + <dimen name="segmented_button_radius">2dp</dimen> + <!-- How far the expanded QS panel peeks from the header in collapsed state. --> <dimen name="qs_peek_height">8dp</dimen> <dimen name="zen_mode_condition_detail_button_padding">8dp</dimen> - <dimen name="zen_mode_condition_height">48dp</dimen> <!-- used by DessertCase --> <dimen name="dessert_case_cell_size">192dp</dimen> @@ -287,10 +289,10 @@ <dimen name="keyguard_min_swipe_amount">75dp</dimen> <!-- Volume panel dialog y offset --> - <dimen name="volume_panel_top">16dp</dimen> + <dimen name="volume_panel_top">0dp</dimen> <!-- Volume panel dialog width --> - <dimen name="volume_panel_width">300dp</dimen> + <dimen name="volume_panel_width">344dp</dimen> <!-- Volume panel z depth --> <dimen name="volume_panel_z">3dp</dimen> diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index a5cfdbc6433e..79cc24bf2a95 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -583,8 +583,14 @@ <!-- Description of the left direction in which one can to slide the handle in the Slide unlock screen. [CHAR LIMIT=NONE] --> <string name="description_direction_left">"Slide left for <xliff:g id="target_description" example="Unlock">%s</xliff:g>.</string> - <!-- Zen mode: Short title. [CHAR LIMIT=40] --> - <string name="zen_mode_title">Do not disturb</string> + <!-- Zen mode: Alarm warning. [CHAR LIMIT=40] --> + <string name="zen_alarm_warning">You won\'t hear your alarms</string> + + <!-- Zen mode: No interruptions. [CHAR LIMIT=40] --> + <string name="zen_no_interruptions">No interruptions</string> + + <!-- Zen mode: Only important interruptions. [CHAR LIMIT=40] --> + <string name="zen_important_interruptions">Priority interruptions only</string> <!-- Text for overflow card on Keyguard when there is not enough space for all notifications on Keyguard. [CHAR LIMIT=1] --> <string name="keyguard_more_overflow_text">+<xliff:g id="number_of_notifications" example="5">%d</xliff:g></string> @@ -607,7 +613,16 @@ <string name="bugreport_tile_extended" translatable="false">%s\n%s (%s)</string> <!-- Zen mode condition: no exit criteria. [CHAR LIMIT=NONE] --> - <string name="zen_mode_forever">Until you turn this off</string> + <string name="zen_mode_forever">Indefinitely</string> + + <!-- Interruption level: None. [CHAR LIMIT=20] --> + <string name="interruption_level_none">None</string> + + <!-- Interruption level: Priority. [CHAR LIMIT=20] --> + <string name="interruption_level_priority">Priority</string> + + <!-- Interruption level: All. [CHAR LIMIT=20] --> + <string name="interruption_level_all">All</string> <!-- Indication on the keyguard that is shown when the device is charging. [CHAR LIMIT=40]--> <string name="keyguard_indication_charging_time">Charging (<xliff:g id="charging_time_left" example="4 hours and 2 minutes">%s</xliff:g> until full)</string> diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml index dd1b749a9996..f920a1fe8463 100644 --- a/packages/SystemUI/res/values/styles.xml +++ b/packages/SystemUI/res/values/styles.xml @@ -179,6 +179,23 @@ <item name="android:gravity">center</item> </style> + <style name="TextAppearance.QS.Subhead"> + <item name="android:textSize">14sp</item> + <item name="android:fontFamily">sans-serif-medium</item> + <item name="android:textColor">@color/qs_subhead</item> + </style> + + <style name="TextAppearance.QS.Warning"> + <item name="android:textSize">12sp</item> + <item name="android:textColor">@color/qs_subhead</item> + </style> + + <style name="TextAppearance.QS.SegmentedButton"> + <item name="android:textSize">12sp</item> + <item name="android:textAllCaps">true</item> + <item name="android:fontFamily">sans-serif-medium</item> + </style> + <style name="BaseBrightnessDialogContainer"> <item name="android:layout_width">match_parent</item> <item name="android:layout_height">wrap_content</item> @@ -239,10 +256,10 @@ <item name="android:background">@drawable/btn_borderless_rect</item> <item name="android:gravity">center</item> </style> - <style name="BorderlessButton" parent="@android:style/Widget.Material.Button.Borderless" /> - <style name="BorderlessButton.Tiny"> - <item name="android:minHeight">12dip</item> - <item name="android:minWidth">12dip</item> + <!-- Window animations used for volume panel. --> + <style name="VolumePanelAnimation"> + <item name="android:windowEnterAnimation">@*android:anim/dock_top_enter</item> + <item name="android:windowExitAnimation">@*android:anim/dock_top_exit</item> </style> </resources> diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/NotificationsTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/NotificationsTile.java deleted file mode 100644 index 3bdea79cabcd..000000000000 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/NotificationsTile.java +++ /dev/null @@ -1,182 +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.systemui.qs.tiles; - -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.media.AudioManager; -import android.util.Log; -import android.view.View; -import android.view.View.OnAttachStateChangeListener; -import android.view.ViewGroup; - -import com.android.systemui.R; -import com.android.systemui.qs.QSTile; -import com.android.systemui.statusbar.policy.ZenModeController; -import com.android.systemui.volume.VolumeComponent; -import com.android.systemui.volume.VolumePanel; -import com.android.systemui.volume.ZenModePanel; - -/** Quick settings tile: Notifications **/ -public class NotificationsTile extends QSTile<NotificationsTile.NotificationsState> { - private final ZenModeController mZenController; - private final AudioManager mAudioManager; - - public NotificationsTile(Host host) { - super(host); - mZenController = host.getZenModeController(); - mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE); - } - - @Override - public DetailAdapter getDetailAdapter() { - return mDetailAdapter; - } - - @Override - protected NotificationsState newTileState() { - return new NotificationsState(); - } - - @Override - public void setListening(boolean listening) { - if (listening) { - mZenController.addCallback(mCallback); - final IntentFilter filter = new IntentFilter(AudioManager.RINGER_MODE_CHANGED_ACTION); - mContext.registerReceiver(mReceiver, filter); - } else { - mZenController.removeCallback(mCallback); - mContext.unregisterReceiver(mReceiver); - } - } - - @Override - protected void handleClick() { - showDetail(true); - } - - @Override - protected void handleUpdateState(NotificationsState state, Object arg) { - state.visible = true; - state.zen = arg instanceof Boolean ? (Boolean) arg : mZenController.isZen(); - state.ringerMode = mAudioManager.getRingerMode(); - if (state.zen) { - state.iconId = R.drawable.ic_qs_zen_on; - } else if (state.ringerMode == AudioManager.RINGER_MODE_VIBRATE) { - state.iconId = R.drawable.ic_qs_ringer_vibrate; - } else if (state.ringerMode == AudioManager.RINGER_MODE_SILENT) { - state.iconId = R.drawable.ic_qs_ringer_silent; - } else { - state.iconId = R.drawable.ic_qs_ringer_audible; - } - state.label = mContext.getString(R.string.quick_settings_notifications_label); - } - - private final ZenModeController.Callback mCallback = new ZenModeController.Callback() { - @Override - public void onZenChanged(boolean zen) { - if (DEBUG) Log.d(TAG, "onZenChanged " + zen); - refreshState(zen); - } - }; - - public static final class NotificationsState extends QSTile.State { - public boolean zen; - public int ringerMode; - - @Override - public boolean copyTo(State other) { - final NotificationsState o = (NotificationsState) other; - final boolean changed = o.zen != zen || o.ringerMode != ringerMode; - o.zen = zen; - o.ringerMode = ringerMode; - return super.copyTo(other) || changed; - } - - @Override - protected StringBuilder toStringBuilder() { - final StringBuilder rt = super.toStringBuilder(); - rt.insert(rt.length() - 1, ",zen=" + zen + ",ringerMode=" + ringerMode); - return rt; - } - } - - private final BroadcastReceiver mReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - if (AudioManager.RINGER_MODE_CHANGED_ACTION.equals(intent.getAction())) { - refreshState(); - } - } - }; - - private final DetailAdapter mDetailAdapter = new DetailAdapter() { - - @Override - public int getTitle() { - return R.string.quick_settings_notifications_label; - } - - @Override - public Boolean getToggleState() { - return null; - } - - public void setToggleState(boolean state) { - // noop - } - - public Intent getSettingsIntent() { - return ZenModePanel.ZEN_SETTINGS; - } - - @Override - public View createDetailView(Context context, View convertView, ViewGroup parent) { - if (convertView != null) return convertView; - final VolumeComponent volumeComponent = mHost.getVolumeComponent(); - final VolumePanel vp = new VolumePanel(mContext, parent, mZenController); - final View v = vp.getContentView(); - v.addOnAttachStateChangeListener(new OnAttachStateChangeListener() { - @Override - public void onViewDetachedFromWindow(View v) { - volumeComponent.setVolumePanel(null); - } - - @Override - public void onViewAttachedToWindow(View v) { - vp.updateStates(); - volumeComponent.setVolumePanel(vp); - } - }); - vp.setZenModePanelCallback(new ZenModePanel.Callback() { - @Override - public void onMoreSettings() { - mHost.startSettingsActivity(ZenModePanel.ZEN_SETTINGS); - } - - @Override - public void onInteraction() { - // noop - } - }); - vp.postVolumeChanged(AudioManager.STREAM_RING, AudioManager.FLAG_SHOW_UI); - return v; - } - }; -} diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java index 84eee2418d3e..5d1b16c7c9b1 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java @@ -266,7 +266,7 @@ public class WifiTile extends QSTile<QSTile.SignalState> { final TextView summary = (TextView) item.findViewById(android.R.id.summary); if (ap.isConnected) { item.setMinimumHeight(mContext.getResources() - .getDimensionPixelSize(R.dimen.qs_detail_item_height_connected)); + .getDimensionPixelSize(R.dimen.qs_detail_item_height_twoline)); summary.setText(R.string.quick_settings_connected); } else { summary.setVisibility(View.GONE); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java index 0a3fdef973e3..a11e61089eaf 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java @@ -60,7 +60,7 @@ public class DemoStatusIcons extends LinearLayout implements DemoMode { } else if (mDemoMode && command.equals(COMMAND_STATUS)) { String volume = args.getString("volume"); if (volume != null) { - int iconId = volume.equals("zen") ? R.drawable.stat_sys_ringer_zen + int iconId = volume.equals("important") ? R.drawable.stat_sys_zen_important : volume.equals("silent") ? R.drawable.stat_sys_ringer_silent : volume.equals("vibrate") ? R.drawable.stat_sys_ringer_vibrate : 0; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java index f6970988f146..a6b2110e67fa 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java @@ -738,6 +738,14 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, return mStatusBarView; } + @Override + protected void setZenMode(int mode) { + super.setZenMode(mode); + if (mIconPolicy != null) { + mIconPolicy.setZenMode(mode); + } + } + private void startKeyguard() { KeyguardViewMediator keyguardViewMediator = getComponent(KeyguardViewMediator.class); mStatusBarKeyguardViewManager = keyguardViewMediator.registerStatusBar(this, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java index b6f5ae0a545f..186b61848ddd 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java @@ -24,6 +24,7 @@ import android.content.Intent; import android.content.IntentFilter; import android.media.AudioManager; import android.os.Handler; +import android.provider.Settings.Global; import android.util.Log; import com.android.internal.telephony.IccCardConstants; @@ -64,7 +65,7 @@ public class PhoneStatusBarPolicy { private boolean mVolumeVisible; // zen mode - private boolean mZen; + private int mZen; // bluetooth device status private boolean mBluetoothEnabled = false; @@ -155,7 +156,7 @@ public class PhoneStatusBarPolicy { updateVolume(); } - public void setZenMode(boolean zen) { + public void setZenMode(int zen) { mZen = zen; updateVolume(); } @@ -202,21 +203,21 @@ public class PhoneStatusBarPolicy { private final void updateVolume() { AudioManager audioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE); final int ringerMode = audioManager.getRingerMode(); - final boolean visible = ringerMode == AudioManager.RINGER_MODE_SILENT || - ringerMode == AudioManager.RINGER_MODE_VIBRATE || - mZen; - - final int iconId; + int iconId = 0; String contentDescription = null; - if (mZen) { - iconId = R.drawable.stat_sys_ringer_zen; - contentDescription = mContext.getString(R.string.zen_mode_title); + boolean visible = false; + if (ringerMode == AudioManager.RINGER_MODE_SILENT) { + visible = true; + iconId = R.drawable.stat_sys_ringer_silent; + contentDescription = mContext.getString(R.string.accessibility_ringer_silent); + } else if (mZen == Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS) { + visible = true; + iconId = R.drawable.stat_sys_zen_important; + contentDescription = mContext.getString(R.string.zen_important_interruptions); } else if (ringerMode == AudioManager.RINGER_MODE_VIBRATE) { + visible = true; iconId = R.drawable.stat_sys_ringer_vibrate; contentDescription = mContext.getString(R.string.accessibility_ringer_vibrate); - } else { - iconId = R.drawable.stat_sys_ringer_silent; - contentDescription = mContext.getString(R.string.accessibility_ringer_silent); } if (visible) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java index 04b1443640e2..5fbade1a9f34 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java @@ -21,19 +21,16 @@ import android.content.Intent; import android.os.HandlerThread; import android.os.Looper; -import com.android.systemui.R; import com.android.systemui.qs.QSTile; import com.android.systemui.qs.tiles.AirplaneModeTile; import com.android.systemui.qs.tiles.BluetoothTile; -import com.android.systemui.qs.tiles.BugreportTile; import com.android.systemui.qs.tiles.CastTile; import com.android.systemui.qs.tiles.CellularTile; import com.android.systemui.qs.tiles.ColorInversionTile; import com.android.systemui.qs.tiles.FlashlightTile; +import com.android.systemui.qs.tiles.HotspotTile; import com.android.systemui.qs.tiles.LocationTile; -import com.android.systemui.qs.tiles.NotificationsTile; import com.android.systemui.qs.tiles.RotationLockTile; -import com.android.systemui.qs.tiles.HotspotTile; import com.android.systemui.qs.tiles.WifiTile; import com.android.systemui.settings.CurrentUserTracker; import com.android.systemui.statusbar.policy.BluetoothController; @@ -93,7 +90,6 @@ public class QSTileHost implements QSTile.Host { mTiles.add(new ColorInversionTile(this)); mTiles.add(new CellularTile(this)); mTiles.add(new AirplaneModeTile(this)); - mTiles.add(new NotificationsTile(this)); mTiles.add(new RotationLockTile(this)); mTiles.add(new LocationTile(this)); mTiles.add(new CastTile(this)); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeController.java index 4cf72a28ee43..61902a2f8653 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeController.java @@ -22,14 +22,15 @@ import android.service.notification.Condition; public interface ZenModeController { void addCallback(Callback callback); void removeCallback(Callback callback); - void setZen(boolean zen); - boolean isZen(); + void setZen(int zen); + int getZen(); void requestConditions(boolean request); void setExitConditionId(Uri exitConditionId); Uri getExitConditionId(); + boolean hasNextAlarm(); public static class Callback { - public void onZenChanged(boolean zen) {} + public void onZenChanged(int zen) {} public void onExitConditionChanged(Uri exitConditionId) {} public void onConditionsChanged(Condition[] conditions) {} } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java index da8fd32ff714..7703966cc093 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java @@ -28,6 +28,7 @@ import android.service.notification.IConditionListener; import android.service.notification.ZenModeConfig; import android.util.Slog; +import com.android.internal.widget.LockPatternUtils; import com.android.systemui.qs.GlobalSetting; import java.util.ArrayList; @@ -44,15 +45,17 @@ public class ZenModeControllerImpl implements ZenModeController { private final GlobalSetting mConfigSetting; private final INotificationManager mNoMan; private final LinkedHashMap<Uri, Condition> mConditions = new LinkedHashMap<Uri, Condition>(); + private final LockPatternUtils mUtils; private boolean mRequesting; public ZenModeControllerImpl(Context context, Handler handler) { mContext = context; + mUtils = new LockPatternUtils(mContext); mModeSetting = new GlobalSetting(mContext, handler, Global.ZEN_MODE) { @Override protected void handleValueChanged(int value) { - fireZenChanged(value != 0); + fireZenChanged(value); } }; mConfigSetting = new GlobalSetting(mContext, handler, Global.ZEN_MODE_CONFIG_ETAG) { @@ -78,13 +81,13 @@ public class ZenModeControllerImpl implements ZenModeController { } @Override - public boolean isZen() { - return mModeSetting.getValue() != 0; + public int getZen() { + return mModeSetting.getValue(); } @Override - public void setZen(boolean zen) { - mModeSetting.setValue(zen ? 1 : 0); + public void setZen(int zen) { + mModeSetting.setValue(zen); } @Override @@ -122,7 +125,12 @@ public class ZenModeControllerImpl implements ZenModeController { return null; } - private void fireZenChanged(boolean zen) { + @Override + public boolean hasNextAlarm() { + return mUtils.getNextAlarm() != null; + } + + private void fireZenChanged(int zen) { for (Callback cb : mCallbacks) { cb.onZenChanged(zen); } diff --git a/packages/SystemUI/src/com/android/systemui/volume/SegmentedButtons.java b/packages/SystemUI/src/com/android/systemui/volume/SegmentedButtons.java new file mode 100644 index 000000000000..d339dd40cbae --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/volume/SegmentedButtons.java @@ -0,0 +1,93 @@ +/* + * 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.systemui.volume; + +import android.content.Context; +import android.util.AttributeSet; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.Button; +import android.widget.LinearLayout; + +import com.android.systemui.R; + +import java.util.Objects; + +public class SegmentedButtons extends LinearLayout { + + private final Context mContext; + private final LayoutInflater mInflater; + + private Callback mCallback; + private Object mSelectedValue; + + public SegmentedButtons(Context context, AttributeSet attrs) { + super(context, attrs); + mContext = context; + mInflater = LayoutInflater.from(mContext); + setOrientation(HORIZONTAL); + } + + public void setCallback(Callback callback) { + mCallback = callback; + } + + public Object getSelectedValue() { + return mSelectedValue; + } + + public void setSelectedValue(Object value) { + if (Objects.equals(value, mSelectedValue)) return; + mSelectedValue = value; + for (int i = 0; i < getChildCount(); i++) { + final View c = getChildAt(i); + final Object tag = c.getTag(); + c.setSelected(Objects.equals(mSelectedValue, tag)); + } + fireOnSelected(); + } + + public void addButton(int labelResId, Object value) { + final Button b = (Button) mInflater.inflate(R.layout.segmented_button, this, false); + b.setText(labelResId); + final LayoutParams lp = (LayoutParams) b.getLayoutParams(); + if (getChildCount() == 0) { + lp.leftMargin = lp.rightMargin = 0; // first button has no margin + } + b.setLayoutParams(lp); + addView(b); + b.setTag(value); + b.setOnClickListener(mClick); + } + + private void fireOnSelected() { + if (mCallback != null) { + mCallback.onSelected(mSelectedValue); + } + } + + private final View.OnClickListener mClick = new View.OnClickListener() { + @Override + public void onClick(View v) { + setSelectedValue(v.getTag()); + } + }; + + public interface Callback { + void onSelected(Object value); + } +} diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java b/packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java index 53daaae1b3bf..b6d67671d59d 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java +++ b/packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java @@ -16,8 +16,6 @@ package com.android.systemui.volume; -import android.animation.Animator; -import android.animation.AnimatorListenerAdapter; import android.app.AlertDialog; import android.app.Dialog; import android.content.BroadcastReceiver; @@ -38,24 +36,21 @@ import android.media.VolumeProvider; import android.media.session.MediaController; import android.media.session.MediaController.VolumeInfo; import android.net.Uri; -import android.os.AsyncTask; import android.os.Handler; import android.os.Message; import android.os.Vibrator; +import android.provider.Settings.Global; import android.util.Log; import android.view.Gravity; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; import android.view.View.OnClickListener; -import android.view.View.OnLongClickListener; import android.view.ViewGroup; import android.view.ViewStub; import android.view.Window; import android.view.WindowManager; import android.view.WindowManager.LayoutParams; -import android.view.animation.AnimationUtils; -import android.view.animation.Interpolator; import android.widget.ImageView; import android.widget.SeekBar; import android.widget.SeekBar.OnSeekBarChangeListener; @@ -71,7 +66,8 @@ import java.util.HashMap; * @hide */ public class VolumePanel extends Handler { - private static boolean LOGD = false; + private static final String TAG = "VolumePanel"; + private static boolean LOGD = Log.isLoggable(TAG, Log.DEBUG); private static final int PLAY_SOUND_DELAY = AudioService.PLAY_SOUND_DELAY; @@ -89,7 +85,6 @@ public class VolumePanel extends Handler { private static final int FREE_DELAY = 10000; private static final int TIMEOUT_DELAY = 3000; private static final int TIMEOUT_DELAY_EXPANDED = 10000; - private static final float ICON_PULSE_SCALE = 1.3f; private static final int MSG_VOLUME_CHANGED = 0; private static final int MSG_FREE_RESOURCES = 1; @@ -105,6 +100,7 @@ public class VolumePanel extends Handler { private static final int MSG_DISPLAY_SAFE_VOLUME_WARNING = 11; private static final int MSG_LAYOUT_DIRECTION = 12; private static final int MSG_ZEN_MODE_CHANGED = 13; + private static final int MSG_USER_ACTIVITY = 14; // Pseudo stream type for master volume private static final int STREAM_MASTER = -100; @@ -114,7 +110,6 @@ public class VolumePanel extends Handler { protected final Context mContext; private final AudioManager mAudioManager; private final ZenModeController mZenController; - private final Interpolator mFastOutSlowInInterpolator; private boolean mRingIsSilent; private boolean mVoiceCapable; private boolean mZenModeCapable; @@ -135,18 +130,12 @@ public class VolumePanel extends Handler { private final ViewGroup mPanel; /** Contains the slider and its touchable icons */ private final ViewGroup mSliderPanel; - /** The button that expands the dialog to show the zen panel */ - private final ImageView mExpandButton; - /** Dummy divider icon that needs to vanish with the expand button */ - private final View mExpandDivider; /** The zen mode configuration panel view stub */ private final ViewStub mZenPanelStub; /** The zen mode configuration panel view, once inflated */ private ZenModePanel mZenPanel; - /** Dummy divider icon that needs to vanish with the zen panel */ - private final View mZenPanelDivider; - private ZenModePanel.Callback mZenPanelCallback; + private Callback mCallback; /** Currently active stream that shows up at the top of the list of sliders */ private int mActiveStreamType = -1; @@ -231,7 +220,6 @@ public class VolumePanel extends Handler { ViewGroup group; ImageView icon; SeekBar seekbarView; - View seekbarContainer; int iconRes; int iconMuteRes; } @@ -280,13 +268,11 @@ public class VolumePanel extends Handler { public VolumePanel(Context context, ViewGroup parent, ZenModeController zenController) { - mTag = String.format("VolumePanel%s.%08x", parent == null ? "Dialog" : "", hashCode()); + mTag = String.format("%s.%s.%08x", TAG, parent == null ? "Dialog" : "Embed", hashCode()); mContext = context; mParent = parent; mZenController = zenController; mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); - mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(mContext, - android.R.interpolator.fast_out_slow_in); // For now, only show master volume if master volume is supported final Resources res = context.getResources(); @@ -318,12 +304,11 @@ public class VolumePanel extends Handler { lp.token = null; // Offset from the top lp.y = res.getDimensionPixelOffset(com.android.systemui.R.dimen.volume_panel_top); - lp.width = res.getDimensionPixelSize(com.android.systemui.R.dimen.volume_panel_width); - lp.type = LayoutParams.TYPE_VOLUME_OVERLAY; + lp.type = LayoutParams.TYPE_STATUS_BAR_PANEL; lp.format = PixelFormat.TRANSLUCENT; - lp.windowAnimations = R.style.Animation_VolumePanel; + lp.windowAnimations = com.android.systemui.R.style.VolumePanelAnimation; + lp.gravity = Gravity.TOP; window.setAttributes(lp); - window.setGravity(Gravity.TOP); window.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND); window.requestFeature(Window.FEATURE_NO_TITLE); window.addFlags(LayoutParams.FLAG_NOT_FOCUSABLE @@ -337,7 +322,7 @@ public class VolumePanel extends Handler { public void onDismiss(DialogInterface dialog) { mActiveStreamType = -1; mAudioManager.forceVolumeControlStream(mActiveStreamType); - collapse(); + setZenPanelVisible(false); } }); @@ -362,19 +347,14 @@ public class VolumePanel extends Handler { } mPanel = (ViewGroup) mView.findViewById(com.android.systemui.R.id.visible_panel); mSliderPanel = (ViewGroup) mView.findViewById(com.android.systemui.R.id.slider_panel); - mExpandButton = (ImageView) mView.findViewById(com.android.systemui.R.id.expand_button); - mExpandDivider = mView.findViewById(com.android.systemui.R.id.expand_button_divider); mZenPanelStub = (ViewStub)mView.findViewById(com.android.systemui.R.id.zen_panel_stub); - mZenPanelDivider = mView.findViewById(com.android.systemui.R.id.zen_panel_divider); mToneGenerators = new ToneGenerator[AudioSystem.getNumStreamTypes()]; mVibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE); mVoiceCapable = context.getResources().getBoolean(R.bool.config_voice_capable); mZenModeCapable = !useMasterVolume && mZenController != null; - mZenPanelDivider.setVisibility(View.GONE); - mExpandButton.setOnClickListener(mClickListener); - updateZenMode(mZenController == null ? false : mZenController.isZen()); + updateZenMode(mZenController != null ? mZenController.getZen() : Global.ZEN_MODE_OFF); mZenController.addCallback(mZenCallback); final boolean masterVolumeOnly = res.getBoolean(R.bool.config_useMasterVolume); @@ -502,17 +482,7 @@ public class VolumePanel extends Handler { toggle(sc); } }); - sc.icon.setOnLongClickListener(new OnLongClickListener() { - @Override - public boolean onLongClick(View v) { - resetTimeout(); - longToggle(sc); - return true; - } - }); } - sc.seekbarContainer = - sc.group.findViewById(com.android.systemui.R.id.seekbar_container); sc.seekbarView = (SeekBar) sc.group.findViewById(com.android.systemui.R.id.seekbar); final int plusOne = (streamType == AudioSystem.STREAM_BLUETOOTH_SCO || streamType == AudioSystem.STREAM_VOICE_CALL) ? 1 : 0; @@ -533,29 +503,19 @@ public class VolumePanel extends Handler { } } - private void longToggle(StreamControl sc) { - if (mAudioManager.getRingerMode() == AudioManager.RINGER_MODE_SILENT) { - mAudioManager.setRingerMode(AudioManager.RINGER_MODE_NORMAL); - postVolumeChanged(sc.streamType, AudioManager.FLAG_PLAY_SOUND); - } else { - mAudioManager.setRingerMode(AudioManager.RINGER_MODE_SILENT); - postVolumeChanged(sc.streamType, AudioManager.FLAG_SHOW_UI); // disable the slider - } - } - private void reorderSliders(int activeStreamType) { mSliderPanel.removeAllViews(); final StreamControl active = mStreamControls.get(activeStreamType); if (active == null) { - Log.e("VolumePanel", "Missing stream type! - " + activeStreamType); + Log.e(TAG, "Missing stream type! - " + activeStreamType); mActiveStreamType = -1; } else { mSliderPanel.addView(active.group); mActiveStreamType = activeStreamType; active.group.setVisibility(View.VISIBLE); updateSlider(active); - updateZenMode(mZenController == null ? false : mZenController.isZen()); + setZenPanelVisible(isNotificationOrRing(mActiveStreamType)); } } @@ -575,6 +535,7 @@ public class VolumePanel extends Handler { private void updateSliderEnabled(final StreamControl sc, boolean muted, boolean fixedVolume) { final boolean wasEnabled = sc.seekbarView.isEnabled(); + final boolean isRinger = isNotificationOrRing(sc.streamType); if (sc.streamType == AudioService.STREAM_REMOTE_MUSIC) { // never disable touch interactions for remote playback, the muting is not tied to // the state of the phone. @@ -583,40 +544,37 @@ public class VolumePanel extends Handler { (sc.streamType != mAudioManager.getMasterStreamType() && muted) || (sConfirmSafeVolumeDialog != null)) { sc.seekbarView.setEnabled(false); - } else if (isNotificationOrRing(sc.streamType) - && mAudioManager.getRingerMode() == AudioManager.RINGER_MODE_SILENT) { + } else if (isRinger && mAudioManager.getRingerMode() == AudioManager.RINGER_MODE_SILENT) { sc.seekbarView.setEnabled(false); + sc.icon.setEnabled(false); + sc.icon.setClickable(false); } else { sc.seekbarView.setEnabled(true); + sc.icon.setEnabled(true); } - // pulse the ringer icon when the disabled slider is touched in silent mode - if (sc.icon.isClickable() && wasEnabled != sc.seekbarView.isEnabled()) { + // show the silent hint when the disabled slider is touched in silent mode + if (isRinger && wasEnabled != sc.seekbarView.isEnabled()) { if (sc.seekbarView.isEnabled()) { - sc.seekbarContainer.setOnTouchListener(null); + sc.group.setOnTouchListener(null); + sc.icon.setClickable(true); } else { - sc.seekbarContainer.setOnTouchListener(new View.OnTouchListener() { + final View.OnTouchListener showHintOnTouch = new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { resetTimeout(); - pulseIcon(sc.icon); + showSilentHint(); return false; } - }); + }; + sc.group.setOnTouchListener(showHintOnTouch); } } } - private void pulseIcon(final ImageView icon) { - if (icon.getScaleX() != 1) return; // already running - icon.animate().cancel(); - icon.animate().scaleX(ICON_PULSE_SCALE).scaleY(ICON_PULSE_SCALE) - .setInterpolator(mFastOutSlowInInterpolator) - .setListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - icon.animate().scaleX(1).scaleY(1).setListener(null); - } - }); + private void showSilentHint() { + if (mZenPanel != null) { + mZenPanel.showSilentHint(); + } } private static boolean isNotificationOrRing(int streamType) { @@ -624,47 +582,45 @@ public class VolumePanel extends Handler { || streamType == AudioManager.STREAM_NOTIFICATION; } - public void setZenModePanelCallback(ZenModePanel.Callback callback) { - mZenPanelCallback = callback; + public void setCallback(Callback callback) { + mCallback = callback; } - private void expand() { - if (LOGD) Log.d(mTag, "expand mZenPanel=" + mZenPanel); - if (mZenPanel == null) { - mZenPanel = (ZenModePanel) mZenPanelStub.inflate(); - final boolean isDialog = mDialog != null; - mZenPanel.init(mZenController, isDialog ? 'D' : 'E', isDialog); - mZenPanel.setCallback(new ZenModePanel.Callback() { - @Override - public void onMoreSettings() { - if (mZenPanelCallback != null) { - mZenPanelCallback.onMoreSettings(); + private void setZenPanelVisible(boolean visible) { + if (LOGD) Log.d(mTag, "setZenPanelVisible " + visible + " mZenPanel=" + mZenPanel); + if (visible) { + if (mZenPanel == null) { + mZenPanel = (ZenModePanel) mZenPanelStub.inflate(); + mZenPanel.init(mZenController, mDialog != null ? 'D' : 'E'); + mZenPanel.setCallback(new ZenModePanel.Callback() { + @Override + public void onMoreSettings() { + if (mCallback != null) { + mCallback.onZenSettings(); + } } - } - @Override - public void onInteraction() { - resetTimeout(); - if (mZenPanelCallback != null) { - mZenPanelCallback.onInteraction(); + @Override + public void onInteraction() { + resetTimeout(); } - } - }); - } - mZenPanel.setVisibility(View.VISIBLE); - mZenPanelDivider.setVisibility(View.VISIBLE); - mTimeoutDelay = TIMEOUT_DELAY_EXPANDED; - resetTimeout(); - } - private void collapse() { - if (LOGD) Log.d(mTag, "collapse mZenPanel=" + mZenPanel); - if (mZenPanel != null) { - mZenPanel.setVisibility(View.GONE); + @Override + public void onExpanded(boolean expanded) { + mTimeoutDelay = expanded ? TIMEOUT_DELAY_EXPANDED : TIMEOUT_DELAY; + resetTimeout(); + } + }); + } + mZenPanel.setVisibility(View.VISIBLE); + resetTimeout(); + } else { + if (mZenPanel != null) { + mZenPanel.setVisibility(View.GONE); + } + mTimeoutDelay = TIMEOUT_DELAY; + resetTimeout(); } - mZenPanelDivider.setVisibility(View.GONE); - mTimeoutDelay = TIMEOUT_DELAY; - resetTimeout(); } public void updateStates() { @@ -675,25 +631,14 @@ public class VolumePanel extends Handler { } } - private void updateZenMode(boolean zen) { - if (mZenModeCapable) { - final boolean show = isNotificationOrRing(mActiveStreamType); - mExpandButton.setVisibility(show ? View.VISIBLE : View.GONE); - mExpandDivider.setVisibility(show ? View.VISIBLE : View.GONE); - mExpandButton.setImageResource(zen ? com.android.systemui.R.drawable.ic_vol_zen_on - : com.android.systemui.R.drawable.ic_vol_zen_off); - if (show && !zen) { - collapse(); - } - } else { - mExpandButton.setVisibility(View.GONE); - mExpandDivider.setVisibility(View.GONE); - } + private void updateZenMode(int zen) { + final boolean show = mZenModeCapable && isNotificationOrRing(mActiveStreamType); + setZenPanelVisible(show); } - public void postZenModeChanged(boolean zen) { + public void postZenModeChanged(int zen) { removeMessages(MSG_ZEN_MODE_CHANGED); - obtainMessage(MSG_ZEN_MODE_CHANGED, zen ? 1 : 0, 0).sendToTarget(); + obtainMessage(MSG_ZEN_MODE_CHANGED, zen).sendToTarget(); } public void postVolumeChanged(int streamType, int flags) { @@ -955,8 +900,8 @@ public class VolumePanel extends Handler { } // Pulse the slider icon if an adjustment was suppressed due to silent mode. - if (sc != null && (flags & AudioManager.FLAG_SHOW_SILENT_HINT) != 0) { - pulseIcon(sc.icon); + if ((flags & AudioManager.FLAG_SHOW_SILENT_HINT) != 0) { + showSilentHint(); } } @@ -1233,15 +1178,23 @@ public class VolumePanel extends Handler { break; case MSG_ZEN_MODE_CHANGED: - updateZenMode(msg.arg1 != 0); + updateZenMode(msg.arg1); + break; + + case MSG_USER_ACTIVITY: + if (mCallback != null) { + mCallback.onInteraction(); + } break; } } - public void resetTimeout() { + private void resetTimeout() { if (LOGD) Log.d(mTag, "resetTimeout at " + System.currentTimeMillis()); removeMessages(MSG_TIMEOUT); sendEmptyMessageDelayed(MSG_TIMEOUT, mTimeoutDelay); + removeMessages(MSG_USER_ACTIVITY); + sendEmptyMessage(MSG_USER_ACTIVITY); } private void forceTimeout() { @@ -1273,29 +1226,8 @@ public class VolumePanel extends Handler { } }; - private final View.OnClickListener mClickListener = new View.OnClickListener() { - @Override - public void onClick(View v) { - if (v == mExpandButton && mZenController != null) { - final boolean newZen = !mZenController.isZen(); - AsyncTask.execute(new Runnable() { - @Override - public void run() { - mZenController.setZen(newZen); - } - }); - if (newZen) { - expand(); - } else { - collapse(); - } - } - resetTimeout(); - } - }; - private final ZenModeController.Callback mZenCallback = new ZenModeController.Callback() { - public void onZenChanged(boolean zen) { + public void onZenChanged(int zen) { postZenModeChanged(zen); } }; @@ -1305,4 +1237,9 @@ public class VolumePanel extends Handler { onRemoteVolumeUpdateIfShown(); } }; + + public interface Callback { + void onZenSettings(); + void onInteraction(); + } } diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java index c1f92fff75de..51be8335674e 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java +++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java @@ -1,8 +1,8 @@ package com.android.systemui.volume; +import android.app.ActivityManagerNative; import android.content.Context; import android.content.Intent; -import android.content.res.Resources; import android.database.ContentObserver; import android.media.AudioManager; import android.media.IRemoteVolumeController; @@ -17,8 +17,8 @@ import android.os.UserHandle; import android.provider.Settings; import android.util.Log; -import com.android.systemui.R; import com.android.systemui.SystemUI; +import com.android.systemui.keyguard.KeyguardViewMediator; import com.android.systemui.statusbar.policy.ZenModeController; import com.android.systemui.statusbar.policy.ZenModeControllerImpl; @@ -80,17 +80,19 @@ public class VolumeUI extends SystemUI { private void initPanel() { mPanel = new VolumePanel(mContext, null, new ZenModeControllerImpl(mContext, mHandler)); - final int delay = mContext.getResources().getInteger(R.integer.feedback_start_delay); - mPanel.setZenModePanelCallback(new ZenModePanel.Callback() { + mPanel.setCallback(new VolumePanel.Callback() { @Override - public void onMoreSettings() { + public void onZenSettings() { mHandler.removeCallbacks(mStartZenSettings); - mHandler.postDelayed(mStartZenSettings, delay); + mHandler.post(mStartZenSettings); } @Override public void onInteraction() { - mDialogPanel.resetTimeout(); + final KeyguardViewMediator kvm = getComponent(KeyguardViewMediator.class); + if (kvm != null) { + kvm.userActivity(); + } } }); mDialogPanel = mPanel; @@ -108,6 +110,11 @@ public class VolumeUI extends SystemUI { @Override public void run() { mDialogPanel.postDismiss(); + try { + // Dismiss the lock screen when Settings starts. + ActivityManagerNative.getDefault().dismissKeyguardOnNextActivity(); + } catch (RemoteException e) { + } final Intent intent = ZenModePanel.ZEN_SETTINGS; intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP); mContext.startActivityAsUser(intent, new UserHandle(UserHandle.USER_CURRENT)); diff --git a/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java b/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java index 9917944e12a3..afa5bfe35a4d 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java +++ b/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java @@ -16,6 +16,8 @@ package com.android.systemui.volume; +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; @@ -25,6 +27,7 @@ import android.os.Handler; import android.os.Looper; import android.os.Message; import android.provider.Settings; +import android.provider.Settings.Global; import android.service.notification.Condition; import android.service.notification.ZenModeConfig; import android.util.AttributeSet; @@ -32,7 +35,8 @@ import android.util.Log; import android.view.ContextThemeWrapper; import android.view.LayoutInflater; import android.view.View; -import android.view.ViewGroup; +import android.view.animation.AnimationUtils; +import android.view.animation.Interpolator; import android.widget.CompoundButton; import android.widget.CompoundButton.OnCheckedChangeListener; import android.widget.ImageView; @@ -47,12 +51,19 @@ import java.util.Arrays; import java.util.Objects; public class ZenModePanel extends LinearLayout { - private static final boolean DEBUG = false; + private static final String TAG = "ZenModePanel"; + private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); - private static final int[] MINUTE_BUCKETS = new int[] { 15, 30, 45, 60, 120, 180, 240, 480 }; + private static final int[] MINUTE_BUCKETS = DEBUG + ? new int[] { 1, 2, 5, 15, 30, 45, 60, 120, 180, 240, 480 } + : new int[] { 15, 30, 45, 60, 120, 180, 240, 480 }; private static final int MIN_BUCKET_MINUTES = MINUTE_BUCKETS[0]; private static final int MAX_BUCKET_MINUTES = MINUTE_BUCKETS[MINUTE_BUCKETS.length - 1]; private static final int DEFAULT_BUCKET_INDEX = Arrays.binarySearch(MINUTE_BUCKETS, 60); + private static final int FOREVER_CONDITION_INDEX = 0; + private static final int TIME_CONDITION_INDEX = 1; + private static final int FIRST_CONDITION_INDEX = 2; + private static final float SILENT_HINT_PULSE_SCALE = 1.1f; private static final int SECONDS_MS = 1000; private static final int MINUTES_MS = 60 * SECONDS_MS; @@ -63,73 +74,110 @@ public class ZenModePanel extends LinearLayout { private final LayoutInflater mInflater; private final H mHandler = new H(); private final Favorites mFavorites; + private final Interpolator mFastOutSlowInInterpolator; private char mLogTag = '?'; private String mTag; - private LinearLayout mConditions; + + private SegmentedButtons mZenButtons; + private View mZenSubhead; + private TextView mZenSubheadCollapsed; + private TextView mZenSubheadExpanded; private View mMoreSettings; + private LinearLayout mZenConditions; + private View mAlarmWarning; + private Callback mCallback; private ZenModeController mController; private boolean mRequestingConditions; private Uri mExitConditionId; private int mBucketIndex = -1; - private boolean mShowing; + private boolean mExpanded; + private int mAttachedZen; + private String mExitConditionText; public ZenModePanel(Context context, AttributeSet attrs) { super(context, attrs); mContext = context; mFavorites = new Favorites(); mInflater = LayoutInflater.from(new ContextThemeWrapper(context, R.style.QSWhiteTheme)); + mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(mContext, + android.R.interpolator.fast_out_slow_in); updateTag(); if (DEBUG) Log.d(mTag, "new ZenModePanel"); } private void updateTag() { - mTag = "ZenModePanel/" + mLogTag + "/" + Integer.toHexString(System.identityHashCode(this)); + mTag = TAG + "/" + mLogTag + "/" + Integer.toHexString(System.identityHashCode(this)); } @Override protected void onFinishInflate() { super.onFinishInflate(); - mConditions = (LinearLayout) findViewById(android.R.id.content); - mMoreSettings = findViewById(android.R.id.button2); + + mZenButtons = (SegmentedButtons) findViewById(R.id.zen_buttons); + mZenButtons.addButton(R.string.interruption_level_none, Global.ZEN_MODE_NO_INTERRUPTIONS); + mZenButtons.addButton(R.string.interruption_level_priority, + Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS); + mZenButtons.addButton(R.string.interruption_level_all, Global.ZEN_MODE_OFF); + mZenButtons.setCallback(mZenButtonsCallback); + + mZenSubhead = findViewById(R.id.zen_subhead); + + mZenSubheadCollapsed = (TextView) findViewById(R.id.zen_subhead_collapsed); + mZenSubheadCollapsed.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + setExpanded(true); + fireInteraction(); + } + }); + + mZenSubheadExpanded = (TextView) findViewById(R.id.zen_subhead_expanded); + mZenSubheadExpanded.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + setExpanded(false); + fireInteraction(); + } + }); + + mMoreSettings = findViewById(R.id.zen_more_settings); mMoreSettings.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { fireMoreSettings(); + fireInteraction(); } }); + + mZenConditions = (LinearLayout) findViewById(R.id.zen_conditions); + + mAlarmWarning = findViewById(R.id.zen_alarm_warning); } @Override protected void onAttachedToWindow() { super.onAttachedToWindow(); if (DEBUG) Log.d(mTag, "onAttachedToWindow"); - final ViewGroup p = (ViewGroup) getParent(); - updateShowing(p != null && p.getVisibility() == VISIBLE); + mAttachedZen = getSelectedZen(-1); + refreshExitConditionText(); } @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); if (DEBUG) Log.d(mTag, "onDetachedFromWindow"); - updateShowing(false); + mAttachedZen = -1; + setExpanded(false); } - @Override - public void setVisibility(int visibility) { - super.setVisibility(visibility); - final boolean vis = visibility == VISIBLE; - updateShowing(isAttachedToWindow() && vis); - } - - private void updateShowing(boolean showing) { - if (showing == mShowing) return; - mShowing = showing; - if (DEBUG) Log.d(mTag, "mShowing=" + mShowing); - if (mController != null) { - setRequestingConditions(mShowing); - } + private void setExpanded(boolean expanded) { + if (expanded == mExpanded) return; + mExpanded = expanded; + updateWidgets(); + setRequestingConditions(mExpanded); + fireExpanded(); } /** Start or stop requesting relevant zen mode exit conditions */ @@ -149,24 +197,40 @@ public class ZenModePanel extends LinearLayout { timeCondition = newTimeCondition(MINUTE_BUCKETS[mBucketIndex]); } if (DEBUG) Log.d(mTag, "Initial bucket index: " + mBucketIndex); - bind(timeCondition, mConditions.getChildAt(0)); - handleUpdateConditions(new Condition[0]); + handleUpdateConditions(new Condition[0]); // ensures forever exists + bind(timeCondition, mZenConditions.getChildAt(TIME_CONDITION_INDEX)); + checkForDefault(); } else { - mConditions.removeAllViews(); + mZenConditions.removeAllViews(); } } - public void init(ZenModeController controller, char logTag, boolean moreSettings) { + public void init(ZenModeController controller, char logTag) { mController = controller; mLogTag = logTag; updateTag(); - mExitConditionId = mController.getExitConditionId(); + setExitConditionId(mController.getExitConditionId()); + refreshExitConditionText(); + mAttachedZen = getSelectedZen(-1); + handleUpdateZen(mController.getZen()); if (DEBUG) Log.d(mTag, "init mExitConditionId=" + mExitConditionId); - mMoreSettings.setVisibility(moreSettings ? VISIBLE : GONE); - mConditions.removeAllViews(); + mZenConditions.removeAllViews(); mController.addCallback(mZenCallback); - if (mShowing) { - setRequestingConditions(true); + } + + private void setExitConditionId(Uri exitConditionId) { + if (Objects.equals(mExitConditionId, exitConditionId)) return; + mExitConditionId = exitConditionId; + refreshExitConditionText(); + } + + private void refreshExitConditionText() { + if (mExitConditionId == null) { + mExitConditionText = mContext.getString(R.string.zen_mode_forever); + } else if (ZenModeConfig.isValidCountdownConditionId(mExitConditionId)) { + mExitConditionText = parseExistingTimeCondition(mExitConditionId).summary; + } else { + mExitConditionText = "(until condition ends)"; // TODO persist current description } } @@ -174,6 +238,59 @@ public class ZenModePanel extends LinearLayout { mCallback = callback; } + public void showSilentHint() { + if (DEBUG) Log.d(mTag, "showSilentHint"); + if (mZenButtons == null || mZenButtons.getChildCount() == 0) return; + final View noneButton = mZenButtons.getChildAt(0); + if (noneButton.getScaleX() != 1) return; // already running + noneButton.animate().cancel(); + noneButton.animate().scaleX(SILENT_HINT_PULSE_SCALE).scaleY(SILENT_HINT_PULSE_SCALE) + .setInterpolator(mFastOutSlowInInterpolator) + .setListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + noneButton.animate().scaleX(1).scaleY(1).setListener(null); + } + }); + } + + private void handleUpdateZen(int zen) { + if (mAttachedZen != -1 && mAttachedZen != zen) { + setExpanded(zen != Global.ZEN_MODE_OFF); + mAttachedZen = zen; + } + mZenButtons.setSelectedValue(zen); + updateWidgets(); + } + + private int getSelectedZen(int defValue) { + final Object zen = mZenButtons.getSelectedValue(); + return zen != null ? (Integer) zen : defValue; + } + + private void updateWidgets() { + final int zen = getSelectedZen(Global.ZEN_MODE_OFF); + final boolean zenOff = zen == Global.ZEN_MODE_OFF; + final boolean zenImportant = zen == Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS; + final boolean zenNone = zen == Global.ZEN_MODE_NO_INTERRUPTIONS; + + mZenSubhead.setVisibility(!zenOff ? VISIBLE : GONE); + mZenSubheadExpanded.setVisibility(mExpanded ? VISIBLE : GONE); + mZenSubheadCollapsed.setVisibility(!mExpanded ? VISIBLE : GONE); + mMoreSettings.setVisibility(zenImportant && mExpanded ? VISIBLE : GONE); + mZenConditions.setVisibility(!zenOff && mExpanded ? VISIBLE : GONE); + mAlarmWarning.setVisibility(zenNone && mExpanded && mController != null + && mController.hasNextAlarm() ? VISIBLE : GONE); + + if (zenNone) { + mZenSubheadExpanded.setText(R.string.zen_no_interruptions); + mZenSubheadCollapsed.setText(mExitConditionText); + } else if (zenImportant) { + mZenSubheadExpanded.setText(R.string.zen_important_interruptions); + mZenSubheadCollapsed.setText(mExitConditionText); + } + } + private Condition parseExistingTimeCondition(Uri conditionId) { final long time = ZenModeConfig.tryParseCountdownConditionId(conditionId); if (time == 0) return null; @@ -200,23 +317,23 @@ public class ZenModePanel extends LinearLayout { private void handleUpdateConditions(Condition[] conditions) { final int newCount = conditions == null ? 0 : conditions.length; - for (int i = mConditions.getChildCount() - 1; i > newCount; i--) { - mConditions.removeViewAt(i); + if (DEBUG) Log.d(mTag, "handleUpdateConditions newCount=" + newCount); + for (int i = mZenConditions.getChildCount(); i >= newCount + FIRST_CONDITION_INDEX; i--) { + mZenConditions.removeViewAt(i); } + bind(null, mZenConditions.getChildAt(FOREVER_CONDITION_INDEX)); for (int i = 0; i < newCount; i++) { - bind(conditions[i], mConditions.getChildAt(i + 1)); + bind(conditions[i], mZenConditions.getChildAt(FIRST_CONDITION_INDEX + i)); } - bind(null, mConditions.getChildAt(newCount + 1)); - checkForDefault(); } private ConditionTag getConditionTagAt(int index) { - return (ConditionTag) mConditions.getChildAt(index).getTag(); + return (ConditionTag) mZenConditions.getChildAt(index).getTag(); } private void checkForDefault() { // are we left without anything selected? if so, set a default - for (int i = 0; i < mConditions.getChildCount(); i++) { + for (int i = 0; i < mZenConditions.getChildCount(); i++) { if (getConditionTagAt(i).rb.isChecked()) { return; } @@ -224,19 +341,19 @@ public class ZenModePanel extends LinearLayout { if (DEBUG) Log.d(mTag, "Selecting a default"); final int favoriteIndex = mFavorites.getMinuteIndex(); if (favoriteIndex == -1) { - getConditionTagAt(mConditions.getChildCount() - 1).rb.setChecked(true); + getConditionTagAt(FOREVER_CONDITION_INDEX).rb.setChecked(true); } else { final Condition c = newTimeCondition(MINUTE_BUCKETS[favoriteIndex]); mBucketIndex = favoriteIndex; - bind(c, mConditions.getChildAt(0)); - getConditionTagAt(0).rb.setChecked(true); + bind(c, mZenConditions.getChildAt(TIME_CONDITION_INDEX)); + getConditionTagAt(TIME_CONDITION_INDEX).rb.setChecked(true); } } private void handleExitConditionChanged(Uri exitCondition) { - mExitConditionId = exitCondition; + setExitConditionId(exitCondition); if (DEBUG) Log.d(mTag, "handleExitConditionChanged " + mExitConditionId); - final int N = mConditions.getChildCount(); + final int N = mZenConditions.getChildCount(); for (int i = 0; i < N; i++) { final ConditionTag tag = getConditionTagAt(i); tag.rb.setChecked(Objects.equals(tag.conditionId, exitCondition)); @@ -249,7 +366,7 @@ public class ZenModePanel extends LinearLayout { if (convertView == null) { row = mInflater.inflate(R.layout.zen_mode_condition, this, false); if (DEBUG) Log.d(mTag, "Adding new condition view for: " + condition); - mConditions.addView(row); + mZenConditions.addView(row); } else { row = convertView; } @@ -264,9 +381,9 @@ public class ZenModePanel extends LinearLayout { tag.rb.setOnCheckedChangeListener(new OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { - if (mShowing && isChecked) { + if (mExpanded && isChecked) { if (DEBUG) Log.d(mTag, "onCheckedChanged " + tag.conditionId); - final int N = mConditions.getChildCount(); + final int N = mZenConditions.getChildCount(); for (int i = 0; i < N; i++) { ConditionTag childTag = getConditionTagAt(i); if (childTag == tag) continue; @@ -284,7 +401,7 @@ public class ZenModePanel extends LinearLayout { title.setText(condition.summary); } title.setEnabled(enabled); - title.setAlpha(enabled ? 1 : .5f); + title.setAlpha(enabled ? 1 : .4f); final ImageView button1 = (ImageView) row.findViewById(android.R.id.button1); button1.setOnClickListener(new OnClickListener() { @Override @@ -365,7 +482,7 @@ public class ZenModePanel extends LinearLayout { if (mController != null) { mController.setExitConditionId(conditionId); } - mExitConditionId = conditionId; + setExitConditionId(conditionId); if (conditionId == null) { mFavorites.setMinuteIndex(-1); } else if (ZenModeConfig.isValidCountdownConditionId(conditionId) && mBucketIndex != -1) { @@ -385,8 +502,18 @@ public class ZenModePanel extends LinearLayout { } } + private void fireExpanded() { + if (mCallback != null) { + mCallback.onExpanded(mExpanded); + } + } + private final ZenModeController.Callback mZenCallback = new ZenModeController.Callback() { @Override + public void onZenChanged(int zen) { + mHandler.obtainMessage(H.UPDATE_ZEN, zen, 0).sendToTarget(); + } + @Override public void onConditionsChanged(Condition[] conditions) { mHandler.obtainMessage(H.UPDATE_CONDITIONS, conditions).sendToTarget(); } @@ -400,6 +527,7 @@ public class ZenModePanel extends LinearLayout { private final class H extends Handler { private static final int UPDATE_CONDITIONS = 1; private static final int EXIT_CONDITION_CHANGED = 2; + private static final int UPDATE_ZEN = 3; private H() { super(Looper.getMainLooper()); @@ -409,8 +537,11 @@ public class ZenModePanel extends LinearLayout { public void handleMessage(Message msg) { if (msg.what == UPDATE_CONDITIONS) { handleUpdateConditions((Condition[])msg.obj); + checkForDefault(); } else if (msg.what == EXIT_CONDITION_CHANGED) { handleExitConditionChanged((Uri)msg.obj); + } else if (msg.what == UPDATE_ZEN) { + handleUpdateZen(msg.arg1); } } } @@ -418,6 +549,7 @@ public class ZenModePanel extends LinearLayout { public interface Callback { void onMoreSettings(); void onInteraction(); + void onExpanded(boolean expanded); } // used as the view tag on condition rows @@ -466,4 +598,15 @@ public class ZenModePanel extends LinearLayout { return Math.max(-1, Math.min(MINUTE_BUCKETS.length - 1, index)); } } + + private final SegmentedButtons.Callback mZenButtonsCallback = new SegmentedButtons.Callback() { + @Override + public void onSelected(Object value) { + if (value != null && mZenButtons.isShown()) { + if (DEBUG) Log.d(mTag, "mZenButtonsCallback selected=" + value); + mController.setZen((Integer) value); + mController.setExitConditionId(null); + } + } + }; } diff --git a/services/core/java/com/android/server/notification/ConditionProviders.java b/services/core/java/com/android/server/notification/ConditionProviders.java index f8ac2e480762..08c82716b630 100644 --- a/services/core/java/com/android/server/notification/ConditionProviders.java +++ b/services/core/java/com/android/server/notification/ConditionProviders.java @@ -264,7 +264,7 @@ public class ConditionProviders extends ManagedServices { mZenModeHelper.setZenMode(Settings.Global.ZEN_MODE_OFF); } else if (c.state == Condition.STATE_TRUE) { Slog.d(TAG, "Enter zen: automatic condition true: " + c); - mZenModeHelper.setZenMode(Settings.Global.ZEN_MODE_ON); + mZenModeHelper.setZenMode(Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS); } } } diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index c8496e4724c5..3a6cec22f0b4 100644 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -890,7 +890,7 @@ public class NotificationManagerService extends SystemService { // Grab our optional AudioService mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE); - + mZenModeHelper.setAudioManager(mAudioManager); } else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) { // This observer will force an update when observe is called, causing us to // bind to listener services. diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java index 7bac3dcf5cb8..92bec14ff264 100644 --- a/services/core/java/com/android/server/notification/ZenModeHelper.java +++ b/services/core/java/com/android/server/notification/ZenModeHelper.java @@ -74,6 +74,8 @@ public class ZenModeHelper { private int mZenMode; private ZenModeConfig mConfig; + private AudioManager mAudioManager; + private int mPreviousRingerMode = -1; // temporary, until we update apps to provide metadata private static final Set<String> CALL_PACKAGES = new HashSet<String>(Arrays.asList( @@ -129,13 +131,17 @@ public class ZenModeHelper { mCallbacks.add(callback); } + public void setAudioManager(AudioManager audioManager) { + mAudioManager = audioManager; + } + public boolean shouldIntercept(NotificationRecord record) { if (mZenMode != Global.ZEN_MODE_OFF) { if (isSystem(record)) { return false; } if (isAlarm(record)) { - return false; + return mZenMode == Global.ZEN_MODE_NO_INTERRUPTIONS; } // audience has veto power over all following rules if (!audienceMatches(record)) { @@ -185,6 +191,34 @@ public class ZenModeHelper { mAppOps.setRestriction(AppOpsManager.OP_VIBRATE, AudioManager.USE_DEFAULT_STREAM_TYPE, zen ? AppOpsManager.MODE_IGNORED : AppOpsManager.MODE_ALLOWED, exceptionPackages); + + // alarm restrictions + final boolean muteAlarms = mZenMode == Global.ZEN_MODE_NO_INTERRUPTIONS; + mAppOps.setRestriction(AppOpsManager.OP_VIBRATE, AudioManager.STREAM_ALARM, + muteAlarms ? AppOpsManager.MODE_IGNORED : AppOpsManager.MODE_ALLOWED, + exceptionPackages); + mAppOps.setRestriction(AppOpsManager.OP_PLAY_AUDIO, AudioManager.STREAM_ALARM, + muteAlarms ? AppOpsManager.MODE_IGNORED : AppOpsManager.MODE_ALLOWED, + exceptionPackages); + + // force ringer mode into compliance + if (mAudioManager != null) { + int ringerMode = mAudioManager.getRingerMode(); + if (mZenMode == Global.ZEN_MODE_NO_INTERRUPTIONS) { + if (ringerMode != AudioManager.RINGER_MODE_SILENT) { + mPreviousRingerMode = ringerMode; + Slog.d(TAG, "Silencing ringer"); + mAudioManager.setRingerMode(AudioManager.RINGER_MODE_SILENT); + } + } else { + if (ringerMode == AudioManager.RINGER_MODE_SILENT) { + Slog.d(TAG, "Unsilencing ringer"); + mAudioManager.setRingerMode(mPreviousRingerMode != -1 ? mPreviousRingerMode + : AudioManager.RINGER_MODE_NORMAL); + mPreviousRingerMode = -1; + } + } + } dispatchOnZenModeChanged(); } @@ -201,6 +235,7 @@ public class ZenModeHelper { pw.println(Global.zenModeToString(mZenMode)); pw.print(prefix); pw.print("mConfig="); pw.println(mConfig); pw.print(prefix); pw.print("mDefaultConfig="); pw.println(mDefaultConfig); + pw.print(prefix); pw.print("mPreviousRingerMode="); pw.println(mPreviousRingerMode); } public void readXml(XmlPullParser parser) throws XmlPullParserException, IOException { @@ -308,16 +343,6 @@ public class ZenModeHelper { return new Date(time) + " (" + time + ")"; } - public static boolean isWeekend(long time, int offsetDays) { - final Calendar c = Calendar.getInstance(); - c.setTimeInMillis(time); - if (offsetDays != 0) { - c.add(Calendar.DATE, offsetDays); - } - final int day = c.get(Calendar.DAY_OF_WEEK); - return day == Calendar.SATURDAY || day == Calendar.SUNDAY; - } - private class SettingsObserver extends ContentObserver { private final Uri ZEN_MODE = Global.getUriFor(Global.ZEN_MODE); @@ -344,31 +369,45 @@ public class ZenModeHelper { } private class ZenBroadcastReceiver extends BroadcastReceiver { + private final Calendar mCalendar = Calendar.getInstance(); + @Override public void onReceive(Context context, Intent intent) { if (ACTION_ENTER_ZEN.equals(intent.getAction())) { - setZenMode(intent, 1, Global.ZEN_MODE_ON); + setZenMode(intent, Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS); } else if (ACTION_EXIT_ZEN.equals(intent.getAction())) { - setZenMode(intent, 0, Global.ZEN_MODE_OFF); + setZenMode(intent, Global.ZEN_MODE_OFF); } } - private void setZenMode(Intent intent, int wkendOffsetDays, int zenModeValue) { + private void setZenMode(Intent intent, int zenModeValue) { final long schTime = intent.getLongExtra(EXTRA_TIME, 0); final long now = System.currentTimeMillis(); Slog.d(TAG, String.format("%s scheduled for %s, fired at %s, delta=%s", intent.getAction(), ts(schTime), ts(now), now - schTime)); - final boolean skip = ZenModeConfig.SLEEP_MODE_WEEKNIGHTS.equals(mConfig.sleepMode) && - isWeekend(schTime, wkendOffsetDays); - - if (skip) { - Slog.d(TAG, "Skipping zen mode update for the weekend"); + final int[] days = ZenModeConfig.tryParseDays(mConfig.sleepMode); + if (days != null) { + final int day = getDayOfWeek(schTime); + for (int i = 0; i < days.length; i++) { + if (days[i] == day) { + Slog.d(TAG, "Enter downtime, day=" + day + " days=" + Arrays.asList(days)); + ZenModeHelper.this.setZenMode(zenModeValue); + break; + } else { + Slog.d(TAG, "Skip downtime, day=" + day + " days=" + Arrays.asList(days)); + } + } } else { - ZenModeHelper.this.setZenMode(zenModeValue); + Slog.d(TAG, "Skip downtime, no days configured"); } updateAlarms(); } + + private int getDayOfWeek(long time) { + mCalendar.setTimeInMillis(time); + return mCalendar.get(Calendar.DAY_OF_WEEK); + } } public static class Callback { |