VolumeZen: combine ringer/notification volume and zen.
- Implement a new volume panel widget, combining volume and zen mode + conditions. - Show zen mode + conditions when modifying ringer or notification streams. - Host the volume panel widget in a dialog when being controlled by the audio service / volume keys. - Remove support for multiple sliders in the volume panel. - Remove support for separate ringer + notification volumes in the volume panel. - Move volume panel resources up to SystemUI. - Create a new combined Notifications quick settings tile. - Host the volume panel widget in the quick settings panel under Notifications. - When the quick settings detail panel is visible, route the volume keys to the embedded widget instead of showing a redundant dialog. - Create common styles for quick settings text to be closer to spec. - Update the framework resources for the ringer stream. - Show the ringer icons in global actions. - Add "until you turn this off" back as a separate zen condition. - Disable time condition buttons when they are N/A. - Don't allow volume changes to set ringer mode silent. Bug:15186070 Change-Id: Id5e321dd1d5e7c4cf3917027ffbdf7e80d38b00d
This commit is contained in:
@@ -1,23 +1,28 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
/*
|
||||
* Copyright 2013, 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.
|
||||
*/
|
||||
-->
|
||||
Copyright (C) 2014 The Android Open Source Project
|
||||
|
||||
<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:src="@drawable/ic_audio_ring_notif_am_alpha"
|
||||
android:autoMirrored="true"
|
||||
android:tint="?attr/colorControlNormal" />
|
||||
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="24.0"
|
||||
android:viewportHeight="24.0"/>
|
||||
|
||||
<path
|
||||
android:fill="#8A000000"
|
||||
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,16.0l0.0,-5.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.7c-2.9,0.7 -5.0,3.2 -5.0,6.3L5.0,16.0l-2.0,2.0l0.0,1.0l17.0,0.0l0.0,-1.0L18.0,16.0z"/>
|
||||
</vector>
|
||||
|
||||
@@ -1,23 +1,28 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
/*
|
||||
* Copyright 2013, 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.
|
||||
*/
|
||||
-->
|
||||
Copyright (C) 2014 The Android Open Source Project
|
||||
|
||||
<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:src="@drawable/ic_audio_ring_notif_mute_am_alpha"
|
||||
android:autoMirrored="true"
|
||||
android:tint="?attr/colorControlNormal" />
|
||||
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="24.0"
|
||||
android:viewportHeight="24.0"/>
|
||||
|
||||
<path
|
||||
android:fill="#8A000000"
|
||||
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>
|
||||
|
||||
@@ -1,23 +1,28 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
/*
|
||||
* Copyright 2013, 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.
|
||||
*/
|
||||
-->
|
||||
Copyright (C) 2014 The Android Open Source Project
|
||||
|
||||
<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:src="@drawable/ic_audio_ring_notif_vibrate_am_alpha"
|
||||
android:autoMirrored="true"
|
||||
android:tint="?attr/colorControlNormal" />
|
||||
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="24.0"
|
||||
android:viewportHeight="24.0"/>
|
||||
|
||||
<path
|
||||
android:fill="#8A000000"
|
||||
android:pathData="M0.0,15.0l2.0,0.0L2.0,9.0L0.0,9.0L0.0,15.0zM3.0,17.0l2.0,0.0L5.0,7.0L3.0,7.0L3.0,17.0zM22.0,9.0l0.0,6.0l2.0,0.0L24.0,9.0L22.0,9.0zM19.0,17.0l2.0,0.0L21.0,7.0l-2.0,0.0L19.0,17.0zM16.5,3.0l-9.0,0.0C6.7,3.0 6.0,3.7 6.0,4.5l0.0,15.0C6.0,20.3 6.7,21.0 7.5,21.0l9.0,0.0c0.8,0.0 1.5,-0.7 1.5,-1.5l0.0,-15.0C18.0,3.7 17.3,3.0 16.5,3.0zM16.0,19.0L8.0,19.0L8.0,5.0l8.0,0.0L16.0,19.0z"/>
|
||||
</vector>
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_marginTop="6dp"
|
||||
android:layout_marginBottom="6dp"
|
||||
android:src="@drawable/ic_audio_vol_mute"
|
||||
android:src="@drawable/ic_audio_ring_notif_mute"
|
||||
android:scaleType="center"
|
||||
android:duplicateParentState="true"
|
||||
android:background="@drawable/silent_mode_indicator"
|
||||
@@ -94,7 +94,7 @@
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_marginTop="6dp"
|
||||
android:layout_marginBottom="6dp"
|
||||
android:src="@drawable/ic_audio_vol"
|
||||
android:src="@drawable/ic_audio_ring_notif"
|
||||
android:scaleType="center"
|
||||
android:duplicateParentState="true"
|
||||
android:background="@drawable/silent_mode_indicator"
|
||||
|
||||
@@ -1,51 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2007 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/visible_panel"
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="300dp"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/slider_group"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:orientation="vertical">
|
||||
<!-- Sliders go here -->
|
||||
</LinearLayout>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/expand_button_divider"
|
||||
android:src="?attr/dividerVertical"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="32dip"
|
||||
android:scaleType="fitXY"
|
||||
android:layout_gravity="top"
|
||||
android:layout_marginTop="16dip"
|
||||
android:layout_marginBottom="16dip" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/expand_button"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="top"
|
||||
android:padding="16dip"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:src="@drawable/ic_sysbar_quicksettings" />
|
||||
|
||||
</LinearLayout>
|
||||
@@ -206,9 +206,6 @@
|
||||
<!-- Default width for a textview error popup -->
|
||||
<dimen name="textview_error_popup_default_width">240dip</dimen>
|
||||
|
||||
<!-- Volume panel y offset -->
|
||||
<dimen name="volume_panel_top">16dp</dimen>
|
||||
|
||||
<!-- Default padding to apply to AppWidgetHostViews containing widgets targeting API level 14 and up. -->
|
||||
<dimen name="default_app_widget_padding_left">8dp</dimen>
|
||||
<dimen name="default_app_widget_padding_top">8dp</dimen>
|
||||
|
||||
@@ -69,8 +69,6 @@
|
||||
<java-symbol type="id" name="edittext_container" />
|
||||
<java-symbol type="id" name="enter_pin_section" />
|
||||
<java-symbol type="id" name="expand_activities_button" />
|
||||
<java-symbol type="id" name="expand_button" />
|
||||
<java-symbol type="id" name="expand_button_divider" />
|
||||
<java-symbol type="id" name="expires_on" />
|
||||
<java-symbol type="id" name="find_next" />
|
||||
<java-symbol type="id" name="find_prev" />
|
||||
@@ -161,9 +159,7 @@
|
||||
<java-symbol type="id" name="share" />
|
||||
<java-symbol type="id" name="shortcut" />
|
||||
<java-symbol type="id" name="skip_button" />
|
||||
<java-symbol type="id" name="slider_group" />
|
||||
<java-symbol type="id" name="split_action_bar" />
|
||||
<java-symbol type="id" name="stream_icon" />
|
||||
<java-symbol type="id" name="submit_area" />
|
||||
<java-symbol type="id" name="switch_new" />
|
||||
<java-symbol type="id" name="switch_old" />
|
||||
@@ -181,7 +177,6 @@
|
||||
<java-symbol type="id" name="topPanel" />
|
||||
<java-symbol type="id" name="up" />
|
||||
<java-symbol type="id" name="value" />
|
||||
<java-symbol type="id" name="visible_panel" />
|
||||
<java-symbol type="id" name="websearch" />
|
||||
<java-symbol type="id" name="wifi_p2p_wps_pin" />
|
||||
<java-symbol type="id" name="year" />
|
||||
@@ -343,7 +338,6 @@
|
||||
<java-symbol type="dimen" name="search_view_preferred_width" />
|
||||
<java-symbol type="dimen" name="textview_error_popup_default_width" />
|
||||
<java-symbol type="dimen" name="toast_y_offset" />
|
||||
<java-symbol type="dimen" name="volume_panel_top" />
|
||||
<java-symbol type="dimen" name="action_bar_stacked_max_height" />
|
||||
<java-symbol type="dimen" name="action_bar_stacked_tab_max_width" />
|
||||
<java-symbol type="dimen" name="notification_text_size" />
|
||||
@@ -1199,8 +1193,6 @@
|
||||
<java-symbol type="layout" name="time_picker_legacy" />
|
||||
<java-symbol type="layout" name="time_picker_dialog" />
|
||||
<java-symbol type="layout" name="transient_notification" />
|
||||
<java-symbol type="layout" name="volume_adjust" />
|
||||
<java-symbol type="layout" name="volume_adjust_item" />
|
||||
<java-symbol type="layout" name="voice_interaction_session" />
|
||||
<java-symbol type="layout" name="web_text_view_dropdown" />
|
||||
<java-symbol type="layout" name="webview_find" />
|
||||
|
||||
@@ -112,6 +112,9 @@ public class AudioService extends IAudioService.Stub {
|
||||
private static final boolean USE_SESSIONS = true;
|
||||
private static final boolean DEBUG_SESSIONS = true;
|
||||
|
||||
/** Allow volume changes to set ringer mode to silent? */
|
||||
private static final boolean VOLUME_SETS_RINGER_MODE_SILENT = false;
|
||||
|
||||
/** How long to delay before persisting a change in volume/ringer mode. */
|
||||
private static final int PERSIST_DELAY = 500;
|
||||
|
||||
@@ -1019,7 +1022,8 @@ public class AudioService extends IAudioService.Stub {
|
||||
int newRingerMode;
|
||||
if (index == 0) {
|
||||
newRingerMode = mHasVibrator ? AudioManager.RINGER_MODE_VIBRATE
|
||||
: AudioManager.RINGER_MODE_SILENT;
|
||||
: VOLUME_SETS_RINGER_MODE_SILENT ? AudioManager.RINGER_MODE_SILENT
|
||||
: AudioManager.RINGER_MODE_NORMAL;
|
||||
} else {
|
||||
newRingerMode = AudioManager.RINGER_MODE_NORMAL;
|
||||
}
|
||||
@@ -2552,7 +2556,9 @@ public class AudioService extends IAudioService.Stub {
|
||||
}
|
||||
} else {
|
||||
// (oldIndex < step) is equivalent to (old UI index == 0)
|
||||
if ((oldIndex < step) && mPrevVolDirection != AudioManager.ADJUST_LOWER) {
|
||||
if ((oldIndex < step)
|
||||
&& VOLUME_SETS_RINGER_MODE_SILENT
|
||||
&& mPrevVolDirection != AudioManager.ADJUST_LOWER) {
|
||||
ringerMode = RINGER_MODE_SILENT;
|
||||
}
|
||||
}
|
||||
@@ -2565,7 +2571,8 @@ public class AudioService extends IAudioService.Stub {
|
||||
break;
|
||||
}
|
||||
if ((direction == AudioManager.ADJUST_LOWER)) {
|
||||
if (mPrevVolDirection != AudioManager.ADJUST_LOWER) {
|
||||
if (VOLUME_SETS_RINGER_MODE_SILENT
|
||||
&& mPrevVolDirection != AudioManager.ADJUST_LOWER) {
|
||||
ringerMode = RINGER_MODE_SILENT;
|
||||
}
|
||||
} else if (direction == AudioManager.ADJUST_RAISE) {
|
||||
|
||||
@@ -24,5 +24,5 @@ Copyright (C) 2014 The Android Open Source Project
|
||||
|
||||
<path
|
||||
android:fill="#FFFFFFFF"
|
||||
android:pathData="M6.6,3.6L5.2,2.2C2.8,4.0 1.2,6.8 1.0,10.0l2.0,0.0C3.2,7.3 4.5,5.0 6.6,3.6zM20.0,10.0l2.0,0.0c-0.2,-3.2 -1.7,-6.0 -4.1,-7.8l-1.4,1.4C18.5,5.0 19.8,7.3 20.0,10.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.7c-2.9,0.7 -5.0,3.2 -5.0,6.3L5.0,16.0l-2.0,2.0l0.0,1.0l17.0,0.0l0.0,-1.0l-2.0,-2.0L18.0,10.5zM11.5,22.0c0.1,0.0 0.3,0.0 0.4,0.0c0.7,-0.1 1.2,-0.6 1.4,-1.2c0.1,-0.2 0.2,-0.5 0.2,-0.8l-4.0,0.0C9.5,21.1 10.4,22.0 11.5,22.0z" />
|
||||
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,16.0l0.0,-5.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.7c-2.9,0.7 -5.0,3.2 -5.0,6.3L5.0,16.0l-2.0,2.0l0.0,1.0l17.0,0.0l0.0,-1.0L18.0,16.0z"/>
|
||||
</vector>
|
||||
|
||||
28
packages/SystemUI/res/drawable/ic_ringer_audible.xml
Normal file
28
packages/SystemUI/res/drawable/ic_ringer_audible.xml
Normal file
@@ -0,0 +1,28 @@
|
||||
<!--
|
||||
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="24.0"
|
||||
android:viewportHeight="24.0"/>
|
||||
|
||||
<path
|
||||
android:fill="#FFFFFFFF"
|
||||
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,16.0l0.0,-5.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.7c-2.9,0.7 -5.0,3.2 -5.0,6.3L5.0,16.0l-2.0,2.0l0.0,1.0l17.0,0.0l0.0,-1.0L18.0,16.0z"/>
|
||||
</vector>
|
||||
28
packages/SystemUI/res/drawable/ic_ringer_silent.xml
Normal file
28
packages/SystemUI/res/drawable/ic_ringer_silent.xml
Normal file
@@ -0,0 +1,28 @@
|
||||
<!--
|
||||
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="24.0"
|
||||
android:viewportHeight="24.0"/>
|
||||
|
||||
<path
|
||||
android:fill="#FFFFFFFF"
|
||||
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>
|
||||
28
packages/SystemUI/res/drawable/ic_ringer_vibrate.xml
Normal file
28
packages/SystemUI/res/drawable/ic_ringer_vibrate.xml
Normal file
@@ -0,0 +1,28 @@
|
||||
<!--
|
||||
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="24.0"
|
||||
android:viewportHeight="24.0"/>
|
||||
|
||||
<path
|
||||
android:fill="#FFFFFFFF"
|
||||
android:pathData="M0.0,15.0l2.0,0.0L2.0,9.0L0.0,9.0L0.0,15.0zM3.0,17.0l2.0,0.0L5.0,7.0L3.0,7.0L3.0,17.0zM22.0,9.0l0.0,6.0l2.0,0.0L24.0,9.0L22.0,9.0zM19.0,17.0l2.0,0.0L21.0,7.0l-2.0,0.0L19.0,17.0zM16.5,3.0l-9.0,0.0C6.7,3.0 6.0,3.7 6.0,4.5l0.0,15.0C6.0,20.3 6.7,21.0 7.5,21.0l9.0,0.0c0.8,0.0 1.5,-0.7 1.5,-1.5l0.0,-15.0C18.0,3.7 17.3,3.0 16.5,3.0zM16.0,19.0L8.0,19.0L8.0,5.0l8.0,0.0L16.0,19.0z"/>
|
||||
</vector>
|
||||
30
packages/SystemUI/res/drawable/ic_vol_zen_off.xml
Normal file
30
packages/SystemUI/res/drawable/ic_vol_zen_off.xml
Normal file
@@ -0,0 +1,30 @@
|
||||
<!--
|
||||
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="24.0"
|
||||
android:viewportHeight="24.0"/>
|
||||
|
||||
<path
|
||||
android:fill="#00000000"
|
||||
android:stroke="#CCCCCC"
|
||||
android:strokeWidth="1.0"
|
||||
android:pathData="M12.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.0zM4.0,12.0c0.0,-4.4 3.6,-8.0 8.0,-8.0c1.8,0.0 3.5,0.6 4.9,1.7L5.7,16.9C4.6,15.5 4.0,13.8 4.0,12.0zM12.0,20.0c-1.8,0.0 -3.5,-0.6 -4.9,-1.7L18.3,7.1C19.4,8.5 20.0,10.2 20.0,12.0C20.0,16.4 16.4,20.0 12.0,20.0z" />
|
||||
</vector>
|
||||
28
packages/SystemUI/res/drawable/ic_vol_zen_on.xml
Normal file
28
packages/SystemUI/res/drawable/ic_vol_zen_on.xml
Normal file
@@ -0,0 +1,28 @@
|
||||
<!--
|
||||
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="24.0"
|
||||
android:viewportHeight="24.0"/>
|
||||
|
||||
<path
|
||||
android:fill="#FFFFFFFF"
|
||||
android:pathData="M12.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.0zM4.0,12.0c0.0,-4.4 3.6,-8.0 8.0,-8.0c1.8,0.0 3.5,0.6 4.9,1.7L5.7,16.9C4.6,15.5 4.0,13.8 4.0,12.0zM12.0,20.0c-1.8,0.0 -3.5,-0.6 -4.9,-1.7L18.3,7.1C19.4,8.5 20.0,10.2 20.0,12.0C20.0,16.4 16.4,20.0 12.0,20.0z" />
|
||||
</vector>
|
||||
@@ -14,64 +14,44 @@
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<com.android.systemui.qs.tiles.ZenModeDetail xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@color/system_secondary_color" >
|
||||
android:background="@color/system_primary_color" >
|
||||
|
||||
<ImageView
|
||||
android:id="@android:id/button1"
|
||||
android:src="@drawable/ic_qs_close"
|
||||
android:layout_width="64dp"
|
||||
android:layout_height="64dp"
|
||||
android:layout_alignParentStart="true"
|
||||
android:padding="@dimen/qs_panel_padding" />
|
||||
|
||||
<Switch
|
||||
android:id="@android:id/checkbox"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="64dp"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:gravity="center"
|
||||
android:padding="@dimen/qs_panel_padding" />
|
||||
android:contentDescription="@string/accessibility_quick_settings_close"
|
||||
android:padding="@dimen/qs_panel_padding"
|
||||
android:src="@drawable/ic_qs_close" />
|
||||
|
||||
<TextView
|
||||
android:id="@android:id/title"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="64dp"
|
||||
android:layout_alignParentTop="true"
|
||||
android:layout_toEndOf="@android:id/button1"
|
||||
android:layout_toStartOf="@android:id/checkbox"
|
||||
android:textAppearance="@style/TextAppearance.StatusBar.Expanded.Clock"
|
||||
android:gravity="center_vertical"
|
||||
android:paddingStart="@dimen/qs_panel_padding"
|
||||
android:text="@string/zen_mode_title" />
|
||||
android:textAppearance="@style/TextAppearance.QS.DetailHeader" />
|
||||
|
||||
<View
|
||||
<ImageView
|
||||
android:id="@android:id/custom"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="2dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@android:id/title"
|
||||
android:background="#888" />
|
||||
android:layout_marginLeft="16dip"
|
||||
android:layout_marginRight="16dip"
|
||||
android:scaleType="fitXY"
|
||||
android:src="?android:attr/dividerHorizontal" />
|
||||
|
||||
<ListView
|
||||
<FrameLayout
|
||||
android:id="@android:id/content"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_above="@android:id/button2"
|
||||
android:layout_below="@android:id/custom"
|
||||
android:divider="#00000000"
|
||||
android:dividerHeight="0px" />
|
||||
android:layout_below="@android:id/custom" />
|
||||
|
||||
<TextView
|
||||
android:id="@android:id/button2"
|
||||
style="@style/QSBorderless"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:textAppearance="@style/TextAppearance.StatusBar.Expanded.Clock"
|
||||
android:padding="@dimen/qs_panel_padding"
|
||||
android:text="@string/quick_settings_more_settings"
|
||||
android:textAllCaps="true" />
|
||||
|
||||
</com.android.systemui.qs.tiles.ZenModeDetail>
|
||||
</RelativeLayout>
|
||||
@@ -27,7 +27,7 @@
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@*android:dimen/volume_panel_top"
|
||||
android:layout_marginTop="@dimen/volume_panel_top"
|
||||
android:background="@*android:drawable/dialog_full_holo_dark">
|
||||
<ListView android:id="@android:id/list"
|
||||
android:layout_width="match_parent"
|
||||
|
||||
67
packages/SystemUI/res/layout/volume_panel.xml
Normal file
67
packages/SystemUI/res/layout/volume_panel.xml
Normal file
@@ -0,0 +1,67 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2007 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.
|
||||
-->
|
||||
<RelativeLayout 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" >
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/slider_panel"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_toLeftOf="@+id/expand_button_divider" />
|
||||
|
||||
<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
|
||||
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:layout="@layout/zen_mode_panel" />
|
||||
|
||||
</RelativeLayout>
|
||||
@@ -27,7 +27,7 @@
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingLeft="16dip"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:contentDescription="@null" />
|
||||
|
||||
<SeekBar
|
||||
@@ -16,44 +16,47 @@
|
||||
-->
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" >
|
||||
android:layout_height="wrap_content" >
|
||||
|
||||
<RadioButton
|
||||
android:id="@android:id/checkbox"
|
||||
android:layout_width="32dp"
|
||||
android:layout_height="64dp"
|
||||
android:layout_height="@dimen/zen_mode_condition_height"
|
||||
android:layout_alignParentStart="true"
|
||||
android:layout_marginStart="@dimen/qs_panel_padding"
|
||||
android:gravity="center" />
|
||||
|
||||
<TextView
|
||||
android:id="@android:id/title"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="64dp"
|
||||
android:layout_height="@dimen/zen_mode_condition_height"
|
||||
android:layout_toEndOf="@android:id/checkbox"
|
||||
android:layout_toStartOf="@android:id/button1"
|
||||
android:ellipsize="end"
|
||||
android:textAppearance="@style/TextAppearance.StatusBar.Expanded.Clock"
|
||||
android:gravity="center_vertical"
|
||||
android:maxLines="1"
|
||||
android:text="@string/accessibility_back" />
|
||||
android:textAppearance="@style/TextAppearance.QS.DetailItemPrimary" />
|
||||
|
||||
<ImageView
|
||||
android:id="@android:id/button1"
|
||||
android:src="@drawable/ic_qs_minus"
|
||||
android:layout_width="64dp"
|
||||
android:layout_height="64dp"
|
||||
style="@style/BorderlessButton"
|
||||
android:layout_width="@dimen/zen_mode_condition_height"
|
||||
android:layout_height="@dimen/zen_mode_condition_height"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_marginEnd="48dp"
|
||||
android:padding="@dimen/qs_panel_padding"
|
||||
android:paddingRight="0px" />
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_marginEnd="@dimen/zen_mode_condition_height"
|
||||
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"
|
||||
android:src="@drawable/ic_qs_plus"
|
||||
android:layout_width="64dp"
|
||||
android:layout_height="64dp"
|
||||
style="@style/BorderlessButton"
|
||||
android:layout_width="@dimen/zen_mode_condition_height"
|
||||
android:layout_height="@dimen/zen_mode_condition_height"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:padding="@dimen/qs_panel_padding" />
|
||||
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>
|
||||
</RelativeLayout>
|
||||
51
packages/SystemUI/res/layout/zen_mode_panel.xml
Normal file
51
packages/SystemUI/res/layout/zen_mode_panel.xml
Normal file
@@ -0,0 +1,51 @@
|
||||
<?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.
|
||||
-->
|
||||
<!-- extends LinearLayout -->
|
||||
<com.android.systemui.volume.ZenModePanel xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/zen_mode_panel"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@color/system_primary_color"
|
||||
android:orientation="vertical"
|
||||
android:padding="@dimen/qs_panel_padding" >
|
||||
|
||||
<TextView
|
||||
android:id="@android:id/title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentStart="true"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:text="@string/zen_mode_title"
|
||||
android:textAppearance="@style/TextAppearance.QS.DetailHeader" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@android:id/content"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical" />
|
||||
|
||||
<TextView
|
||||
android:id="@android:id/button2"
|
||||
style="@style/BorderlessButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_gravity="end"
|
||||
android:text="@string/quick_settings_more_settings"
|
||||
android:textAppearance="@style/TextAppearance.QS.DetailButton" />
|
||||
|
||||
</com.android.systemui.volume.ZenModePanel>
|
||||
@@ -135,5 +135,8 @@
|
||||
<!-- Defines the implementation of the velocity tracker to be used for the panel expansion. Can
|
||||
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>
|
||||
</resources>
|
||||
|
||||
|
||||
@@ -199,6 +199,9 @@
|
||||
<!-- 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>
|
||||
|
||||
@@ -291,4 +294,9 @@
|
||||
<dimen name="keyguard_clock_notifications_margin_min">22dp</dimen>
|
||||
<dimen name="keyguard_clock_notifications_margin_max">36dp</dimen>
|
||||
|
||||
<!-- Volume panel dialog y offset -->
|
||||
<dimen name="volume_panel_top">16dp</dimen>
|
||||
|
||||
<!-- Volume panel dialog width -->
|
||||
<dimen name="volume_panel_width">300dp</dimen>
|
||||
</resources>
|
||||
|
||||
@@ -388,6 +388,12 @@
|
||||
<string name="accessibility_quick_settings_location">Location <xliff:g id="state" example="Off">%s</xliff:g>.</string>
|
||||
<!-- Content description of the alarm tile in quick settings (not shown on the screen). [CHAR LIMIT=NONE] -->
|
||||
<string name="accessibility_quick_settings_alarm">Alarm set for <xliff:g id="time" example="Wed 3:30 PM">%s</xliff:g>.</string>
|
||||
<!-- Content description of quick settings detail panel close button (not shown on the screen). [CHAR LIMIT=NONE] -->
|
||||
<string name="accessibility_quick_settings_close">Close panel</string>
|
||||
<!-- Content description of zen mode time condition plus button (not shown on the screen). [CHAR LIMIT=NONE] -->
|
||||
<string name="accessibility_quick_settings_more_time">More time</string>
|
||||
<!-- Content description of zen mode time condition minus button (not shown on the screen). [CHAR LIMIT=NONE] -->
|
||||
<string name="accessibility_quick_settings_less_time">Less time</string>
|
||||
|
||||
<!-- Title of dialog shown when 2G-3G data usage has exceeded limit and has been disabled. [CHAR LIMIT=48] -->
|
||||
<string name="data_usage_disabled_dialog_3g_title">2G-3G data disabled</string>
|
||||
@@ -512,6 +518,8 @@
|
||||
<string name="quick_settings_tethering_label">Tethering</string>
|
||||
<!-- QuickSettings: Hotspot. [CHAR LIMIT=NONE] -->
|
||||
<string name="quick_settings_hotspot_label">Hotspot</string>
|
||||
<!-- QuickSettings: Notifications [CHAR LIMIT=NONE] -->
|
||||
<string name="quick_settings_notifications_label">Notifications</string>
|
||||
|
||||
<!-- Recents: The empty recents string. [CHAR LIMIT=NONE] -->
|
||||
<string name="recents_empty_message">RECENTS</string>
|
||||
@@ -563,4 +571,19 @@
|
||||
<string name="keyguard_unlock">Swipe up to unlock</string>
|
||||
|
||||
<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>
|
||||
|
||||
<!-- Zen mode condition: time duration in minutes. [CHAR LIMIT=NONE] -->
|
||||
<plurals name="zen_mode_duration_minutes">
|
||||
<item quantity="one">For one minute</item>
|
||||
<item quantity="other">For %d minutes</item>
|
||||
</plurals>
|
||||
|
||||
<!-- Zen mode condition: time duration in hours. [CHAR LIMIT=NONE] -->
|
||||
<plurals name="zen_mode_duration_hours">
|
||||
<item quantity="one">For one hour</item>
|
||||
<item quantity="other">For %d hours</item>
|
||||
</plurals>
|
||||
</resources>
|
||||
|
||||
@@ -133,6 +133,32 @@
|
||||
<item name="android:fadingEdge">horizontal</item>
|
||||
</style>
|
||||
|
||||
<style name="TextAppearance.QS">
|
||||
<item name="android:textStyle">normal</item>
|
||||
<item name="android:textColor">#ffffff</item>
|
||||
<item name="android:fontFamily">sans-serif</item>
|
||||
</style>
|
||||
|
||||
<style name="TextAppearance.QS.DetailHeader">
|
||||
<item name="android:textSize">20sp</item>
|
||||
<item name="android:fontFamily">sans-serif-medium</item>
|
||||
</style>
|
||||
|
||||
<style name="TextAppearance.QS.DetailItemPrimary">
|
||||
<item name="android:textSize">16sp</item>
|
||||
</style>
|
||||
|
||||
<style name="TextAppearance.QS.DetailItemSecondary">
|
||||
<item name="android:textSize">14sp</item>
|
||||
<item name="android:textColor">#7fcac3</item>
|
||||
</style>
|
||||
|
||||
<style name="TextAppearance.QS.DetailButton">
|
||||
<item name="android:textSize">14sp</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>
|
||||
@@ -192,9 +218,9 @@
|
||||
<item name="android:colorControlActivated">@color/system_accent_color</item>
|
||||
</style>
|
||||
|
||||
<style name="QSBorderless" parent="@android:style/Widget.Quantum.Button.Borderless" />
|
||||
<style name="BorderlessButton" parent="@android:style/Widget.Quantum.Button.Borderless" />
|
||||
|
||||
<style name="QSBorderless.Tiny">
|
||||
<style name="BorderlessButton.Tiny">
|
||||
<item name="android:minHeight">12dip</item>
|
||||
<item name="android:minWidth">12dip</item>
|
||||
</style>
|
||||
|
||||
@@ -42,12 +42,12 @@ public class SystemUIApplication extends Application {
|
||||
private final Class<?>[] SERVICES = new Class[] {
|
||||
com.android.systemui.keyguard.KeyguardViewMediator.class,
|
||||
com.android.systemui.recent.Recents.class,
|
||||
com.android.systemui.volume.VolumeUI.class,
|
||||
com.android.systemui.statusbar.SystemBars.class,
|
||||
com.android.systemui.usb.StorageNotification.class,
|
||||
com.android.systemui.power.PowerUI.class,
|
||||
com.android.systemui.media.RingtonePlayer.class,
|
||||
com.android.systemui.settings.SettingsUI.class,
|
||||
com.android.systemui.volume.VolumeUI.class,
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -26,6 +26,7 @@ import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import com.android.systemui.R;
|
||||
import com.android.systemui.qs.QSTile.State;
|
||||
import com.android.systemui.statusbar.policy.BluetoothController;
|
||||
import com.android.systemui.statusbar.policy.CastController;
|
||||
@@ -35,6 +36,7 @@ import com.android.systemui.statusbar.policy.NetworkController;
|
||||
import com.android.systemui.statusbar.policy.RotationLockController;
|
||||
import com.android.systemui.statusbar.policy.TetheringController;
|
||||
import com.android.systemui.statusbar.policy.ZenModeController;
|
||||
import com.android.systemui.volume.VolumeComponent;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
@@ -49,12 +51,12 @@ import java.util.Objects;
|
||||
public abstract class QSTile<TState extends State> implements Listenable {
|
||||
protected final String TAG = "QSTile." + getClass().getSimpleName();
|
||||
protected static final boolean DEBUG = false;
|
||||
public static final int FEEDBACK_START_DELAY = 400;
|
||||
|
||||
protected final Host mHost;
|
||||
protected final Context mContext;
|
||||
protected final H mHandler;
|
||||
protected final Handler mUiHandler = new Handler(Looper.getMainLooper());
|
||||
private final int mFeedbackStartDelay;
|
||||
|
||||
private Callback mCallback;
|
||||
protected final TState mState = newTileState();
|
||||
@@ -68,6 +70,7 @@ public abstract class QSTile<TState extends State> implements Listenable {
|
||||
mHost = host;
|
||||
mContext = host.getContext();
|
||||
mHandler = new H(host.getLooper());
|
||||
mFeedbackStartDelay = mContext.getResources().getInteger(R.integer.feedback_start_delay);
|
||||
}
|
||||
|
||||
public boolean supportsDualTargets() {
|
||||
@@ -116,6 +119,10 @@ public abstract class QSTile<TState extends State> implements Listenable {
|
||||
mHandler.obtainMessage(H.USER_SWITCH, newUserId).sendToTarget();
|
||||
}
|
||||
|
||||
protected void postAfterFeedback(Runnable runnable) {
|
||||
mHandler.postDelayed(runnable, mFeedbackStartDelay);
|
||||
}
|
||||
|
||||
// call only on tile worker looper
|
||||
|
||||
private void handleSetCallback(Callback callback) {
|
||||
@@ -213,6 +220,7 @@ public abstract class QSTile<TState extends State> implements Listenable {
|
||||
ZenModeController getZenModeController();
|
||||
TetheringController getTetheringController();
|
||||
CastController getCastController();
|
||||
VolumeComponent getVolumeComponent();
|
||||
}
|
||||
|
||||
public static class State {
|
||||
|
||||
@@ -84,7 +84,8 @@ public class QSTileView extends ViewGroup {
|
||||
removeView(mLabel);
|
||||
}
|
||||
final Resources res = mContext.getResources();
|
||||
mLabel = new TextView(mDual ? new ContextThemeWrapper(mContext, R.style.QSBorderless_Tiny)
|
||||
mLabel = new TextView(mDual
|
||||
? new ContextThemeWrapper(mContext, R.style.BorderlessButton_Tiny)
|
||||
: mContext);
|
||||
mLabel.setId(android.R.id.title);
|
||||
mLabel.setTextColor(res.getColor(R.color.qs_tile_text));
|
||||
|
||||
@@ -58,13 +58,13 @@ public class BugreportTile extends QSTile<QSTile.State> {
|
||||
|
||||
@Override
|
||||
protected void handleClick() {
|
||||
mHandler.postDelayed(new Runnable() {
|
||||
postAfterFeedback(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
mHost.collapsePanels();
|
||||
mUiHandler.post(mShowDialog);
|
||||
}
|
||||
}, FEEDBACK_START_DELAY);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -65,12 +65,12 @@ public class CastTile extends QSTile<QSTile.BooleanState> {
|
||||
|
||||
@Override
|
||||
protected void handleClick() {
|
||||
mHandler.postDelayed(new Runnable() {
|
||||
postAfterFeedback(new Runnable() {
|
||||
public void run() {
|
||||
mHost.collapsePanels();
|
||||
mUiHandler.post(mShowDialog);
|
||||
}
|
||||
}, FEEDBACK_START_DELAY);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,172 @@
|
||||
/*
|
||||
* 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.ContextThemeWrapper;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.View.OnAttachStateChangeListener;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
|
||||
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 View createDetailView(Context context, ViewGroup root) {
|
||||
final Context themedContext = new ContextThemeWrapper(mContext, R.style.QSAccentTheme);
|
||||
final View v = LayoutInflater.from(themedContext).inflate(R.layout.qs_detail, root, false);
|
||||
final TextView title = (TextView) v.findViewById(android.R.id.title);
|
||||
title.setText(R.string.quick_settings_notifications_label);
|
||||
final View close = v.findViewById(android.R.id.button1);
|
||||
close.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
showDetail(false);
|
||||
}
|
||||
});
|
||||
final ViewGroup content = (ViewGroup) v.findViewById(android.R.id.content);
|
||||
final VolumeComponent volumeComponent = mHost.getVolumeComponent();
|
||||
final VolumePanel vp = new VolumePanel(mContext, content, mZenController);
|
||||
v.addOnAttachStateChangeListener(new OnAttachStateChangeListener() {
|
||||
@Override
|
||||
public void onViewDetachedFromWindow(View v) {
|
||||
volumeComponent.setVolumePanel(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewAttachedToWindow(View v) {
|
||||
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_NOTIFICATION, AudioManager.FLAG_SHOW_UI);
|
||||
return v;
|
||||
}
|
||||
|
||||
@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() {
|
||||
if (mState.zen) {
|
||||
mZenController.setZen(false);
|
||||
} else {
|
||||
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();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -1,108 +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 com.android.systemui.R;
|
||||
import com.android.systemui.qs.QSTile;
|
||||
|
||||
/** Quick settings tile: Ringer mode **/
|
||||
public class RingerModeTile extends QSTile<RingerModeTile.IntState> {
|
||||
|
||||
private final AudioManager mAudioManager;
|
||||
|
||||
public RingerModeTile(Host host) {
|
||||
super(host);
|
||||
mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected IntState newTileState() {
|
||||
return new IntState();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setListening(boolean listening) {
|
||||
if (listening) {
|
||||
final IntentFilter filter = new IntentFilter(AudioManager.RINGER_MODE_CHANGED_ACTION);
|
||||
mContext.registerReceiver(mReceiver, filter);
|
||||
} else {
|
||||
mContext.unregisterReceiver(mReceiver);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void handleClick() {
|
||||
final int oldValue = (Integer) mState.value;
|
||||
final int newValue =
|
||||
oldValue == AudioManager.RINGER_MODE_NORMAL ? AudioManager.RINGER_MODE_VIBRATE
|
||||
: oldValue == AudioManager.RINGER_MODE_VIBRATE ? AudioManager.RINGER_MODE_SILENT
|
||||
: AudioManager.RINGER_MODE_NORMAL;
|
||||
|
||||
mAudioManager.setRingerMode(newValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void handleUpdateState(IntState state, Object arg) {
|
||||
final int ringerMode = mAudioManager.getRingerMode();
|
||||
state.visible = true;
|
||||
state.value = ringerMode;
|
||||
if (ringerMode == AudioManager.RINGER_MODE_VIBRATE) {
|
||||
state.iconId = R.drawable.ic_qs_ringer_vibrate;
|
||||
state.label = "Vibrate";
|
||||
} else if (ringerMode == AudioManager.RINGER_MODE_SILENT) {
|
||||
state.iconId = R.drawable.ic_qs_ringer_silent;
|
||||
state.label = "Silent";
|
||||
} else {
|
||||
state.iconId = R.drawable.ic_qs_ringer_audible;
|
||||
state.label = "Audible";
|
||||
}
|
||||
}
|
||||
|
||||
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
if (AudioManager.RINGER_MODE_CHANGED_ACTION.equals(intent.getAction())) {
|
||||
refreshState();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
public static class IntState extends QSTile.State {
|
||||
public int value;
|
||||
|
||||
@Override
|
||||
public boolean copyTo(State other) {
|
||||
final IntState o = (IntState) other;
|
||||
final boolean changed = o.value != value;
|
||||
o.value = value;
|
||||
return super.copyTo(other) || changed;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected StringBuilder toStringBuilder() {
|
||||
final StringBuilder rt = super.toStringBuilder();
|
||||
rt.insert(rt.length() - 1, ",value=" + value);
|
||||
return rt;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,273 +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.Context;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.os.Message;
|
||||
import android.provider.Settings;
|
||||
import android.service.notification.Condition;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.ContextThemeWrapper;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.CompoundButton;
|
||||
import android.widget.CompoundButton.OnCheckedChangeListener;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.ListView;
|
||||
import android.widget.RadioButton;
|
||||
import android.widget.RelativeLayout;
|
||||
import android.widget.Switch;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.android.systemui.R;
|
||||
import com.android.systemui.qs.QSTile;
|
||||
import com.android.systemui.statusbar.policy.ZenModeController;
|
||||
|
||||
import java.util.HashSet;
|
||||
|
||||
/** Quick settings control panel: Zen mode **/
|
||||
public class ZenModeDetail extends RelativeLayout {
|
||||
private static final String TAG = "ZenModeDetail";
|
||||
private static final Intent ZEN_SETTINGS = new Intent(Settings.ACTION_ZEN_MODE_SETTINGS);
|
||||
private static final int[] MINUTES = new int[] { 15, 30, 45, 60, 120, 180, 240, 480 };
|
||||
|
||||
private final H mHandler = new H();
|
||||
|
||||
private int mMinutesIndex = 3;
|
||||
private Context mContext;
|
||||
private ZenModeTile mTile;
|
||||
private QSTile.Host mHost;
|
||||
private ZenModeController mController;
|
||||
|
||||
private Switch mSwitch;
|
||||
private ConditionAdapter mAdapter;
|
||||
|
||||
public ZenModeDetail(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
}
|
||||
|
||||
public void init(ZenModeTile tile) {
|
||||
mTile = tile;
|
||||
mHost = mTile.getHost();
|
||||
mContext = getContext();
|
||||
mController = mHost.getZenModeController();
|
||||
|
||||
final ImageView close = (ImageView) findViewById(android.R.id.button1);
|
||||
close.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
mTile.showDetail(false);
|
||||
}
|
||||
});
|
||||
mSwitch = (Switch) findViewById(android.R.id.checkbox);
|
||||
mSwitch.setOnCheckedChangeListener(new OnCheckedChangeListener() {
|
||||
@Override
|
||||
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
|
||||
mController.setZen(isChecked);
|
||||
}
|
||||
});
|
||||
mSwitch.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
final boolean isChecked = mSwitch.isChecked();
|
||||
mController.setZen(isChecked);
|
||||
if (!isChecked) {
|
||||
mTile.showDetail(false);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
final View moreSettings = findViewById(android.R.id.button2);
|
||||
moreSettings.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
mHost.startSettingsActivity(ZEN_SETTINGS);
|
||||
mTile.showDetail(false);
|
||||
}
|
||||
});
|
||||
final ListView conditions = (ListView) findViewById(android.R.id.content);
|
||||
mAdapter = new ConditionAdapter(mContext);
|
||||
conditions.setAdapter(mAdapter);
|
||||
mAdapter.add(updateTimeCondition());
|
||||
|
||||
updateZen(mController.isZen());
|
||||
}
|
||||
|
||||
private Condition updateTimeCondition() {
|
||||
final int minutes = MINUTES[mMinutesIndex];
|
||||
final long millis = System.currentTimeMillis() + minutes * 60 * 1000;
|
||||
final Uri id = new Uri.Builder().scheme(Condition.SCHEME).authority("android")
|
||||
.appendPath("countdown").appendPath(Long.toString(millis)).build();
|
||||
final int num = minutes < 60 ? minutes : minutes / 60;
|
||||
final String units = minutes < 60 ? "minutes" : minutes == 60 ? "hour" : "hours";
|
||||
return new Condition(id, "For " + num + " " + units, "", "", 0, Condition.STATE_TRUE,
|
||||
Condition.FLAG_RELEVANT_NOW);
|
||||
}
|
||||
|
||||
private void editTimeCondition(int delta) {
|
||||
final int i = mMinutesIndex + delta;
|
||||
if (i < 0 || i >= MINUTES.length) return;
|
||||
mMinutesIndex = i;
|
||||
mAdapter.remove(mAdapter.getItem(0));
|
||||
final Condition c = updateTimeCondition();
|
||||
mAdapter.insert(c, 0);
|
||||
select(c);
|
||||
}
|
||||
|
||||
private void select(Condition condition) {
|
||||
mController.select(condition);
|
||||
}
|
||||
|
||||
private void updateZen(boolean zen) {
|
||||
mHandler.obtainMessage(H.UPDATE_ZEN, zen ? 1 : 0, 0).sendToTarget();
|
||||
}
|
||||
|
||||
private void updateConditions(Condition[] conditions) {
|
||||
if (conditions == null) return;
|
||||
mHandler.obtainMessage(H.UPDATE_CONDITIONS, conditions).sendToTarget();
|
||||
}
|
||||
|
||||
private void handleUpdateZen(boolean zen) {
|
||||
mSwitch.setChecked(zen);
|
||||
}
|
||||
|
||||
private void handleUpdateConditions(Condition[] conditions) {
|
||||
for (int i = mAdapter.getCount() - 1; i > 0; i--) {
|
||||
mAdapter.remove(mAdapter.getItem(i));
|
||||
}
|
||||
for (Condition condition : conditions) {
|
||||
mAdapter.add(condition);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onAttachedToWindow() {
|
||||
super.onAttachedToWindow();
|
||||
mController.addCallback(mCallback);
|
||||
mController.requestConditions(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDetachedFromWindow() {
|
||||
super.onDetachedFromWindow();
|
||||
mController.removeCallback(mCallback);
|
||||
mController.requestConditions(false);
|
||||
}
|
||||
|
||||
private final class H extends Handler {
|
||||
private static final int UPDATE_ZEN = 1;
|
||||
private static final int UPDATE_CONDITIONS = 2;
|
||||
|
||||
public H() {
|
||||
super(Looper.getMainLooper());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleMessage(Message msg) {
|
||||
if (msg.what == UPDATE_ZEN) {
|
||||
handleUpdateZen(msg.arg1 == 1);
|
||||
} else if (msg.what == UPDATE_CONDITIONS) {
|
||||
handleUpdateConditions((Condition[])msg.obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private final ZenModeController.Callback mCallback = new ZenModeController.Callback() {
|
||||
@Override
|
||||
public void onZenChanged(boolean zen) {
|
||||
updateZen(zen);
|
||||
}
|
||||
public void onConditionsChanged(Condition[] conditions) {
|
||||
updateConditions(conditions);
|
||||
}
|
||||
};
|
||||
|
||||
private final class ConditionAdapter extends ArrayAdapter<Condition> {
|
||||
private final LayoutInflater mInflater;
|
||||
private final HashSet<RadioButton> mRadioButtons = new HashSet<RadioButton>();
|
||||
|
||||
public ConditionAdapter(Context context) {
|
||||
super(context, 0);
|
||||
mInflater = LayoutInflater.from(new ContextThemeWrapper(context, R.style.QSWhiteTheme));
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(int position, View convertView, ViewGroup parent) {
|
||||
final Condition condition = getItem(position);
|
||||
final boolean enabled = condition.state == Condition.STATE_TRUE;
|
||||
|
||||
final View row = convertView != null ? convertView : mInflater
|
||||
.inflate(R.layout.qs_zen_mode_detail_condition, parent, false);
|
||||
final RadioButton rb = (RadioButton) row.findViewById(android.R.id.checkbox);
|
||||
mRadioButtons.add(rb);
|
||||
rb.setEnabled(enabled);
|
||||
rb.setOnCheckedChangeListener(new OnCheckedChangeListener() {
|
||||
@Override
|
||||
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
|
||||
if (isChecked) {
|
||||
for (RadioButton otherButton : mRadioButtons) {
|
||||
if (otherButton == rb) continue;
|
||||
otherButton.setChecked(false);
|
||||
}
|
||||
select(condition);
|
||||
}
|
||||
}
|
||||
});
|
||||
final TextView title = (TextView) row.findViewById(android.R.id.title);
|
||||
title.setText(condition.summary);
|
||||
title.setEnabled(enabled);
|
||||
title.setAlpha(enabled ? 1 : .5f);
|
||||
final ImageView button1 = (ImageView) row.findViewById(android.R.id.button1);
|
||||
button1.setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
rb.setChecked(true);
|
||||
editTimeCondition(-1);
|
||||
}
|
||||
});
|
||||
|
||||
final ImageView button2 = (ImageView) row.findViewById(android.R.id.button2);
|
||||
button2.setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
rb.setChecked(true);
|
||||
editTimeCondition(1);
|
||||
}
|
||||
});
|
||||
title.setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
rb.setChecked(true);
|
||||
}
|
||||
});
|
||||
if (position != 0) {
|
||||
button1.setVisibility(View.GONE);
|
||||
button2.setVisibility(View.GONE);
|
||||
}
|
||||
if (position == 0 && mRadioButtons.size() == 1) {
|
||||
rb.setChecked(true);
|
||||
}
|
||||
return row;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,87 +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.Context;
|
||||
import android.util.Log;
|
||||
import android.view.ContextThemeWrapper;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import com.android.systemui.R;
|
||||
import com.android.systemui.qs.QSTile;
|
||||
import com.android.systemui.statusbar.policy.ZenModeController;
|
||||
|
||||
/** Quick settings tile: Zen mode **/
|
||||
public class ZenModeTile extends QSTile<QSTile.BooleanState> {
|
||||
private final ZenModeController mController;
|
||||
|
||||
public ZenModeTile(Host host) {
|
||||
super(host);
|
||||
mController = host.getZenModeController();
|
||||
}
|
||||
|
||||
@Override
|
||||
public View createDetailView(Context context, ViewGroup root) {
|
||||
final Context themedContext = new ContextThemeWrapper(mContext, R.style.QSAccentTheme);
|
||||
final ZenModeDetail v = (ZenModeDetail) LayoutInflater.from(themedContext)
|
||||
.inflate(R.layout.qs_zen_mode_detail, root, false);
|
||||
v.init(this);
|
||||
return v;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected BooleanState newTileState() {
|
||||
return new BooleanState();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setListening(boolean listening) {
|
||||
if (listening) {
|
||||
mController.addCallback(mCallback);
|
||||
} else {
|
||||
mController.removeCallback(mCallback);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void handleClick() {
|
||||
final boolean newZen = !mState.value;
|
||||
mController.setZen(newZen);
|
||||
if (newZen) {
|
||||
showDetail(true);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void handleUpdateState(BooleanState state, Object arg) {
|
||||
final boolean zen = arg instanceof Boolean ? (Boolean)arg : mController.isZen();
|
||||
state.value = zen;
|
||||
state.visible = true;
|
||||
state.iconId = zen ? R.drawable.ic_qs_zen_on : R.drawable.ic_qs_zen_off;
|
||||
state.label = mContext.getString(R.string.zen_mode_title);
|
||||
}
|
||||
|
||||
private final ZenModeController.Callback mCallback = new ZenModeController.Callback() {
|
||||
@Override
|
||||
public void onZenChanged(boolean zen) {
|
||||
if (DEBUG) Log.d(TAG, "onZenChanged " + zen);
|
||||
refreshState(zen);
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -72,8 +72,7 @@ public class BrightnessDialog extends Dialog implements
|
||||
window.setGravity(Gravity.TOP);
|
||||
WindowManager.LayoutParams lp = window.getAttributes();
|
||||
// Offset from the top
|
||||
lp.y = getContext().getResources().getDimensionPixelOffset(
|
||||
com.android.internal.R.dimen.volume_panel_top);
|
||||
lp.y = getContext().getResources().getDimensionPixelOffset(R.dimen.volume_panel_top);
|
||||
lp.type = WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY;
|
||||
lp.privateFlags |=
|
||||
WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
|
||||
|
||||
@@ -121,10 +121,12 @@ import com.android.systemui.statusbar.policy.UserInfoController;
|
||||
import com.android.systemui.statusbar.policy.LocationControllerImpl;
|
||||
import com.android.systemui.statusbar.policy.NetworkControllerImpl;
|
||||
import com.android.systemui.statusbar.policy.RotationLockControllerImpl;
|
||||
import com.android.systemui.statusbar.policy.ZenModeController;
|
||||
import com.android.systemui.statusbar.policy.ZenModeControllerImpl;
|
||||
import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
|
||||
import com.android.systemui.statusbar.stack.NotificationStackScrollLayout.OnChildLocationsChangedListener;
|
||||
import com.android.systemui.statusbar.stack.StackScrollState.ViewState;
|
||||
import com.android.systemui.volume.VolumeComponent;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.PrintWriter;
|
||||
@@ -196,8 +198,9 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
|
||||
NetworkControllerImpl mNetworkController;
|
||||
RotationLockControllerImpl mRotationLockController;
|
||||
UserInfoController mUserInfoController;
|
||||
ZenModeControllerImpl mZenModeController;
|
||||
ZenModeController mZenModeController;
|
||||
CastControllerImpl mCastController;
|
||||
VolumeComponent mVolumeComponent;
|
||||
|
||||
int mNaturalBarHeight = -1;
|
||||
int mIconSize = -1;
|
||||
@@ -684,7 +687,8 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
|
||||
mRotationLockController = new RotationLockControllerImpl(mContext);
|
||||
}
|
||||
mUserInfoController = new UserInfoController(mContext);
|
||||
mZenModeController = new ZenModeControllerImpl(mContext, mHandler);
|
||||
mVolumeComponent = getComponent(VolumeComponent.class);
|
||||
mZenModeController = mVolumeComponent.getZenController();
|
||||
mCastController = new CastControllerImpl(mContext);
|
||||
final SignalClusterView signalCluster =
|
||||
(SignalClusterView)mStatusBarView.findViewById(R.id.signal_cluster);
|
||||
@@ -747,7 +751,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
|
||||
final QSTileHost qsh = new QSTileHost(mContext, this,
|
||||
mBluetoothController, mLocationController, mRotationLockController,
|
||||
mNetworkController, mZenModeController, null /*tethering*/,
|
||||
mCastController);
|
||||
mCastController, mVolumeComponent);
|
||||
for (QSTile<?> tile : qsh.getTiles()) {
|
||||
mQSPanel.addTile(tile);
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ 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;
|
||||
@@ -29,11 +30,10 @@ 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.LocationTile;
|
||||
import com.android.systemui.qs.tiles.RingerModeTile;
|
||||
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.qs.tiles.ZenModeTile;
|
||||
import com.android.systemui.settings.CurrentUserTracker;
|
||||
import com.android.systemui.statusbar.policy.BluetoothController;
|
||||
import com.android.systemui.statusbar.policy.CastController;
|
||||
@@ -42,6 +42,7 @@ import com.android.systemui.statusbar.policy.NetworkController;
|
||||
import com.android.systemui.statusbar.policy.RotationLockController;
|
||||
import com.android.systemui.statusbar.policy.TetheringController;
|
||||
import com.android.systemui.statusbar.policy.ZenModeController;
|
||||
import com.android.systemui.volume.VolumeComponent;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@@ -60,13 +61,15 @@ public class QSTileHost implements QSTile.Host {
|
||||
private final CastController mCast;
|
||||
private final Looper mLooper;
|
||||
private final CurrentUserTracker mUserTracker;
|
||||
private final VolumeComponent mVolume;
|
||||
private final ArrayList<QSTile<?>> mTiles = new ArrayList<QSTile<?>>();
|
||||
private final int mFeedbackStartDelay;
|
||||
|
||||
public QSTileHost(Context context, PhoneStatusBar statusBar,
|
||||
BluetoothController bluetooth, LocationController location,
|
||||
RotationLockController rotation, NetworkController network,
|
||||
ZenModeController zen, TetheringController tethering,
|
||||
CastController cast) {
|
||||
CastController cast, VolumeComponent volume) {
|
||||
mContext = context;
|
||||
mStatusBar = statusBar;
|
||||
mBluetooth = bluetooth;
|
||||
@@ -76,6 +79,7 @@ public class QSTileHost implements QSTile.Host {
|
||||
mZen = zen;
|
||||
mTethering = tethering;
|
||||
mCast = cast;
|
||||
mVolume = volume;
|
||||
|
||||
final HandlerThread ht = new HandlerThread(QSTileHost.class.getSimpleName());
|
||||
ht.start();
|
||||
@@ -86,8 +90,7 @@ public class QSTileHost implements QSTile.Host {
|
||||
mTiles.add(new ColorInversionTile(this));
|
||||
mTiles.add(new CellularTile(this));
|
||||
mTiles.add(new AirplaneModeTile(this));
|
||||
mTiles.add(new ZenModeTile(this));
|
||||
mTiles.add(new RingerModeTile(this));
|
||||
mTiles.add(new NotificationsTile(this));
|
||||
mTiles.add(new RotationLockTile(this));
|
||||
mTiles.add(new LocationTile(this));
|
||||
mTiles.add(new CastTile(this));
|
||||
@@ -103,6 +106,7 @@ public class QSTileHost implements QSTile.Host {
|
||||
}
|
||||
};
|
||||
mUserTracker.startTracking();
|
||||
mFeedbackStartDelay = mContext.getResources().getInteger(R.integer.feedback_start_delay);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -112,7 +116,7 @@ public class QSTileHost implements QSTile.Host {
|
||||
|
||||
@Override
|
||||
public void startSettingsActivity(final Intent intent) {
|
||||
mStatusBar.postStartSettingsActivity(intent, QSTile.FEEDBACK_START_DELAY);
|
||||
mStatusBar.postStartSettingsActivity(intent, mFeedbackStartDelay);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -169,4 +173,9 @@ public class QSTileHost implements QSTile.Host {
|
||||
public CastController getCastController() {
|
||||
return mCast;
|
||||
}
|
||||
|
||||
@Override
|
||||
public VolumeComponent getVolumeComponent() {
|
||||
return mVolume;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* 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 com.android.systemui.statusbar.policy.ZenModeController;
|
||||
|
||||
public interface VolumeComponent {
|
||||
ZenModeController getZenController();
|
||||
void setVolumePanel(VolumePanel panel);
|
||||
}
|
||||
@@ -16,14 +16,12 @@
|
||||
|
||||
package com.android.systemui.volume;
|
||||
|
||||
import com.android.internal.R;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.app.Dialog;
|
||||
import android.content.DialogInterface.OnDismissListener;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.DialogInterface.OnDismissListener;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.res.Resources;
|
||||
@@ -42,6 +40,7 @@ import android.view.LayoutInflater;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.ViewStub;
|
||||
import android.view.Window;
|
||||
import android.view.WindowManager;
|
||||
import android.view.WindowManager.LayoutParams;
|
||||
@@ -49,6 +48,9 @@ import android.widget.ImageView;
|
||||
import android.widget.SeekBar;
|
||||
import android.widget.SeekBar.OnSeekBarChangeListener;
|
||||
|
||||
import com.android.internal.R;
|
||||
import com.android.systemui.statusbar.policy.ZenModeController;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
/**
|
||||
@@ -57,7 +59,6 @@ import java.util.HashMap;
|
||||
* @hide
|
||||
*/
|
||||
public class VolumePanel extends Handler {
|
||||
private static final String TAG = VolumePanel.class.getSimpleName();
|
||||
private static boolean LOGD = false;
|
||||
|
||||
private static final int PLAY_SOUND_DELAY = AudioService.PLAY_SOUND_DELAY;
|
||||
@@ -88,33 +89,48 @@ public class VolumePanel extends Handler {
|
||||
private static final int MSG_REMOTE_VOLUME_UPDATE_IF_SHOWN = 9;
|
||||
private static final int MSG_SLIDER_VISIBILITY_CHANGED = 10;
|
||||
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;
|
||||
|
||||
// Pseudo stream type for master volume
|
||||
private static final int STREAM_MASTER = -100;
|
||||
// Pseudo stream type for remote volume is defined in AudioService.STREAM_REMOTE_MUSIC
|
||||
|
||||
private final String mTag;
|
||||
protected final Context mContext;
|
||||
private final AudioManager mAudioManager;
|
||||
private final ZenModeController mZenController;
|
||||
private boolean mRingIsSilent;
|
||||
private boolean mShowCombinedVolumes;
|
||||
private boolean mVoiceCapable;
|
||||
private boolean mZenModeCapable;
|
||||
|
||||
// True if we want to play tones on the system stream when the master stream is specified.
|
||||
private final boolean mPlayMasterStreamTones;
|
||||
|
||||
/** Dialog containing all the sliders */
|
||||
private final Dialog mDialog;
|
||||
/** Dialog's content view */
|
||||
|
||||
/** Volume panel content view */
|
||||
private final View mView;
|
||||
/** Dialog hosting the panel, if not embedded */
|
||||
private final Dialog mDialog;
|
||||
/** Parent view hosting the panel, if embedded */
|
||||
private final ViewGroup mParent;
|
||||
|
||||
/** The visible portion of the volume overlay */
|
||||
private final ViewGroup mPanel;
|
||||
/** Contains the sliders and their touchable icons */
|
||||
private final ViewGroup mSliderGroup;
|
||||
/** The button that expands the dialog to show all sliders */
|
||||
private final View mMoreButton;
|
||||
/** Dummy divider icon that needs to vanish with the more button */
|
||||
private final View mDivider;
|
||||
/** 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;
|
||||
|
||||
/** Currently active stream that shows up at the top of the list of sliders */
|
||||
private int mActiveStreamType = -1;
|
||||
@@ -129,8 +145,8 @@ public class VolumePanel extends Handler {
|
||||
false),
|
||||
RingerStream(AudioManager.STREAM_RING,
|
||||
R.string.volume_icon_description_ringer,
|
||||
R.drawable.ic_audio_ring_notif,
|
||||
R.drawable.ic_audio_ring_notif_mute,
|
||||
com.android.systemui.R.drawable.ic_ringer_audible,
|
||||
com.android.systemui.R.drawable.ic_ringer_silent,
|
||||
false),
|
||||
VoiceStream(AudioManager.STREAM_VOICE_CALL,
|
||||
R.string.volume_icon_description_incall,
|
||||
@@ -149,8 +165,8 @@ public class VolumePanel extends Handler {
|
||||
true),
|
||||
NotificationStream(AudioManager.STREAM_NOTIFICATION,
|
||||
R.string.volume_icon_description_notification,
|
||||
R.drawable.ic_audio_notification,
|
||||
R.drawable.ic_audio_notification_mute,
|
||||
com.android.systemui.R.drawable.ic_ringer_audible,
|
||||
com.android.systemui.R.drawable.ic_ringer_silent,
|
||||
true),
|
||||
// for now, use media resources for master volume
|
||||
MasterStream(STREAM_MASTER,
|
||||
@@ -245,8 +261,11 @@ public class VolumePanel extends Handler {
|
||||
}
|
||||
|
||||
|
||||
public VolumePanel(Context context) {
|
||||
public VolumePanel(Context context, ViewGroup parent, ZenModeController zenController) {
|
||||
mTag = String.format("VolumePanel%s.%08x", parent == null ? "Dialog" : "", hashCode());
|
||||
mContext = context;
|
||||
mParent = parent;
|
||||
mZenController = zenController;
|
||||
mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
|
||||
|
||||
// For now, only show master volume if master volume is supported
|
||||
@@ -258,74 +277,81 @@ public class VolumePanel extends Handler {
|
||||
streamRes.show = (streamRes.streamType == STREAM_MASTER);
|
||||
}
|
||||
}
|
||||
|
||||
mDialog = new Dialog(context) {
|
||||
@Override
|
||||
public boolean onTouchEvent(MotionEvent event) {
|
||||
if (isShowing() && event.getAction() == MotionEvent.ACTION_OUTSIDE &&
|
||||
sConfirmSafeVolumeDialog == null) {
|
||||
forceTimeout();
|
||||
return true;
|
||||
if (LOGD) Log.d(mTag, String.format("new VolumePanel hasParent=%s", parent != null));
|
||||
final int layoutId = com.android.systemui.R.layout.volume_panel;
|
||||
if (parent == null) {
|
||||
// dialog mode
|
||||
mDialog = new Dialog(context) {
|
||||
@Override
|
||||
public boolean onTouchEvent(MotionEvent event) {
|
||||
if (isShowing() && event.getAction() == MotionEvent.ACTION_OUTSIDE &&
|
||||
sConfirmSafeVolumeDialog == null) {
|
||||
forceTimeout();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
// Change some window properties
|
||||
final Window window = mDialog.getWindow();
|
||||
final LayoutParams lp = window.getAttributes();
|
||||
lp.token = null;
|
||||
// Offset from the top
|
||||
lp.y = res.getDimensionPixelOffset(R.dimen.volume_panel_top);
|
||||
lp.type = LayoutParams.TYPE_VOLUME_OVERLAY;
|
||||
lp.windowAnimations = R.style.Animation_VolumePanel;
|
||||
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
|
||||
| LayoutParams.FLAG_NOT_TOUCH_MODAL
|
||||
| LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH);
|
||||
// Change some window properties
|
||||
final Window window = mDialog.getWindow();
|
||||
final LayoutParams lp = window.getAttributes();
|
||||
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.windowAnimations = R.style.Animation_VolumePanel;
|
||||
window.setBackgroundDrawableResource(com.android.systemui.R.drawable.qs_panel_background);
|
||||
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
|
||||
| LayoutParams.FLAG_NOT_TOUCH_MODAL
|
||||
| LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH);
|
||||
mDialog.setCanceledOnTouchOutside(true);
|
||||
mDialog.setContentView(layoutId);
|
||||
mDialog.setOnDismissListener(new OnDismissListener() {
|
||||
@Override
|
||||
public void onDismiss(DialogInterface dialog) {
|
||||
mActiveStreamType = -1;
|
||||
mAudioManager.forceVolumeControlStream(mActiveStreamType);
|
||||
}
|
||||
});
|
||||
|
||||
mDialog.setCanceledOnTouchOutside(true);
|
||||
mDialog.setContentView(R.layout.volume_adjust);
|
||||
mDialog.setOnDismissListener(new OnDismissListener() {
|
||||
@Override
|
||||
public void onDismiss(DialogInterface dialog) {
|
||||
mActiveStreamType = -1;
|
||||
mAudioManager.forceVolumeControlStream(mActiveStreamType);
|
||||
}
|
||||
});
|
||||
mDialog.create();
|
||||
|
||||
mDialog.create();
|
||||
mView = window.findViewById(R.id.content);
|
||||
mView.setOnTouchListener(new View.OnTouchListener() {
|
||||
@Override
|
||||
public boolean onTouch(View v, MotionEvent event) {
|
||||
resetTimeout();
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
mView = window.findViewById(R.id.content);
|
||||
mView.setOnTouchListener(new View.OnTouchListener() {
|
||||
@Override
|
||||
public boolean onTouch(View v, MotionEvent event) {
|
||||
resetTimeout();
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
mPanel = (ViewGroup) mView.findViewById(R.id.visible_panel);
|
||||
mSliderGroup = (ViewGroup) mView.findViewById(R.id.slider_group);
|
||||
mMoreButton = mView.findViewById(R.id.expand_button);
|
||||
mDivider = mView.findViewById(R.id.expand_button_divider);
|
||||
} else {
|
||||
// embedded mode
|
||||
mDialog = null;
|
||||
mView = LayoutInflater.from(mContext).inflate(layoutId, parent, true);
|
||||
}
|
||||
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);
|
||||
|
||||
// If we don't want to show multiple volumes, hide the settings button
|
||||
// and divider.
|
||||
mShowCombinedVolumes = !mVoiceCapable && !useMasterVolume;
|
||||
if (!mShowCombinedVolumes) {
|
||||
mMoreButton.setVisibility(View.GONE);
|
||||
mDivider.setVisibility(View.GONE);
|
||||
} else {
|
||||
mMoreButton.setOnClickListener(mClickListener);
|
||||
}
|
||||
mZenModeCapable = !useMasterVolume && mZenController != null;
|
||||
mZenPanelDivider.setVisibility(View.GONE);
|
||||
mExpandButton.setOnClickListener(mClickListener);
|
||||
updateZenMode(mZenController == null ? false : mZenController.isZen());
|
||||
mZenController.addCallback(mZenCallback);
|
||||
|
||||
final boolean masterVolumeOnly = res.getBoolean(R.bool.config_useMasterVolume);
|
||||
final boolean masterVolumeKeySounds = res.getBoolean(R.bool.config_useVolumeKeySounds);
|
||||
@@ -334,7 +360,7 @@ public class VolumePanel extends Handler {
|
||||
listenToRingerMode();
|
||||
}
|
||||
|
||||
public void setLayoutDirection(int layoutDirection) {
|
||||
private void setLayoutDirection(int layoutDirection) {
|
||||
mPanel.setLayoutDirection(layoutDirection);
|
||||
updateStates();
|
||||
}
|
||||
@@ -406,21 +432,19 @@ public class VolumePanel extends Handler {
|
||||
StreamResources streamRes = STREAMS[i];
|
||||
|
||||
final int streamType = streamRes.streamType;
|
||||
if (mVoiceCapable && streamRes == StreamResources.NotificationStream) {
|
||||
streamRes = StreamResources.RingerStream;
|
||||
}
|
||||
|
||||
final StreamControl sc = new StreamControl();
|
||||
sc.streamType = streamType;
|
||||
sc.group = (ViewGroup) inflater.inflate(R.layout.volume_adjust_item, null);
|
||||
sc.group = (ViewGroup) inflater.inflate(
|
||||
com.android.systemui.R.layout.volume_panel_item, null);
|
||||
sc.group.setTag(sc);
|
||||
sc.icon = (ImageView) sc.group.findViewById(R.id.stream_icon);
|
||||
sc.icon = (ImageView) sc.group.findViewById(com.android.systemui.R.id.stream_icon);
|
||||
sc.icon.setTag(sc);
|
||||
sc.icon.setContentDescription(res.getString(streamRes.descRes));
|
||||
sc.iconRes = streamRes.iconRes;
|
||||
sc.iconMuteRes = streamRes.iconMuteRes;
|
||||
sc.icon.setImageResource(sc.iconRes);
|
||||
sc.seekbarView = (SeekBar) sc.group.findViewById(R.id.seekbar);
|
||||
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;
|
||||
sc.seekbarView.setMax(getStreamMaxVolume(streamType) + plusOne);
|
||||
@@ -431,34 +455,18 @@ public class VolumePanel extends Handler {
|
||||
}
|
||||
|
||||
private void reorderSliders(int activeStreamType) {
|
||||
mSliderGroup.removeAllViews();
|
||||
mSliderPanel.removeAllViews();
|
||||
|
||||
final StreamControl active = mStreamControls.get(activeStreamType);
|
||||
if (active == null) {
|
||||
Log.e("VolumePanel", "Missing stream type! - " + activeStreamType);
|
||||
mActiveStreamType = -1;
|
||||
} else {
|
||||
mSliderGroup.addView(active.group);
|
||||
mSliderPanel.addView(active.group);
|
||||
mActiveStreamType = activeStreamType;
|
||||
active.group.setVisibility(View.VISIBLE);
|
||||
updateSlider(active);
|
||||
}
|
||||
|
||||
addOtherVolumes();
|
||||
}
|
||||
|
||||
private void addOtherVolumes() {
|
||||
if (!mShowCombinedVolumes) return;
|
||||
|
||||
for (int i = 0; i < STREAMS.length; i++) {
|
||||
// Skip the phone specific ones and the active one
|
||||
final int streamType = STREAMS[i].streamType;
|
||||
if (!STREAMS[i].show || streamType == mActiveStreamType) {
|
||||
continue;
|
||||
}
|
||||
StreamControl sc = mStreamControls.get(streamType);
|
||||
mSliderGroup.addView(sc.group);
|
||||
updateSlider(sc);
|
||||
updateZenMode(mZenController == null ? false : mZenController.isZen());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -472,7 +480,7 @@ public class VolumePanel extends Handler {
|
||||
if (((sc.streamType == AudioManager.STREAM_RING) ||
|
||||
(sc.streamType == AudioManager.STREAM_NOTIFICATION)) &&
|
||||
mAudioManager.getRingerMode() == AudioManager.RINGER_MODE_VIBRATE) {
|
||||
sc.icon.setImageResource(R.drawable.ic_audio_ring_notif_vibrate);
|
||||
sc.icon.setImageResource(com.android.systemui.R.drawable.ic_ringer_vibrate);
|
||||
}
|
||||
if (sc.streamType == AudioService.STREAM_REMOTE_MUSIC) {
|
||||
// never disable touch interactions for remote playback, the muting is not tied to
|
||||
@@ -486,32 +494,70 @@ public class VolumePanel extends Handler {
|
||||
}
|
||||
}
|
||||
|
||||
public void setZenModePanelCallback(ZenModePanel.Callback callback) {
|
||||
mZenPanelCallback = callback;
|
||||
}
|
||||
|
||||
private void expand() {
|
||||
final int count = mSliderGroup.getChildCount();
|
||||
for (int i = 0; i < count; i++) {
|
||||
mSliderGroup.getChildAt(i).setVisibility(View.VISIBLE);
|
||||
if (LOGD) Log.d(mTag, "expand mZenPanel=" + mZenPanel);
|
||||
if (mZenPanel == null) {
|
||||
mZenPanel = (ZenModePanel) mZenPanelStub.inflate();
|
||||
mZenPanel.init(mZenController);
|
||||
mZenPanel.setCallback(new ZenModePanel.Callback() {
|
||||
@Override
|
||||
public void onMoreSettings() {
|
||||
if (mZenPanelCallback != null) {
|
||||
mZenPanelCallback.onMoreSettings();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onInteraction() {
|
||||
if (mZenPanelCallback != null) {
|
||||
mZenPanelCallback.onInteraction();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
mMoreButton.setVisibility(View.INVISIBLE);
|
||||
mDivider.setVisibility(View.INVISIBLE);
|
||||
mZenPanel.setVisibility(View.VISIBLE);
|
||||
mZenPanelDivider.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
private void collapse() {
|
||||
mMoreButton.setVisibility(View.VISIBLE);
|
||||
mDivider.setVisibility(View.VISIBLE);
|
||||
final int count = mSliderGroup.getChildCount();
|
||||
for (int i = 1; i < count; i++) {
|
||||
mSliderGroup.getChildAt(i).setVisibility(View.GONE);
|
||||
if (LOGD) Log.d(mTag, "collapse mZenPanel=" + mZenPanel);
|
||||
if (mZenPanel != null) {
|
||||
mZenPanel.setVisibility(View.GONE);
|
||||
}
|
||||
mZenPanelDivider.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
public void updateStates() {
|
||||
final int count = mSliderGroup.getChildCount();
|
||||
final int count = mSliderPanel.getChildCount();
|
||||
for (int i = 0; i < count; i++) {
|
||||
StreamControl sc = (StreamControl) mSliderGroup.getChildAt(i).getTag();
|
||||
StreamControl sc = (StreamControl) mSliderPanel.getChildAt(i).getTag();
|
||||
updateSlider(sc);
|
||||
}
|
||||
}
|
||||
|
||||
private void updateZenMode(boolean zen) {
|
||||
if (mZenModeCapable) {
|
||||
final boolean show = mActiveStreamType == AudioManager.STREAM_NOTIFICATION
|
||||
|| mActiveStreamType == AudioManager.STREAM_RING;
|
||||
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);
|
||||
} else {
|
||||
mExpandButton.setVisibility(View.GONE);
|
||||
mExpandDivider.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
|
||||
public void postZenModeChanged(boolean zen) {
|
||||
removeMessages(MSG_ZEN_MODE_CHANGED);
|
||||
obtainMessage(MSG_ZEN_MODE_CHANGED, zen ? 1 : 0).sendToTarget();
|
||||
}
|
||||
|
||||
public void postVolumeChanged(int streamType, int flags) {
|
||||
if (hasMessages(MSG_VOLUME_CHANGED)) return;
|
||||
synchronized (this) {
|
||||
@@ -582,8 +628,12 @@ public class VolumePanel extends Handler {
|
||||
}
|
||||
|
||||
public void postDismiss() {
|
||||
removeMessages(MSG_TIMEOUT);
|
||||
sendEmptyMessage(MSG_TIMEOUT);
|
||||
forceTimeout();
|
||||
}
|
||||
|
||||
public void postLayoutDirection(int layoutDirection) {
|
||||
removeMessages(MSG_LAYOUT_DIRECTION);
|
||||
obtainMessage(MSG_LAYOUT_DIRECTION, layoutDirection).sendToTarget();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -593,7 +643,7 @@ public class VolumePanel extends Handler {
|
||||
*/
|
||||
protected void onVolumeChanged(int streamType, int flags) {
|
||||
|
||||
if (LOGD) Log.d(TAG, "onVolumeChanged(streamType: " + streamType + ", flags: " + flags + ")");
|
||||
if (LOGD) Log.d(mTag, "onVolumeChanged(streamType: " + streamType + ", flags: " + flags + ")");
|
||||
|
||||
if ((flags & AudioManager.FLAG_SHOW_UI) != 0) {
|
||||
synchronized (this) {
|
||||
@@ -622,7 +672,7 @@ public class VolumePanel extends Handler {
|
||||
|
||||
protected void onMuteChanged(int streamType, int flags) {
|
||||
|
||||
if (LOGD) Log.d(TAG, "onMuteChanged(streamType: " + streamType + ", flags: " + flags + ")");
|
||||
if (LOGD) Log.d(mTag, "onMuteChanged(streamType: " + streamType + ", flags: " + flags + ")");
|
||||
|
||||
StreamControl sc = mStreamControls.get(streamType);
|
||||
if (sc != null) {
|
||||
@@ -638,7 +688,7 @@ public class VolumePanel extends Handler {
|
||||
mRingIsSilent = false;
|
||||
|
||||
if (LOGD) {
|
||||
Log.d(TAG, "onShowVolumeChanged(streamType: " + streamType
|
||||
Log.d(mTag, "onShowVolumeChanged(streamType: " + streamType
|
||||
+ ", flags: " + flags + "), index: " + index);
|
||||
}
|
||||
|
||||
@@ -707,7 +757,7 @@ public class VolumePanel extends Handler {
|
||||
}
|
||||
|
||||
case AudioService.STREAM_REMOTE_MUSIC: {
|
||||
if (LOGD) { Log.d(TAG, "showing remote volume "+index+" over "+ max); }
|
||||
if (LOGD) { Log.d(mTag, "showing remote volume "+index+" over "+ max); }
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -730,16 +780,18 @@ public class VolumePanel extends Handler {
|
||||
}
|
||||
}
|
||||
|
||||
if (!mDialog.isShowing()) {
|
||||
if (!isShowing()) {
|
||||
int stream = (streamType == AudioService.STREAM_REMOTE_MUSIC) ? -1 : streamType;
|
||||
// when the stream is for remote playback, use -1 to reset the stream type evaluation
|
||||
mAudioManager.forceVolumeControlStream(stream);
|
||||
|
||||
// Showing dialog - use collapsed state
|
||||
if (mShowCombinedVolumes) {
|
||||
if (mZenModeCapable) {
|
||||
collapse();
|
||||
}
|
||||
mDialog.show();
|
||||
if (mDialog != null) {
|
||||
mDialog.show();
|
||||
}
|
||||
}
|
||||
|
||||
// Do a little vibrate if applicable (only when going into vibrate mode)
|
||||
@@ -751,6 +803,10 @@ public class VolumePanel extends Handler {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isShowing() {
|
||||
return mDialog != null ? mDialog.isShowing() : mParent.isAttachedToWindow();
|
||||
}
|
||||
|
||||
protected void onPlaySound(int streamType, int flags) {
|
||||
|
||||
if (hasMessages(MSG_STOP_SOUNDS)) {
|
||||
@@ -795,9 +851,9 @@ public class VolumePanel extends Handler {
|
||||
// streamType is the real stream type being affected, but for the UI sliders, we
|
||||
// refer to AudioService.STREAM_REMOTE_MUSIC. We still play the beeps on the real
|
||||
// stream type.
|
||||
if (LOGD) Log.d(TAG, "onRemoteVolumeChanged(stream:"+streamType+", flags: " + flags + ")");
|
||||
if (LOGD) Log.d(mTag, "onRemoteVolumeChanged(stream:"+streamType+", flags: " + flags + ")");
|
||||
|
||||
if (((flags & AudioManager.FLAG_SHOW_UI) != 0) || mDialog.isShowing()) {
|
||||
if (((flags & AudioManager.FLAG_SHOW_UI) != 0) || isShowing()) {
|
||||
synchronized (this) {
|
||||
if (mActiveStreamType != AudioService.STREAM_REMOTE_MUSIC) {
|
||||
reorderSliders(AudioService.STREAM_REMOTE_MUSIC);
|
||||
@@ -805,7 +861,7 @@ public class VolumePanel extends Handler {
|
||||
onShowVolumeChanged(AudioService.STREAM_REMOTE_MUSIC, flags);
|
||||
}
|
||||
} else {
|
||||
if (LOGD) Log.d(TAG, "not calling onShowVolumeChanged(), no FLAG_SHOW_UI or no UI");
|
||||
if (LOGD) Log.d(mTag, "not calling onShowVolumeChanged(), no FLAG_SHOW_UI or no UI");
|
||||
}
|
||||
|
||||
if ((flags & AudioManager.FLAG_PLAY_SOUND) != 0 && ! mRingIsSilent) {
|
||||
@@ -825,8 +881,8 @@ public class VolumePanel extends Handler {
|
||||
}
|
||||
|
||||
protected void onRemoteVolumeUpdateIfShown() {
|
||||
if (LOGD) Log.d(TAG, "onRemoteVolumeUpdateIfShown()");
|
||||
if (mDialog.isShowing()
|
||||
if (LOGD) Log.d(mTag, "onRemoteVolumeUpdateIfShown()");
|
||||
if (isShowing()
|
||||
&& (mActiveStreamType == AudioService.STREAM_REMOTE_MUSIC)
|
||||
&& (mStreamControls != null)) {
|
||||
onShowVolumeChanged(AudioService.STREAM_REMOTE_MUSIC, 0);
|
||||
@@ -842,7 +898,7 @@ public class VolumePanel extends Handler {
|
||||
* @param visible
|
||||
*/
|
||||
synchronized protected void onSliderVisibilityChanged(int streamType, int visible) {
|
||||
if (LOGD) Log.d(TAG, "onSliderVisibilityChanged(stream="+streamType+", visi="+visible+")");
|
||||
if (LOGD) Log.d(mTag, "onSliderVisibilityChanged(stream="+streamType+", visi="+visible+")");
|
||||
boolean isVisible = (visible == 1);
|
||||
for (int i = STREAMS.length - 1 ; i >= 0 ; i--) {
|
||||
StreamResources streamRes = STREAMS[i];
|
||||
@@ -857,7 +913,7 @@ public class VolumePanel extends Handler {
|
||||
}
|
||||
|
||||
protected void onDisplaySafeVolumeWarning(int flags) {
|
||||
if ((flags & AudioManager.FLAG_SHOW_UI) != 0 || mDialog.isShowing()) {
|
||||
if ((flags & AudioManager.FLAG_SHOW_UI) != 0 || isShowing()) {
|
||||
synchronized (sConfirmSafeVolumeLock) {
|
||||
if (sConfirmSafeVolumeDialog != null) {
|
||||
return;
|
||||
@@ -907,7 +963,7 @@ public class VolumePanel extends Handler {
|
||||
mToneGenerators[streamType] = new ToneGenerator(streamType, MAX_VOLUME);
|
||||
} catch (RuntimeException e) {
|
||||
if (LOGD) {
|
||||
Log.d(TAG, "ToneGenerator constructor failed with "
|
||||
Log.d(mTag, "ToneGenerator constructor failed with "
|
||||
+ "RuntimeException: " + e);
|
||||
}
|
||||
}
|
||||
@@ -976,8 +1032,10 @@ public class VolumePanel extends Handler {
|
||||
}
|
||||
|
||||
case MSG_TIMEOUT: {
|
||||
if (mDialog.isShowing()) {
|
||||
mDialog.dismiss();
|
||||
if (isShowing()) {
|
||||
if (mDialog != null) {
|
||||
mDialog.dismiss();
|
||||
}
|
||||
mActiveStreamType = -1;
|
||||
}
|
||||
synchronized (sConfirmSafeVolumeLock) {
|
||||
@@ -988,7 +1046,7 @@ public class VolumePanel extends Handler {
|
||||
break;
|
||||
}
|
||||
case MSG_RINGER_MODE_CHANGED: {
|
||||
if (mDialog.isShowing()) {
|
||||
if (isShowing()) {
|
||||
updateStates();
|
||||
}
|
||||
break;
|
||||
@@ -1010,17 +1068,30 @@ public class VolumePanel extends Handler {
|
||||
case MSG_DISPLAY_SAFE_VOLUME_WARNING:
|
||||
onDisplaySafeVolumeWarning(msg.arg1);
|
||||
break;
|
||||
|
||||
case MSG_LAYOUT_DIRECTION:
|
||||
setLayoutDirection(msg.arg1);
|
||||
break;
|
||||
|
||||
case MSG_ZEN_MODE_CHANGED:
|
||||
updateZenMode(msg.arg1 != 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void resetTimeout() {
|
||||
public void resetTimeout() {
|
||||
if (LOGD) Log.d(mTag, "resetTimeout at " + System.currentTimeMillis());
|
||||
removeMessages(MSG_TIMEOUT);
|
||||
sendMessageDelayed(obtainMessage(MSG_TIMEOUT), TIMEOUT_DELAY);
|
||||
sendEmptyMessageDelayed(MSG_TIMEOUT, TIMEOUT_DELAY);
|
||||
}
|
||||
|
||||
private void forceTimeout() {
|
||||
removeMessages(MSG_TIMEOUT);
|
||||
sendMessage(obtainMessage(MSG_TIMEOUT));
|
||||
sendEmptyMessage(MSG_TIMEOUT);
|
||||
}
|
||||
|
||||
public ZenModeController getZenController() {
|
||||
return mZenController;
|
||||
}
|
||||
|
||||
private final OnSeekBarChangeListener mSeekListener = new OnSeekBarChangeListener() {
|
||||
@@ -1061,10 +1132,22 @@ public class VolumePanel extends Handler {
|
||||
private final View.OnClickListener mClickListener = new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
if (v == mMoreButton) {
|
||||
expand();
|
||||
if (v == mExpandButton && mZenController != null) {
|
||||
final boolean newZen = !mZenController.isZen();
|
||||
mZenController.setZen(newZen);
|
||||
if (newZen) {
|
||||
expand();
|
||||
} else {
|
||||
collapse();
|
||||
}
|
||||
}
|
||||
resetTimeout();
|
||||
}
|
||||
};
|
||||
|
||||
private final ZenModeController.Callback mZenCallback = new ZenModeController.Callback() {
|
||||
public void onZenChanged(boolean zen) {
|
||||
updateZenMode(zen);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,16 +1,22 @@
|
||||
package com.android.systemui.volume;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.res.Resources;
|
||||
import android.database.ContentObserver;
|
||||
import android.media.AudioManager;
|
||||
import android.media.IVolumeController;
|
||||
import android.net.Uri;
|
||||
import android.os.Handler;
|
||||
import android.os.RemoteException;
|
||||
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.statusbar.policy.ZenModeController;
|
||||
import com.android.systemui.statusbar.policy.ZenModeControllerImpl;
|
||||
|
||||
/*
|
||||
* Copyright (C) 2014 The Android Open Source Project
|
||||
@@ -34,21 +40,21 @@ public class VolumeUI extends SystemUI {
|
||||
private static final Uri SETTING_URI = Settings.Global.getUriFor(SETTING);
|
||||
private static final int DEFAULT = 1; // enabled by default
|
||||
|
||||
private final Handler mHandler = new Handler();
|
||||
private AudioManager mAudioManager;
|
||||
private VolumeController mVolumeController;
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
|
||||
mVolumeController = new VolumeController(mContext);
|
||||
putComponent(VolumeComponent.class, mVolumeController);
|
||||
updateController();
|
||||
mContext.getContentResolver().registerContentObserver(SETTING_URI, false, mObserver);
|
||||
}
|
||||
|
||||
private void updateController() {
|
||||
if (Settings.Global.getInt(mContext.getContentResolver(), SETTING, DEFAULT) != 0) {
|
||||
if (mVolumeController == null) {
|
||||
mVolumeController = new VolumeController(mContext);
|
||||
}
|
||||
Log.d(TAG, "Registering volume controller");
|
||||
mAudioManager.setVolumeController(mVolumeController);
|
||||
} else {
|
||||
@@ -57,7 +63,7 @@ public class VolumeUI extends SystemUI {
|
||||
}
|
||||
}
|
||||
|
||||
private final ContentObserver mObserver = new ContentObserver(new Handler()) {
|
||||
private final ContentObserver mObserver = new ContentObserver(mHandler) {
|
||||
public void onChange(boolean selfChange, Uri uri) {
|
||||
if (SETTING_URI.equals(uri)) {
|
||||
updateController();
|
||||
@@ -66,13 +72,38 @@ public class VolumeUI extends SystemUI {
|
||||
};
|
||||
|
||||
/** For now, simply host an unmodified base volume panel in this process. */
|
||||
private final class VolumeController extends IVolumeController.Stub {
|
||||
private final VolumePanel mPanel;
|
||||
private final class VolumeController extends IVolumeController.Stub implements VolumeComponent {
|
||||
private final VolumePanel mDialogPanel;
|
||||
private VolumePanel mPanel;
|
||||
|
||||
public VolumeController(Context context) {
|
||||
mPanel = new VolumePanel(context);
|
||||
mPanel = new VolumePanel(context, null, new ZenModeControllerImpl(mContext, mHandler));
|
||||
final int delay = context.getResources().getInteger(R.integer.feedback_start_delay);
|
||||
mPanel.setZenModePanelCallback(new ZenModePanel.Callback() {
|
||||
@Override
|
||||
public void onMoreSettings() {
|
||||
mHandler.removeCallbacks(mStartZenSettings);
|
||||
mHandler.postDelayed(mStartZenSettings, delay);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onInteraction() {
|
||||
mDialogPanel.resetTimeout();
|
||||
}
|
||||
});
|
||||
mDialogPanel = mPanel;
|
||||
}
|
||||
|
||||
private final Runnable mStartZenSettings = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
mDialogPanel.postDismiss();
|
||||
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));
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public void hasNewRemotePlaybackInfo() throws RemoteException {
|
||||
mPanel.postHasNewRemotePlaybackInfo();
|
||||
@@ -114,12 +145,22 @@ public class VolumeUI extends SystemUI {
|
||||
@Override
|
||||
public void setLayoutDirection(int layoutDirection)
|
||||
throws RemoteException {
|
||||
mPanel.setLayoutDirection(layoutDirection);
|
||||
mPanel.postLayoutDirection(layoutDirection);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dismiss() throws RemoteException {
|
||||
mPanel.postDismiss();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ZenModeController getZenController() {
|
||||
return mDialogPanel.getZenController();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setVolumePanel(VolumePanel panel) {
|
||||
mPanel = panel == null ? mDialogPanel : panel;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,248 @@
|
||||
/*
|
||||
* 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.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.os.Message;
|
||||
import android.provider.Settings;
|
||||
import android.service.notification.Condition;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.ContextThemeWrapper;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.CompoundButton;
|
||||
import android.widget.CompoundButton.OnCheckedChangeListener;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.RadioButton;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.android.systemui.R;
|
||||
import com.android.systemui.statusbar.policy.ZenModeController;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
|
||||
public class ZenModePanel extends LinearLayout {
|
||||
private static final int[] MINUTES = new int[] { 15, 30, 45, 60, 120, 180, 240, 480 };
|
||||
public static final Intent ZEN_SETTINGS = new Intent(Settings.ACTION_ZEN_MODE_SETTINGS);
|
||||
|
||||
private final LayoutInflater mInflater;
|
||||
private final HashSet<RadioButton> mRadioButtons = new HashSet<RadioButton>();
|
||||
private final H mHandler = new H();
|
||||
private LinearLayout mConditions;
|
||||
private int mMinutesIndex = Arrays.binarySearch(MINUTES, 60); // default to one hour
|
||||
private Callback mCallback;
|
||||
private ZenModeController mController;
|
||||
private boolean mRequestingConditions;
|
||||
|
||||
public ZenModePanel(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
mInflater = LayoutInflater.from(new ContextThemeWrapper(context, R.style.QSWhiteTheme));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onFinishInflate() {
|
||||
super.onFinishInflate();
|
||||
mConditions = (LinearLayout) findViewById(android.R.id.content);
|
||||
findViewById(android.R.id.button2).setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
fireMoreSettings();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setVisibility(int visibility) {
|
||||
super.setVisibility(visibility);
|
||||
setRequestingConditions(visibility == VISIBLE);
|
||||
}
|
||||
|
||||
/** Start or stop requesting relevant zen mode exit conditions */
|
||||
private void setRequestingConditions(boolean requesting) {
|
||||
if (mRequestingConditions == requesting) return;
|
||||
mRequestingConditions = requesting;
|
||||
if (mRequestingConditions) {
|
||||
mController.addCallback(mZenCallback);
|
||||
} else {
|
||||
mController.removeCallback(mZenCallback);
|
||||
}
|
||||
mController.requestConditions(mRequestingConditions);
|
||||
}
|
||||
|
||||
public void init(ZenModeController controller) {
|
||||
mController = controller;
|
||||
mConditions.removeAllViews();
|
||||
bind(updateTimeCondition(), mConditions.getChildAt(0));
|
||||
handleUpdateConditions(new Condition[0]);
|
||||
}
|
||||
|
||||
public void setCallback(Callback callback) {
|
||||
mCallback = callback;
|
||||
}
|
||||
|
||||
private Condition updateTimeCondition() {
|
||||
final int minutes = MINUTES[mMinutesIndex];
|
||||
final long millis = System.currentTimeMillis() + minutes * 60 * 1000;
|
||||
final Uri id = new Uri.Builder().scheme(Condition.SCHEME).authority("android")
|
||||
.appendPath("countdown").appendPath(Long.toString(millis)).build();
|
||||
final int num = minutes < 60 ? minutes : minutes / 60;
|
||||
final int resId = minutes < 60
|
||||
? R.plurals.zen_mode_duration_minutes
|
||||
: R.plurals.zen_mode_duration_hours;
|
||||
final String caption = mContext.getResources().getQuantityString(resId, num, num);
|
||||
return new Condition(id, caption, "", "", 0, Condition.STATE_TRUE,
|
||||
Condition.FLAG_RELEVANT_NOW);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
for (int i = 0; i < newCount; i++) {
|
||||
bind(conditions[i], mConditions.getChildAt(i + 1));
|
||||
}
|
||||
bind(null, mConditions.getChildAt(newCount + 1));
|
||||
}
|
||||
|
||||
private void editTimeCondition(int delta) {
|
||||
final int i = mMinutesIndex + delta;
|
||||
if (i < 0 || i >= MINUTES.length) return;
|
||||
mMinutesIndex = i;
|
||||
final Condition c = updateTimeCondition();
|
||||
bind(c, mConditions.getChildAt(0));
|
||||
}
|
||||
|
||||
private void bind(final Condition condition, View convertView) {
|
||||
final boolean enabled = condition == null || condition.state == Condition.STATE_TRUE;
|
||||
final View row;
|
||||
if (convertView == null) {
|
||||
row = mInflater.inflate(R.layout.zen_mode_condition, this, false);
|
||||
mConditions.addView(row);
|
||||
} else {
|
||||
row = convertView;
|
||||
}
|
||||
final int position = mConditions.indexOfChild(row);
|
||||
final RadioButton rb = (RadioButton) row.findViewById(android.R.id.checkbox);
|
||||
mRadioButtons.add(rb);
|
||||
rb.setEnabled(enabled);
|
||||
rb.setOnCheckedChangeListener(new OnCheckedChangeListener() {
|
||||
@Override
|
||||
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
|
||||
if (isChecked) {
|
||||
for (RadioButton otherButton : mRadioButtons) {
|
||||
if (otherButton == rb) continue;
|
||||
otherButton.setChecked(false);
|
||||
}
|
||||
mController.select(condition);
|
||||
fireInteraction();
|
||||
}
|
||||
}
|
||||
});
|
||||
final TextView title = (TextView) row.findViewById(android.R.id.title);
|
||||
if (condition == null) {
|
||||
title.setText(R.string.zen_mode_forever);
|
||||
} else {
|
||||
title.setText(condition.summary);
|
||||
}
|
||||
title.setEnabled(enabled);
|
||||
title.setAlpha(enabled ? 1 : .5f);
|
||||
final ImageView button1 = (ImageView) row.findViewById(android.R.id.button1);
|
||||
button1.setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
rb.setChecked(true);
|
||||
editTimeCondition(-1);
|
||||
fireInteraction();
|
||||
}
|
||||
});
|
||||
|
||||
final ImageView button2 = (ImageView) row.findViewById(android.R.id.button2);
|
||||
button2.setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
rb.setChecked(true);
|
||||
editTimeCondition(1);
|
||||
fireInteraction();
|
||||
}
|
||||
});
|
||||
title.setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
rb.setChecked(true);
|
||||
fireInteraction();
|
||||
}
|
||||
});
|
||||
if (position == 0) {
|
||||
button1.setEnabled(mMinutesIndex > 0);
|
||||
button2.setEnabled(mMinutesIndex < MINUTES.length - 1);
|
||||
button1.setImageAlpha(button1.isEnabled() ? 0xff : 0x7f);
|
||||
button2.setImageAlpha(button2.isEnabled() ? 0xff : 0x7f);
|
||||
} else {
|
||||
button1.setVisibility(View.GONE);
|
||||
button2.setVisibility(View.GONE);
|
||||
}
|
||||
if (position == 0 && mConditions.getChildCount() == 1) {
|
||||
rb.setChecked(true);
|
||||
}
|
||||
}
|
||||
|
||||
private void fireMoreSettings() {
|
||||
if (mCallback != null) {
|
||||
mCallback.onMoreSettings();
|
||||
}
|
||||
}
|
||||
|
||||
private void fireInteraction() {
|
||||
if (mCallback != null) {
|
||||
mCallback.onInteraction();
|
||||
}
|
||||
}
|
||||
|
||||
private final ZenModeController.Callback mZenCallback = new ZenModeController.Callback() {
|
||||
@Override
|
||||
public void onConditionsChanged(Condition[] conditions) {
|
||||
mHandler.obtainMessage(H.UPDATE_CONDITIONS, conditions).sendToTarget();
|
||||
}
|
||||
};
|
||||
|
||||
private final class H extends Handler {
|
||||
private static final int UPDATE_CONDITIONS = 1;
|
||||
|
||||
private H() {
|
||||
super(Looper.getMainLooper());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleMessage(Message msg) {
|
||||
if (msg.what == UPDATE_CONDITIONS) {
|
||||
handleUpdateConditions((Condition[])msg.obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public interface Callback {
|
||||
void onMoreSettings();
|
||||
void onInteraction();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user